2

I have a performance issue in a prototype I am working on. The requirement is to build a datagrid with multiple synchronized frozen panes, supporting grouping and sorting etc... For more details about the grid I am building, see this previous question.

Now, I have a question related to Grouping and in particular Expanders. I have a GroupStyle defined by the following Xaml, and taken from this blog post.

    <!--Default GroupStyle-->
    <GroupStyle x:Key="gs_Default">
        <GroupStyle.Panel>
            <ItemsPanelTemplate>
                <DataGridRowsPresenter/>
            </ItemsPanelTemplate>
        </GroupStyle.Panel>
        <GroupStyle.HeaderTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" Padding="3"/>
                </StackPanel>
            </DataTemplate>
        </GroupStyle.HeaderTemplate>
        <GroupStyle.ContainerStyle>
            <Style TargetType="{x:Type GroupItem}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type GroupItem}">
                            <Expander x:Name="exp"
                                      BorderBrush="#FFA4B97F" 
                                      BorderThickness="0,0,0,1" 
                                      IsExpanded="{Binding Path=Items[0].IsExpanded}">
                                <Expander.Header>
                                    <DockPanel TextBlock.FontWeight="Bold">
                                        <TextBlock Text="{Binding Path=Name}" Margin="5,0,5,0" />
                                        <TextBlock Text="{Binding Path=ItemCount}"/>
                                    </DockPanel>
                                </Expander.Header>
                                <ItemsPresenter/>                       
                            </Expander>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </GroupStyle.ContainerStyle>
    </GroupStyle>

The Expander is not virtualized and we are experiencing a performance issue when there are several hundred rows in a group.

Has anyone encoutered this before and have a fix? I am ideally looking for a Virtualizing Expander, and have seen workarounds such as this (which doesn't solve the problem).

Community
  • 1
  • 1
Dr. Andrew Burnett-Thompson
  • 20,980
  • 8
  • 88
  • 178
  • Performance for this kind of configuration can be painfully slow running a Debug build with the debugger attached yet perform reasonably running a Release build with no debugger attached. Have you tried a release build? – Doug Ferguson Feb 08 '12 at 17:35
  • Hi Doug, good idea, I will check. From my searches on the web it seems that WPF Datagrid cannot virtualize when grouping, as the VirtualizingStackPanel is containing few groups, which each have many rows in a non-virtualized ItemsPresenter – Dr. Andrew Burnett-Thompson Feb 08 '12 at 21:38
  • I'm sad, nobody has an answer to this question. Would it not be possible to override DataGridRowsPresenter or use another panel? Does it work? – J. Lennon Aug 20 '12 at 01:40
  • Hi John, I don't have the code in front of me, so can't post a full solution, but did manage to get this working. It involved pretty much a re-write of the templates of rows. So we had "Group" rows and "Item" rows. Then clicking on a group row would remove the child item rows from its collection view source. All done in code and was extremely fast with tens of thousands of rows. What you lost was nice swooshy animation on expand/collapse – Dr. Andrew Burnett-Thompson Aug 21 '12 at 20:08
  • This is a magnificent news, when you have the code, you will be able to share or even publish it on codeproject or another site. – J. Lennon Aug 22 '12 at 02:16
  • I'll add an answer below. Im afraid its not compelte as the above was completed under NDA, I cannot share any code – Dr. Andrew Burnett-Thompson Aug 22 '12 at 06:12
  • @Dr.AndrewBurnett-Thompson did u find any solution for this? – raghava arr Apr 27 '21 at 13:17
  • This is a 9-year old question, sorry I've long forgotten about it! – Dr. Andrew Burnett-Thompson Apr 30 '21 at 13:46

2 Answers2

4

If you're using .NET 4 then get the ItemsPresenters visibility to track/be dependent on the IsExpanded state.

In .NET 4.5 there's a new attached property VirtualizingPanel.IsVirtualizingWhenGrouping.

Another alternative is to push the grouping into the ViewModel rather than making the DataGrid/CollectionView be responsible for that. See here:

Community
  • 1
  • 1
Colin Smith
  • 12,375
  • 4
  • 39
  • 47
  • Thanks, but I, like many others, still looking for a solution in .NET 4 =( Performance is lousy with 1000, 2000 items divided into several groups. Especially when it opens an expander. – J. Lennon Aug 21 '12 at 19:52
  • Have a look at this example...it pushes the grouping into the ViewModel, rather than in the DataGrid/CollectionView. http://blog.smoura.com/wpf-toolkit-datagrid-part-iv-templatecolumns-and-row-grouping/ – Colin Smith Aug 21 '12 at 20:47
  • Thanks for sharing, sounds like a great alternative in specific cases, the only problem that generates a larger work... – J. Lennon Aug 22 '12 at 02:18
  • @J.Lennon the blog post colin links to above is very similar to the solution we used. I even read this at the time. It's the only way I'm afraid – Dr. Andrew Burnett-Thompson Aug 22 '12 at 13:58
3

In order to solve this, we did the following.

We used DataTemplates to present a different row view for different row viewmodels. We had a GroupRowViewModel and ItemRowViewModel. Also a parent ViewModel which had a sorted list of Group/Item viewmodels.

When the grid was instantiated, the parent ViewModel would sort all child viewmodels into the following:

  • Group
    • Item
    • Item
    • Item
  • Group
    • Item
    • Item
    • Item

When a GroupRow is clicked you want to execute some code where the parent (which contains a sorted list of group+item rows) will remove or include the items. E.g. say the second gropu was clicked, your list of rowviewmodels you bind to now becomes

  • Group
    • Item
    • Item
    • Item
  • Group (Collapsed)

That's it. So no magic at all, you manually remove or include the rows you want depending on what was clicked. It worked with virtualization and hundreds of thousands of rows at an acceptible speed.

Sorry I can't post any code (due to NDA) but I hope that helps you. Also - I would suggest looking at Telerik Grid as this is awesomely fast for large datasets

Dr. Andrew Burnett-Thompson
  • 20,980
  • 8
  • 88
  • 178