带分组的WPF DataGrid虚拟化

时间:2009-09-25 12:33:29

标签: .net wpf datagrid virtualization grouping

我正在使用WPF DataGrid from CodePlex,我需要让Virtualization与分组一起使用。

question是主题并指向MSDN Example,但它仅涵盖带有简单(即单个“列”)DataTemplates的ListControls。

分组和虚拟化似乎是网格的一个非常常见的用例。是否有标准/推荐/简单的方法来实现这一目标?

4 个答案:

答案 0 :(得分:33)

我意识到我在这里迟到了...但我最近遇到了这个问题(使用.NET 4中内置的DataGrid)。不幸的是,一旦在DataGrid上使用Grouping,仍然没有行的虚拟化......但是我找到了一个非常光滑的性能增强技巧,希望其他人也会觉得有用。

假设您在GroupItem模板的扩展器中使用ItemsPresenter,并且默认情况下您的扩展器未展开,请尝试使用默认的BooleanToVisibilityConverter将ItemsPresenter的可见性绑定到Expander的IsEnabled属性:

<BooleanToVisibilityConverter x:Key="bool2vis" />


<DataGrid.GroupStyle>
    <GroupStyle>
        <GroupStyle.ContainerStyle>
            <Style TargetType="{x:Type GroupItem}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type GroupItem}">
                            <Expander x:Name="exp">
                                <ItemsPresenter Visibility="{Binding ElementName=exp, Path=IsExpanded, Converter={StaticResource bool2vis}}" />
                            </Expander>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </GroupStyle.ContainerStyle>
    </GroupStyle>
</DataGrid.GroupStyle>

如果您遇到DataGrid需要很长时间加载的问题(因为它实际上是在数据网格中抽出每条记录,即使它在折叠的扩展器中)...然后使用上面的代码会导致数据网格在扩展组之前不绘制您的记录,然后,它只会绘制该特定组的记录。

缺点是,这只有在默认情况下折叠你的扩展器时才有用,但仍然没有虚拟化行(如果扩展组中有100个项目,但屏幕上只有20个,则所有100个将是在你扩展小组时绘制的。)

好处是你实际上已经实现了对DataGrid记录的延迟加载,因此在实际需要查看项目(您选择展开组)之前,您不会执行绘图工作。对于我的产品,我的组头包含内置按钮以对其组内的所有项执行操作,因此除非用户需要对组内的单个项执行操作,否则用户通常不会扩展组。

*如果您使用此技巧,需要注意的一点是您应该为列标题设置一些显式宽度或最小宽度(因为在DataGrid首次加载时不会绘制项目,因此列标题无法自动调整为适合最大的项目。)

希望真正的虚拟化能够在未来的服务包中实现,但如果没有,我希望这会对其他人有所帮助!

更新

看起来这个问题将在.NET 4.5中使用新的附加属性VirtualizingPanel.IsVirtualizingWhenGrouping修复。

答案 1 :(得分:14)

框架4.5 VirtualizingPanel.IsVirtualizingWhenGrouping中有一个新的附加属性,允许在分组时启用虚拟化。

<DataGrid EnableColumnVirtualization="True" EnableRowVirtualization="True"
   VirtualizingPanel.IsVirtualizingWhenGrouping="True">

答案 2 :(得分:2)

没有内置功能允许您在ListView或DataGrid中启用分组时启用UI虚拟化。如果您考虑它一秒钟它也是有意义的。 DataGrid如何对不存在的项进行分组。要应用分组,控件将需要加载整个集合,这将破坏虚拟化的整个目的。 您可能做的最好的事情是在viewmodel(再次绑定的对象)中提供某种虚拟化,因为您只提供当前需要的数据以及有关存在的数据量的某种通用数据然后伪造你自己的观点。

通过分组,它可以是这样的:当启用分组时,最初所有组都将折叠。因此,您的viewmodel只需为每个组提供一个项目。只是为了确保视图包含所有现有组。一旦用户扩展了一个组,ViewModel就会动态地重新填充该组的项目。这是一种非常简单和基本的虚拟化方式,并不是最优的,但它可能是一个很好的起点。这只是为了证明这种方法。

答案 3 :(得分:0)

正如您所说,启用分组将禁用UI虚拟化。

我认为你找不到解决这个问题的简单方法。我建议您检查一个可用的WPF DataGrid,例如可能在其控件中构建此功能的XCeeed