I have a grid that is handling real-time data from the network and I allow the user to group and sum the data. Because the grid doesn't automatically recalculate the summary calculations i have to call RefreshSummaries on the RowsManagerBase class. But doing this doesn't work when grouping so I have to traverse all of the row managers by iterating the rows and grabbing the GroupByRows and calling their managers. This works but seems to use alot of CPU. I have a grid with about 1000 rows which the user groups into about 100 groups (100 rows per group). I have a timer and I am doing my RefreshSummaries every 2 seconds but it still uses enough CPU to where the grid lags significantly. Is there a better way to recalculate the summary information when using grouping?
Hi John,
The reason the XamGrid does not automatically refresh the summaries is for performance reasons. If the data was to be updated quite frequently, the data would need to be iterated and summaries recalculated. This is very expensive to do as you can see.
It sounds like your application is refreshing the summaries for every group all at once. A better approach might be to stagger the updates so that the application isn't hitting the cpu with a ton of work all at once. Spread out the updates over a longer period of time and you should see better performance. Maybe update two groups at a time and then wait a few milliseconds and then update the next two groups. To the user it will look like the summaries are updated almost instantly (users might still see some quickly changing numbers as the summaries are updated) but to the cpu there is more time to update summaries and still keep the UI responsive. The idea is to spread out the updates over the course of a few 100 milliseconds rather than doing it all at once.
I had already implemented the staggering as a workaround and it is OK. But i have found I can only really re-calculate the summaries for 1 group level (most times there are 3 levels) every 2 seconds. So each level ends up getting updated every 6 seconds. That is really not very often. With only 1000 rows and summing 1 column i would have expected to be able to do it much more often.
Not that I can see. One area where you might hit a performance bump is that GroupByRow row controls are swapped between different groups when using a GroupByItemTemplate and the summary is updated. This may be a result of the virtualization that the XamGrid does. When the row controls are swapped the DataContext is changed which causes the bindings to re-update which means your ItemsControl is going to destroy it's old items and then make new ones for the new DataContext. I'm not really sure how much of an impact this would really have though. It doesn't seem like it should take up a lot of time unless you have a lot of SummaryResults.
The performance issue seems to be because I am useing GroupByItemTemplate in order to show the summary values on the group by row. Using the WPF performance suite I can see it is repainting the whole grid on every update when using this template. Below is my template defintion. Is there something I am doing wrong?
<DataTemplate x:Key="groupByItemTemplate"> <StackPanel Orientation="Horizontal" Margin="0, -2, 0 ,-2"> <TextBlock Text="{Binding Value}" MinWidth="25" VerticalAlignment="Center" FontWeight="Bold" Margin="5,0,15,0" Padding="0" Foreground="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType=ContentControl}}"/> <ItemsControl ItemsSource="{Binding SummaryResults}" Margin="0" Padding="0" HorizontalContentAlignment="Center" Background="Transparent" BorderThickness="0" Foreground="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType=ContentControl}}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal" Margin="0"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <Border BorderBrush="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType=ContentControl}}" Padding="4,0,0,0" BorderThickness="1,0,0,0"> <TextBlock Grid.Row="1" MinWidth="50" TextAlignment="Center" Margin="0,0,5,0" Padding="0" FontWeight="Bold" Text="{Binding Value}"> </TextBlock> </Border> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </StackPanel> </DataTemplate>
2 seconds per group seems like a bit much. I built a quick sample with 1000 rows split into three groups and refreshing the summaries of 1 group happens pretty quickly. Quickly enough that I am able to refresh the summary for one group, then 50 milliseconds later update the next group. I have a DispatcherTimer that runs every 50 milliseconds. Each time the timer ticks, I refresh the summary for 1 group and then update the group index so that in the next tick it will update the next group.
I have attached the sample below so you can take a look at it.