wpf 数据网格,合并/组合行、单元格和列
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24490861/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Datagrid, Merge/Combine rows, cells and columns
提问by Steven Borges
I'm trying to acomplish exactly what thisquestion is requesting, but unfortunately the code sample that was provided as the answer is gone, and I'm also not using WPF Toolkit, here the question that he did:
我正在尝试准确完成这个问题所要求的内容,但不幸的是,作为答案提供的代码示例已经消失了,而且我也没有使用 WPF Toolkit,这里是他提出的问题:
I am trying to Merge cells in WPF toolkit datagrid .I am trying to do something as shown in the image below.We can do this in Winforms datagrid.But how to do this using WPF toolkit datagrid ?.Or is there any alternative controls..?
Can we do this using listview or listbox..? Or is there any free controls available which have this functionality ?
我正在尝试合并 WPF 工具包数据网格中的单元格。我正在尝试执行下图所示的操作。我们可以在 Winforms 数据网格中执行此操作。但是如何使用 WPF 工具包数据网格执行此操作?。或者是否有任何替代控件。 .?
我们可以使用列表视图或列表框来做到这一点吗?或者是否有任何具有此功能的免费控件可用?


I found several answers that manage to do this with the DataGridView control, but I do not want to use Form objects in a WPF project, is there a way to acomplish this?
我找到了几个设法使用 DataGridView 控件执行此操作的答案,但我不想在 WPF 项目中使用 Form 对象,有没有办法完成此操作?
回答by Heena Patil
Recource
资源
<Window.Resources>
<Color x:Key="customBlue" A="255" R="54" G="95" B="177" />
<SolidColorBrush x:Key="customBlueBrush" Color="{StaticResource customBlue}"></SolidColorBrush>
<SolidColorBrush x:Key="customBlueBrushOpacity" Color="LightGray" Opacity="0.11"></SolidColorBrush>
<Style x:Key="calcyListbox" TargetType="ListBox">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="35"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Height="30" VerticalAlignment="Top" Background="{StaticResource customBlueBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Manufacturer" FontSize="14" FontFamily="Segoe Ui Dark" Foreground="White" SnapsToDevicePixels="True" HorizontalAlignment="Center" VerticalAlignment="Center" ></TextBlock>
<TextBlock Text="Name" FontSize="14" FontFamily="Segoe Ui Dark" Foreground="White" SnapsToDevicePixels="True" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="1"></TextBlock>
<TextBlock Text="CPU" FontSize="14" FontFamily="Segoe Ui Dark" Foreground="White" SnapsToDevicePixels="True" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="2"></TextBlock>
<TextBlock Text="RAM" FontSize="14" FontFamily="Segoe Ui Dark" Foreground="White" SnapsToDevicePixels="True" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="3"></TextBlock>
<TextBlock Text="Price" FontSize="14" FontFamily="Segoe Ui Dark" Foreground="White" SnapsToDevicePixels="True" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="4"></TextBlock>
</Grid>
<Border Grid.Row="1" SnapsToDevicePixels="True" Background="Transparent" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0">
<ScrollViewer x:Name="ScrollViewer" Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}" BorderBrush="Transparent" BorderThickness="0">
<ItemsPresenter />
</ScrollViewer>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="noStyleToListboxItem" TargetType="ListBoxItem">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border>
<ContentPresenter></ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
xaml
xml
<ListBox MaxHeight="300" ItemsSource="{Binding ManufacturerList}" Background="{StaticResource customBlueBrushOpacity}" x:Name="ManufacturerListBox" ScrollViewer.VerticalScrollBarVisibility="Auto" Style="{StaticResource calcyListbox}" ItemContainerStyle="{StaticResource noStyleToListboxItem}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="4*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Company}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border BorderThickness="0,0,0,1" BorderBrush="Black" ></Border>
<ListBox Grid.Column="1" BorderThickness="1,0,1,1" Background="{StaticResource customBlueBrushOpacity}" HorizontalContentAlignment="Stretch" ItemsSource="{Binding Models}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border BorderThickness="0,0,1,0" BorderBrush="Black" Margin="-2" Grid.Column="0"></Border>
<Border BorderThickness="0,0,1,0" BorderBrush="Black" Margin="-2" Grid.Column="1"></Border>
<Border BorderThickness="0,0,1,0" BorderBrush="Black" Margin="-2" Grid.Column="2"></Border>
<TextBlock Text="{Binding Name}" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="0"/>
<TextBlock Text="{Binding CPU}" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="1"/>
<TextBlock Text="{Binding Ram}" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="2"/>
<TextBlock Text="{Binding price}" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="3"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
c#
C#
InitializeComponent();
List<Manufacturer> ManufacturerList = new List<Manufacturer>();
ManufacturerList.Add(new Manufacturer()
{
Company = "DEll",
Models = new List<Model>(){new Model(){CPU = "T7250", Name = "Inspiron1525", price =234434 , Ram= "2048 MB" },
new Model(){CPU = "T5750", Name = "Studio 1535", price =234443 , Ram= "2048 MB" },
new Model(){CPU = "T5780", Name = "Vastro 1510", price =234434 , Ram= "2048 MB" },}
});
ManufacturerList.Add(new Manufacturer()
{
Company = "Lenovo",
Models = new List<Model>(){new Model(){CPU = "T1230", Name = "l123", price =23546454 , Ram= "1024 MB" },
new Model(){CPU = "T1230", Name = "l1423", price =2346456 , Ram= "1024 MB" },
new Model(){CPU = "T1230", Name = "ldf123", price =2344646 , Ram= "1024 MB" },}
});
ManufacturerListBox.ItemsSource = ManufacturerList;
public class Manufacturer
{
public string Company { get; set; }
public List<Model> Models { get; set; }
}
public class Model
{
public string Name { get; set; }
public string Ram { get; set; }
public double price { get; set; }
public string CPU { get; set; }
}


