首页 文章

如何处理组小计和例如WPF DataGrid中的目标行?

提问于
浏览
12

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

对于每个类别,应该有:

  • 一行,显示在每个关键值图列中列的所有行的总和 .

  • 不属于绑定到的数据源网格的目标行 . 目标行告诉每一列当年的目标是什么(例如,要花多少钱) .

这些行应始终位于每个组的顶部(排序过滤) .

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

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

DataGrid正在使用CollectionViewSource,所以's not populated with C# code. Basically i' m扩展了这个例子:http://msdn.microsoft.com/en-us/library/ff407126.aspx

谢谢和最诚挚的问候 - matti

2 回答

  • 0

    在我的一个项目中,我有一个黑客组合的DataGrid,其中包含组小计行 . 我们并不关心你提出的一些问题,例如隐藏和排序列,所以我不确定它是否可以扩展 . 我也意识到可能存在性能问题可能是大型集合的问题(我的窗口运行32个独立的DataGrids - ouch) . 但它与我见过的其他解决方案的方向不同,所以我想我会把它扔到这里,看看它是否会帮助你 .

    我的解决方案包括两个主要组件:
    1.小计行不是't rows in the main DataGrid, but are separate DataGrids. I have 2 extra grids in each group actually: 1 in the header that is only displayed when the group is collapsed, and one beneath the ItemsPresenter. The ItemsSource for the subtotal DataGrids comes from a Converter that takes the items in the group and returns an aggregate view model. The columns of the subtotal grids are exactly the same as the main grid (filled out in DataGrid_Loaded, though I'确定它也可以在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表现得就像它们是单个网格一样 . 我已经通过子类化 DataGridTextColumn (在这种情况下我们只有文本,但其他列类型也应该工作)处理了一个名为 DataGridSharedSizeTextColumn 的类,它模仿Grid类的SharedSizeGroup行为 . 它具有带有组名的字符串依赖项属性,并跟踪同一组中的所有列 . 当 Width.DesiredValue 在一列中更改时,我更新所有其他列中的MinWidth并强制使用 DataGridOwner.UpdateLayout() 进行更新 . 此类还包括列重新排序,并在DisplayIndex更改时执行组范围更新 . 我认为这个方法也适用于任何其他列属性,只要它有一个setter .

    还有其他讨厌的事情可以解决选择,复制等问题 . 但事实证明,使用MouseEntered和MouseLeave事件以及使用自定义复制命令可以轻松处理 .

  • 2

    一个选项可能是在数据源中添加具有Name的特殊值和其他没有意义的字段的行,并使用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假设没有很好的功能:(

相关问题