WPF DataGrid Virtualization with Grouping

18,066

Solution 1

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.

Solution 2

There is a new attached property in framework 4.5 VirtualizingPanel.IsVirtualizingWhenGrouping, which allows to switch on virtualization when grouping.

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

Solution 3

There is no built-in feature that allows you to enable UI Virtualization when grouping is enabled in a ListView or DataGrid, If you think about it for a second it also makes sense. How is the DataGrid to group items that do not exist. To apply grouping the control would need to load the whole collection wich would defeat the whole purpose of virtualization. The best you can probably do is to provide some sort of virtualization in your viewmodel (the object you bind agains) in that you provide only the data that is currently needed plus some sort of generic data about the amount of data that exists and then fake the view yourself.

With grouping it could go something like this: When grouping is enabled initially all groups would be collapsed. So your viewmodel would only have to provide one item for each group that there is. Just to make sure that the view contains all exisiting groups. As soon as the user expands one group the ViewModel would dynamically refill the items for that group. This is a very simple and basic way of virtulization and not optimal but it might be a good starting point to. It is just to illistrate the approach.

Share:
18,066

Related videos on Youtube

Jan Bannister
Author by

Jan Bannister

I'm just a lowly developer :)

Updated on April 15, 2022

Comments

  • Jan Bannister
    Jan Bannister about 2 years

    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?

  • Jan Bannister
    Jan Bannister over 14 years
    I disagree that grouping intrinsically breaks UI Visualization. If you think about it, what you are taking about is Data Visualization, which I don't care about. There is a valid point to be made around groups being forced to be the same height as the rows they contain. Which would simplify height layout calculations.
  • Jan Bannister
    Jan Bannister over 14 years
    I know that the other grids have these features to some extent but I'd prefer to use the WPF CodePlex grid as it will be standard and all the other grids are crap in different ways.
  • Steve Greatrex
    Steve Greatrex about 13 years
    If only I could upvote twice... fantastic performance improvement at a stroke
  • John Gardner
    John Gardner about 13 years
    this worked awesome! i had a place where this was getting an out of memory every time, and this worked like a charm!
  • Dr. Andrew Burnett-Thompson
    Dr. Andrew Burnett-Thompson about 12 years
    @Scott - this is good, but I'm stuck with a situation where I have all groups expanded and multiple rows per expander. Do you know of a way to virtualize the ItemsPresenter insite Expander?
  • Scott
    Scott about 12 years
    @Dr.AndrewBurnett-Thompson - Unfortunately, I don't have a good answer for you until .NET 4.5 is released which will have an IsVirtualizingWhenGrouping property on the VirtualizingPanel class: msdn.microsoft.com/en-us/library/…
  • Dr. Andrew Burnett-Thompson
    Dr. Andrew Burnett-Thompson about 12 years
    @Scott lol "IsGoingToWorkProperlyUnderAnEdgeCondition" - thanks for the info! I'm looking into it now. I did find this example where they use a row to pretend to be a group, which may allow virtualization whilst grouped. blog.smoura.com/…
  • MickyD
    MickyD about 6 years
    OP is talking about UI virtualisation not data virtualisation (which I believe no WPF control supports).
  • Unknown Coder
    Unknown Coder almost 5 years
    The VirtualizingPanel.IsVirtualizingWhenGrouping did the trick! Thanks for the updated information about it!