回答by Tekito
For a merged cell, bind its Marginand set it to a negative value equal to the sum width/height of the associated merged cells - then the cell will spill across and on top the neighboring cells.
对于合并的单元格,将其绑定并将其Margin设置为等于关联合并单元格的宽度/高度总和的负值 - 然后该单元格将溢出并位于相邻单元格的顶部。
<Style TargetType="DataGridCell">
<Setter Property="BorderThickness" Value="{{Binding BorderThickness[5], Mode=OneWay}}"/>
<Setter Property="Margin" Value="{{Binding CellMargins[5], Mode=OneWay}}"/>
<Setter Property="Block.TextAlignment" Value="Center"/>
</Style>
The bindings are indexed because CellMarginsis an ObservableCollectionof Thickness. The viewmodel is row-level, so each column binds to a different index.
该绑定索引,因为CellMargins是ObservableCollection的Thickness。视图模型是行级的,因此每一列都绑定到不同的索引。
Before this gets downvoted, let me say this can lead to some undesirable visual quirks. Getting this to work perfectly requires a bit of code-behind, such as:
在这被否决之前,让我说这可能会导致一些不受欢迎的视觉怪癖。让它完美地工作需要一些代码隐藏,例如:
The cell margins' negative values need to be updated whenever a column width changes, so I handled the datagrid's LayoutUpdatedevent, where I iterated through the columns, measured their current ActualWidthsand updated the margins accordingly. I likewise update the BorderThicknessto show/hide cell borders as needed. Disabling the selection highlight for cells that are "hidden" is another trick.
每当列宽发生变化时,单元格边距的负值都需要更新,所以我处理了数据网格的LayoutUpdated事件,在那里我遍历列,测量它们的当前值ActualWidths并相应地更新边距。我同样BorderThickness根据需要更新以显示/隐藏单元格边框。禁用“隐藏”单元格的选择突出显示是另一个技巧。
Note this means keeping track of what cells (i.e., which row viewmodels and column indices) you want merged separately in code-behind.
请注意,这意味着跟踪您希望在代码隐藏中单独合并的单元格(即,哪些行视图模型和列索引)。
This method is complicated and probably not the easiest for every situation, but I found it useful for my purposes. I needed a Datagridwhere the user could merge/unmerge cells and create/delete columns, similar to Excel. Furthermore, I wanted to stick with DataGridTextColumns(instead of custom TemplateColums) because of their built-in functionality (recognized keyboard edit commands, copy/paste, etc.)
这种方法很复杂,对于每种情况可能都不是最简单的,但我发现它对我的目的很有用。我需要一个Datagrid用户可以合并/取消合并单元格和创建/删除列的地方,类似于 Excel。此外,我想坚持使用DataGridTextColumns(而不是 custom TemplateColums),因为它们的内置功能(可识别的键盘编辑命令、复制/粘贴等)

