如何处理组小计,例如 WPF 数据网格中的目标行

本文关键字:数据网 数据 WPF 网格 目标 例如 何处理 处理 | 更新日期: 2023-09-27 18:34:31

我正在实现一个包含许多关键指标的项目的 WPF DataGrid。项目按项目类别分组。

对于每个类别,应有:

  1. 在每个关键指标列中显示该列的所有行的总和的行。
  2. 不属于">
  3. 绑定到"中的数据源网格的目标行。目标行告诉每一列一年的目标是什么(例如,要花多少钱(。

这些行应始终位于每个组的顶部(排序筛选(。

我的第一个解决方案是将此数据放在组标题中。这不是一个好的解决方案,因为组标题不支持列。即它应该通过获取列宽来构造。

这可以完成,但是当用户想要重新排序和隐藏列时,它会变得复杂。

DataGrid 使用的是 CollectionViewSource,因此它未填充 C# 代码。基本上我正在扩展此示例:http://msdn.microsoft.com/en-us/library/ff407126.aspx

感谢和最好的问候 - 马蒂

如何处理组小计,例如 WPF 数据网格中的目标行

我有一个被黑客入侵的 DataGrid,在我的一个项目中有组小计行。我们不关心您提出的一些问题,例如隐藏和排序列,所以我不确定是否可以为此扩展它。我还意识到可能存在性能问题,这可能是大型集的问题(我的窗口正在运行 32 个单独的 DataGrid - 哎哟(。但它与我见过的其他解决方案的方向不同,所以我想我会把它扔在这里,看看它是否对你有帮助。

我的解决方案由 2 个主要组件组成:
1. 小计行不是主数据网格中的行,而是单独的数据网格。实际上,每个组中都有 2 个额外的网格:1 个在标题中,仅在组折叠时显示,一个在 ItemsPresenter 下方。小计 DataGrid 的 ItemsSource 来自一个转换器,该转换器获取组中的项并返回聚合视图模型。小计网格的列与主网格完全相同(用 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.那么问题是如何让所有数据网格的行为就好像它们是单个网格一样。我通过在一个名为 DataGridSharedSizeTextColumn 的类中子类化DataGridTextColumn(在这种情况下我们只有文本,但其他列类型也应该有效(来处理这个问题,该类模仿 Grid 类的 SharedSizeGroup 行为。它具有带有组名的字符串依赖项属性,并跟踪同一组中的所有列。当一列中的Width.DesiredValue更改时,我会更新所有其他列中的 MinWidth 并使用 DataGridOwner.UpdateLayout() 强制更新。此类还涵盖列重新排序,并在 DisplayIndex 更改时执行组范围的更新。我认为这种方法也适用于任何其他列属性,只要它有一个二传手。

还有其他

烦人的事情需要通过选择、复制等来解决。但事实证明,使用MouseEnter和MouseLeave事件以及使用自定义复制命令很容易处理。

一种选择是添加数据源中具有特殊值的行,用于名称和其他没有意义的字段,并使用 DataTrigger 以特殊颜色和其他颜色显示它们。

无论如何,筛选都是在 C# 中完成的,因此不会影响这些行。

排序是这里唯一的问题。仅仅告诉某些行在组中始终具有顺序 0 和顺序 1 会很酷。但是因为我不知道该怎么做,我必须用 C# 对所有列进行自定义排序,而不仅仅是声明排序:

<CollectionViewSource.SortDescriptions>
   <!-- Requires 'xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"' declaration. -->
    <scm:SortDescription PropertyName="ProjectName"/>
    <scm:SortDescription PropertyName="Complete" />
    <scm:SortDescription PropertyName="DueDate" />
</CollectionViewSource.SortDescriptions>

编辑:最重要的是,与我的第一个解决方案(组标题中的总和信息(相比,它有一个主要缺点,因为在过滤更改时,我应该更新仅针对可见行计算的总和。

所以这个答案是一个完整的黑客,缺乏所有的优雅,也没有使用WPF应该具有的漂亮功能:(