Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF DataGrid Virtualization with Grouping

Tags:

I'm using the WPF DataGrid from CodePlex and I need to get Virtualization to work with grouping.

This question is on topic and points to an MSDN Example but it only covers ListControls with with simple (i.e. single 'column') DataTemplates.

Grouping and Virtualization seems like a pretty common use case for a Grid. Is there a standard/recommended/simple way of getting this going?

like image 873
Jan Bannister Avatar asked Sep 25 '09 12:09

Jan Bannister


1 Answers

I realize I'm late to the party here... but I ran into this problem recently (using the DataGrid built into .NET 4). Unfortunately, there still is no virtualization of the rows once Grouping is used on the DataGrid... but a I found a very slick performance enhancement trick that hopefully somebody else will find useful as well.

Assuming you're using an ItemsPresenter within an expander of your GroupItem's template and by default your expander is not expanded, then try simply binding the visibility of your ItemsPresenter to the Expander's IsEnabled property with the default BooleanToVisibilityConverter:

<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> 

If you're running into the problem where your DataGrid takes really long to load (because it's essentially drawing out every record in your datagrid even though it's in a collapsed expander)... then using the above code will cause the datagrid to not draw your records until you expand a group, and then, it will only draw out the records for that particular group.

The down side is that this only helps if your expanders are collapsed by default, and still the rows do not get virtualized (if you have 100 items in an expanded group, but only 20 fit on the screen, all 100 will be drawn at the time you expanded the group).

The upside is that you've essentially implemented lazy loading of your DataGrid records, so you're not performing the drawing work until you actually need to view the items (you choose to expand the group). For my product, my group header had buttons built in to perform operations on all items within its group, so more often the user never expanded a group unless they needed to perform an operation on an individual item within a group.

*One thing to note if you use this trick is that you should probably set some explicit widths or minimum widths to your column headers (because the items are not being drawn when the DataGrid first loads, so the column headers cannot autosize to fit the largest item).

Hopefully true virtualization gets implemented in a future service pack, but if not, I hope this will help somebody else!

Update

It appears this issue will be fixed in .NET 4.5 with a new attached property VirtualizingPanel.IsVirtualizingWhenGrouping.

like image 187
Scott Avatar answered Sep 28 '22 03:09

Scott