Kishor
Kishor

Reputation: 4096

Improve WPF DataGrid performance

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?

Upvotes: 42

Views: 51455

Answers (7)

Oskar Sjöberg
Oskar Sjöberg

Reputation: 2878

I was having a DataGrid in a ScrollViewer allowing for the DataGrid to grow to infinite height. Setting the Height or the MaxHeight of the DataGrid to something reasonable was solving the majority of my performance problems.

Upvotes: 1

Zeyad
Zeyad

Reputation: 626

One soltuion that I found to be the best compromise for both loading and scrolling performance is to set the IsAsync=True for all the columns' Binding not the DataGrid ItemsSource Binding. Example:

<DataGridTextColumn Binding="{Binding Path=MaterialName, Mode=OneTime, IsAsync=True}" Header="Name" />

By the way, this solution works better when virtualization on the DataGrid is switched off. However, even if virtualization is switched on, still worth a try. Also this solution is very effective when applied to a DataGridTemplateColumn that displays an image or so.

Upvotes: 0

marsh-wiggle
marsh-wiggle

Reputation: 2803

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.

Upvotes: 1

chris84948
chris84948

Reputation: 4360

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.

Upvotes: 4

Rajat Ghalni
Rajat Ghalni

Reputation: 131

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

Upvotes: 13

Alan
Alan

Reputation: 7951

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!

Upvotes: 96

Constanta
Constanta

Reputation: 399

Maybe try this instead of loading all 50 rows at once

http://www.codeproject.com/Articles/34405/WPF-Data-Virtualization

Upvotes: 0

Related Questions