我正在使用CodePlex 的 WPF DataGrid,我需要让虚拟化与分组一起工作。
这个问题是关于主题的,并指向一个MSDN 示例,但它仅涵盖带有简单(即单个“列”)DataTemplates 的 ListControls。
分组和虚拟化似乎是网格的一个非常常见的用例。是否有标准/推荐/简单的方法来实现这一点?
我正在使用CodePlex 的 WPF DataGrid,我需要让虚拟化与分组一起工作。
这个问题是关于主题的,并指向一个MSDN 示例,但它仅涵盖带有简单(即单个“列”)DataTemplates 的 ListControls。
分组和虚拟化似乎是网格的一个非常常见的用例。是否有标准/推荐/简单的方法来实现这一点?
我意识到我在这里聚会迟到了......但我最近遇到了这个问题(使用.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得到解决。
框架 4.5 VirtualizingPanel.IsVirtualizingWhenGrouping中有一个新的附加属性,它允许在分组时打开虚拟化。
<DataGrid EnableColumnVirtualization="True" EnableRowVirtualization="True"
VirtualizingPanel.IsVirtualizingWhenGrouping="True">
没有内置功能允许您在 ListView 或 DataGrid 中启用分组时启用 UI 虚拟化,如果您考虑一下,它也很有意义。DataGrid 如何对不存在的项目进行分组。要应用分组,控件需要加载整个集合,这会破坏虚拟化的整个目的。您可能做的最好的事情是在您的视图模型(您再次绑定的对象)中提供某种虚拟化,因为您只提供当前需要的数据加上某种关于存在的数据量的通用数据然后伪造自己的看法。
通过分组,它可以是这样的:最初启用分组时,所有组都将被折叠。因此,您的视图模型只需为每个组提供一个项目。只是为了确保视图包含所有现有组。只要用户展开一个组,ViewModel 就会动态地重新填充该组的项目。这是一种非常简单和基本的虚拟化方式,不是最优的,但它可能是一个很好的起点。这只是为了说明这种方法。
如您所说,启用分组将禁用 UI 虚拟化。
我认为您不会找到解决此问题的简单方法。我建议您检查一个可用的 WPF DataGrid,例如XCeeed,它可能在其控件中内置了此功能。