Improve WPF DataGrid performance

43,033

Solution 1

There are a few options you can turn on to help you on your DataGrid object

EnableColumnVirtualization = true
EnableRowVirtualization = true

These two are the main ones I think might help. Next try making your binding async

ItemsSource="{Binding MyStuff, IsAsync=True}"

And lastly, I've heard that setting a maximum height and width can help even if it above the max screen size, but I didn't notice a difference myself (claim had to do with auto size measuring)

MaxWidth="2560"
MaxHeight="1600"

Also never put a DataGrid in a ScrollViewer, because you will essentially lose virtualization. Let me know if this helps!

Solution 2

Check if you have property ScrollViewer.CanContentScroll set False. Setting this property to false disables the virtualization in a way will degrade the performance of your Data-grid. For more clarification refer this CanContentScroll

Solution 3

Set the DataGrid.RowHeight value and that will make a huge difference.

I know this is a really old question, but I just came across it, and this was the biggest difference on my end. My default height was 25.

Solution 4

Step 1: From 2 minutes to 10 seconds

This answer (Set ScrollViewer.CanContentScroll to True) put me on the right track. But I need it to be set to false. To set it to true when I'm doing my refresh I wrote this two methods.

internal static void DataGridRefreshItems(DataGrid dataGridToRefresh)
{
    /// Get the scrollViewer from the datagrid
    ScrollViewer scrollViewer = WpfToolsGeneral.FindVisualChildren<ScrollViewer>(dataGridToRefresh).ElementAt(0);
    bool savedContentScrollState = scrollViewer.CanContentScroll;
    scrollViewer.CanContentScroll = true;

    dataGridToRefresh.Items.Refresh();

    /// Was set to false, restore it
    if (!savedContentScrollState)
    {
        /// This method finishes even when the update of the DataGrid is not 
        /// finished. Therefore we use this call to perform the restore of
        /// the setting after the UI work has finished.
        Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => SetScrollViewerCanContentScrollFalse(scrollViewer)), DispatcherPriority.ContextIdle, null);
    }
}

private static void SetScrollViewerCanContentScrollFalse(ScrollViewer scrollViewer)
{
    scrollViewer.CanContentScroll = false;
}

This is the method I use to get the VisualChildren:

public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
    if (depObj != null)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
            if (child != null && child is T)
            {
                yield return (T)child;
            }

            foreach (T childOfChild in FindVisualChildren<T>(child))
            {
                yield return childOfChild;
            }
        }
    }
}

After this my refresh of 50.000 new items lasts only 10 seconds unlike 2 Minutes and consumes only 2 MB of RAM instad of 4 GB before.

Step 2: From 10 seconds to 0.5 seconds

For testing I disabled all of my IValueConverter and implemented properties which I bind directly. Without the converters the DataGrid refreshes immediately. So I left it.

Share:
43,033
Kishor
Author by

Kishor

Software Developer C++ C# WPF .NET

Updated on January 16, 2022

Comments

  • Kishor
    Kishor over 2 years

    In my .NET 3.5 WPF Application, I have a WPF DataGrid which will be populated with 500 columns and 50 rows. The performance of App is very very poor in scrolling, or when I do DataGrid.Items.Refresh() or in selecting rows.

    Actually App will take around 20 sec to Update Layout. Layout_Updated() event will trigger after 20 sec.

    If I reduce the columns to 50 or less, App will be very responsive. As per my findings performance is directly related to column count.

    How do I improve the DataGrid performance?

  • Kishor
    Kishor over 11 years
    Thanks for suggestions. But my requirement to have 500 columns at once.
  • Constanta
    Constanta over 11 years
    well you said scrolling so I thought you don't display all rows at once (how do you do that anyway with 500 cols) The idea with data virtualization is that you load a certain number to populate your grid and then remove and replace rows as you scroll
  • Scott
    Scott over 11 years
    I don't think EnableColumnVirtualization and EnableRowVirtualization are available until .NET 4.0. So the OP would need to upgrade from 3.5 before looking into the first suggestions.
  • Alan
    Alan over 11 years
    @Scott Well that could be a reasonable solution. To the OP, why are you using .NET 3.5? .NET 4.0 is available on XP SP3 and many 3rd party libraries already require .NET 4.0 if you want to use them.
  • Kelly
    Kelly about 11 years
    I would also make your columns a fixed width.
  • testpattern
    testpattern over 10 years
    @Alan I'm curious as to how you go about having a large data grid that avoids being inside a ScrollViewer?
  • Alan
    Alan over 10 years
    @testpattern The datagrid scrolls on its own, you just don't want to put it in your own ScrollViewer external to the DataGrid otherwise you'll lose virtualization of controls.
  • BENN1TH
    BENN1TH about 9 years
    I set my MaxHeight to 800 as a i had two scroll bars showing, maybe cause i had the grid wrapped in dockpanel but that fixed the (scrollbar) issue now i can load 1000+ items from XML into datagrid easily,fast and async without a slow render of the grid! thx
  • Vikas
    Vikas almost 9 years
    Amazing. I wonder why other threads never talked about this Enable Row and Column Virtualization. Thanks a ton.
  • Admin
    Admin almost 7 years
    I am suprised people adding ScrollViewer to DataGrid. Could that be previous version of wpf datagrid does not support scrolling?
  • Siva Gopal
    Siva Gopal over 5 years
    Definitely worth giving a try! And in fact they improved the performance a lot for me. Thanks @Alan
  • Zeyad
    Zeyad over 4 years
    Setting the MaxHeight made a significant improvement. Thank you very much. Also setting MaxWidth made a slight improvement as well. I was going crazy until I found this solution. Thank you.