我意识到我在这里聚会迟到了……但我最近遇到了这个问题(使用 .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 得到修复。