4

I'm using a .NET 4.0 WPF DataGrid, bound to an ObservableCollection<T>. The collection is having rows added and deleted a few times a second. The DataGrid is contained in a TabControl / TabItem / Grid.

It works more-or-less OK as long as I leave it visible. If I go to a different tab in the app, then come back a few minutes later, the UI thread locks up for 30 seconds (with about 1200 total rows, about 40 of which are on the screen). All row data is already in memory, so no I/O. All bound properties are either simple strings, numbers or dates, or the logic to create them is very simple; nothing complex or time consuming to calculate.

When there are more than a few hundred rows, selecting a new column to sort by is very slow. Adding a new row also seems slow. If I switch to another tab and then switch right back, the grid reappears quickly.

Resizing the window performs fine.

Scrolling performance is slow at first, but gets after the grid is fully loaded; it's never great. Without ScrollView.CanContentScroll="False", scrolling is so slow as to be unusable. Using IsDeferredScrollingEnabled="True" instead results in a 10+ second delay in rendering after the user lets go of the scrollbar -- still an unacceptable user experience.

There are 17 DataGridTextColumns. Several of the columns use custom StringFormats, but nothing complex. No TypeConverters.

The Visual Studio performance tools/profiler have been useless. This seems like a relatively simple/straightforward setup. Any suggestions on how to improve performance would be appreciated.

I'd also like to know WHY it's SO slow.

<DataGrid x:Name="MyGrid" AutoGenerateColumns="False" Margin="3,35,3,20" VerticalContentAlignment="Center" Width="Auto" 
                          FontSize="12" FontFamily="Consolas" ScrollViewer.CanContentScroll="False"
                          CanUserResizeRows="False" AlternationCount="2" AlternatingRowBackground="#FFE3F0FF"
                          VirtualizingStackPanel.VirtualizationMode="Recycling" IsReadOnly="True">
    <DataGrid.Columns>
        <DataGridTextColumn Header="XX" Binding="{Binding Path=XX}" />
        <DataGridTextColumn Header="YY" Binding="{Binding Path=YY, StringFormat={}{0:0.0}}">
            <DataGridTextColumn.ElementStyle>
                <Style>
                    <Setter Property="TextBlock.TextAlignment" Value="Right" />
                </Style>
            </DataGridTextColumn.ElementStyle>
        </DataGridTextColumn>
        . . .
    </DataGrid.Columns>
</DataGrid>
RickNZ
  • 18,448
  • 3
  • 51
  • 66

2 Answers2

4

Remove ScrollViewer.CanContentScroll = "False". It will disable the default UI Virtualization support of WPF DataGrid.

Refer to the answer here Physical scrolling disable UI Virtualization.

From the answer -

"ScrollViewer currently allows two scrolling modes: smooth pixel-by-pixel scrolling (CanContentScroll = false) or discrete item-by-item scrolling (CanContentScroll = true). Currently WPF supports UI virtualization only when scrolling by item. Pixel-based scrolling is also called “physical scrolling” and item-based scrolling is also called “logical scrolling”."

UPDATE

You can set the IsDeferredScrollingEnabled to true in case you want the smooth operation while you are dragging the Scrollbar. It will make the items in view to render only once you released the scrollbar thumb instead of creating all the items during dragging operation.

<DataGrid ScrollViewer.IsDeferredScrollingEnabled="True"/>

Also, this link from MSDN might be of your help.

Community
  • 1
  • 1
Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
  • With that change, it still takes about 5 seconds for the page to refresh after clicking on the tab. The DataGrid does start showing new data right away, though, which is good. Unfortunately, as I said in my post, it also makes scrolling so slow that it's unusable. – RickNZ Nov 24 '12 at 20:53
  • Try setting the `ScrollViewer.IsDeferredScrollingEnabled="True"` property on dataGrid. I have updated the answer. Have a look. – Rohit Vats Nov 25 '12 at 07:41
  • I've tried deferred scrolling before. Yes, it does allow the scrollbar to move. However, after you let go of the scrollbar, it takes the window 10 seconds or more to update, which adds a new source of user confusion/frustration. I'd like to understand WHY updating a measly 40 rows on screen, even when there are 1200-ish rows off-screen, takes SO incredibly long. – RickNZ Nov 25 '12 at 08:12
  • Hi, did you ever find a proper solution for this? I'm having the same problem. – Søren Engel Apr 03 '13 at 12:43
  • 1
    Lifesaver! Thank you! – jkl Aug 22 '16 at 14:48
0

I recommend that you investigate the TabControl issue of non-persisting tab item state when switching between tab items.

TabControl has a specific behavior - when tab item gets unselected, its content is destroyed, and it must be recreated when tab item gets selected again, meaning that entire DataGrid and all of its visible DataGridCells must be recreated.

Just Google for 'Persist visual tree in WPF TabControl' or 'Persist state in WPF TabControl'.

Stipo
  • 4,566
  • 1
  • 21
  • 37
  • Thanks for the suggestion. It looks like the content destruction problem only applies when you set ItemSource on the TabControl. If that's right, then it's not the issue in my case, since I don't do that. – RickNZ Dec 03 '12 at 01:24