在我的一个项目中,我有一个与组小计行一起被破解的 DataGrid。我们并不关心您提出的一些问题,例如隐藏和排序列,所以我不确定它是否可以扩展。我也意识到大型集合可能会出现性能问题(我的窗口正在运行 32 个单独的 DataGrids - 哎哟)。但这与我见过的其他解决方案的方向不同,所以我想我会把它扔在这里,看看它是否对你有帮助。
我的解决方案由 2 个主要组件组成:
1. 小计行不是主 DataGrid 中的行,而是单独的 DataGrid。实际上,我在每个组中有 2 个额外的网格:1 个在标题中,仅在组折叠时显示,一个在 ItemsPresenter 下方。小计 DataGrids 的 ItemsSource 来自一个 Converter,它获取组中的项目并返回一个聚合视图模型。小计网格的列与主网格完全相同(在 DataGrid_Loaded 中填写,尽管我确信它也可以在 xaml 中完成)。
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander Background="Gray" HorizontalAlignment="Left" IsExpanded="True"
ScrollViewer.CanContentScroll="True">
<Expander.Header>
<DataGrid Name="HeaderGrid" ItemsSource="{Binding Path=., Converter={StaticResource SumConverter}}"
Loaded="DataGrid_Loaded" HeadersVisibility="Row"
Margin="25 0 0 0" PreviewMouseDown="HeaderGrid_PreviewMouseDown">
<DataGrid.Style>
<Style TargetType="DataGrid">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Expander}, Path=IsExpanded}"
Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Style>
</DataGrid>
</Expander.Header>
<StackPanel>
<ItemsPresenter/>
<DataGrid Name="FooterGrid" ItemsSource="{Binding ElementName=HeaderGrid, Path=ItemsSource, Mode=OneWay}"
Loaded="DataGrid_Loaded" HeadersVisibility="Row"
Margin="50 0 0 0">
<DataGrid.Style>
<Style TargetType="DataGrid">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Expander}, Path=IsExpanded}"
Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid>
</StackPanel>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
2. 然后问题是如何让所有 DataGrids 表现得好像它们是一个网格一样。我已经通过在一个模拟 Grid 类的 SharedSizeGroup 行为的类中子类化DataGridTextColumn
(在这种情况下我们只有文本,但其他列类型也应该工作)来处理这个问题。DataGridSharedSizeTextColumn
它有一个带有组名的字符串依赖属性,并跟踪同一组中的所有列。当Width.DesiredValue
一列发生变化时,我会更新所有其他列中的 MinWidth 并强制使用DataGridOwner.UpdateLayout()
. 此类还涵盖列重新排序,并在 DisplayIndex 更改时进行组范围的更新。我认为这种方法也适用于任何其他列属性,只要它有一个设置器。
选择、复制等还有其他烦人的事情需要解决。但结果证明,使用 MouseEntered 和 MouseLeave 事件以及使用自定义 Copy 命令很容易处理。