Poor performance when sorting by WPF DataGrid without virtualization

We have a simple WPF demo application with 1000 rows and 32 columns (see code below).

We didn’t do anything special, except to disable the virtualization that our users require, because scrolling is too sluggish (they do this all day on large data sets, so responsiveness / affection is important for them).

The problem is that if you click on one of the headers to sort the data, it will take about 20 seconds (on a 2x3 GHz dual-core Core 2 Duo processor). Is there any way to speed this up?

It seems that it reconstructs the entire visual tree when sorting, and this seems unnecessary. Any pointers on how to speed up this particular situation will be appreciated, even if it comes to compiling our own version of the grid.

Thanks.

<Window x:Class="WpfGridTest1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <DataGrid Name="dataGrid" VirtualizingStackPanel.IsVirtualizing="False"> </DataGrid> </Grid> </Window> using System.Collections.Generic; namespace WpfGridTest1 { public partial class MainWindow { public MainWindow() { InitializeComponent(); List<Row> rows = new List<Row>(); for (int i = 0; i < 1000; i++) { Row row = new Row { Column0 = i, Column1 = i, Column2 = i, Column3 = i, Column4 = i, Column5 = i, Column6 = i, Column7 = i, Column8 = i, Column9 = i, Column10 = i, Column11 = i, Column12 = i, Column13 = i, Column14 = i, Column15 = i, Column16 = i, Column17 = i, Column18 = i, Column19 = i, Column20 = i, Column21 = i, Column22 = i, Column23 = i, Column24 = i, Column25 = i, Column26 = i, Column27 = i, Column28 = i, Column29 = i, Column30 = i, Column31 = i }; rows.Add(row); } dataGrid.ItemsSource = rows; } } } using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; namespace WpfGridTest1 { class Row : INotifyPropertyChanged { private double column0 ; private double column1 ; private double column2 ; private double column3 ; private double column4 ; private double column5 ; private double column6 ; private double column7 ; private double column8 ; private double column9 ; private double column10; private double column11; private double column12; private double column13; private double column14; private double column15; private double column16; private double column17; private double column18; private double column19; private double column20; private double column21; private double column22; private double column23; private double column24; private double column25; private double column26; private double column27; private double column28; private double column29; private double column30; private double column31; public double Column0 { get { return column0 ; } set { column0 = value; NotifyPropertyChanged("Column0 "); } } public double Column1 { get { return column1 ; } set { column1 = value; NotifyPropertyChanged("Column1 "); } } public double Column2 { get { return column2 ; } set { column2 = value; NotifyPropertyChanged("Column2 "); } } public double Column3 { get { return column3 ; } set { column3 = value; NotifyPropertyChanged("Column3 "); } } public double Column4 { get { return column4 ; } set { column4 = value; NotifyPropertyChanged("Column4 "); } } public double Column5 { get { return column5 ; } set { column5 = value; NotifyPropertyChanged("Column5 "); } } public double Column6 { get { return column6 ; } set { column6 = value; NotifyPropertyChanged("Column6 "); } } public double Column7 { get { return column7 ; } set { column7 = value; NotifyPropertyChanged("Column7 "); } } public double Column8 { get { return column8 ; } set { column8 = value; NotifyPropertyChanged("Column8 "); } } public double Column9 { get { return column9 ; } set { column9 = value; NotifyPropertyChanged("Column9 "); } } public double Column10 { get { return column10; } set { column10 = value; NotifyPropertyChanged("Column10"); } } public double Column11 { get { return column11; } set { column11 = value; NotifyPropertyChanged("Column11"); } } public double Column12 { get { return column12; } set { column12 = value; NotifyPropertyChanged("Column12"); } } public double Column13 { get { return column13; } set { column13 = value; NotifyPropertyChanged("Column13"); } } public double Column14 { get { return column14; } set { column14 = value; NotifyPropertyChanged("Column14"); } } public double Column15 { get { return column15; } set { column15 = value; NotifyPropertyChanged("Column15"); } } public double Column16 { get { return column16; } set { column16 = value; NotifyPropertyChanged("Column16"); } } public double Column17 { get { return column17; } set { column17 = value; NotifyPropertyChanged("Column17"); } } public double Column18 { get { return column18; } set { column18 = value; NotifyPropertyChanged("Column18"); } } public double Column19 { get { return column19; } set { column19 = value; NotifyPropertyChanged("Column19"); } } public double Column20 { get { return column20; } set { column20 = value; NotifyPropertyChanged("Column20"); } } public double Column21 { get { return column21; } set { column21 = value; NotifyPropertyChanged("Column21"); } } public double Column22 { get { return column22; } set { column22 = value; NotifyPropertyChanged("Column22"); } } public double Column23 { get { return column23; } set { column23 = value; NotifyPropertyChanged("Column23"); } } public double Column24 { get { return column24; } set { column24 = value; NotifyPropertyChanged("Column24"); } } public double Column25 { get { return column25; } set { column25 = value; NotifyPropertyChanged("Column25"); } } public double Column26 { get { return column26; } set { column26 = value; NotifyPropertyChanged("Column26"); } } public double Column27 { get { return column27; } set { column27 = value; NotifyPropertyChanged("Column27"); } } public double Column28 { get { return column28; } set { column28 = value; NotifyPropertyChanged("Column28"); } } public double Column29 { get { return column29; } set { column29 = value; NotifyPropertyChanged("Column29"); } } public double Column30 { get { return column30; } set { column30 = value; NotifyPropertyChanged("Column30"); } } public double Column31 { get { return column31; } set { column31 = value; NotifyPropertyChanged("Column31"); } } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(String info) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(info)); } } } } 

UPDATE: I tried the AngelWPF suggestion as follows:

 private void dataGrid_Sorting(object sender, System.Windows.Controls.DataGridSortingEventArgs e) { e.Handled = true; IQueryable<Row> iqueryable = _rows.AsQueryable(); var v = iqueryable.OrderBy(row => row.Column0); foreach (Row row in v) System.Diagnostics.Debug.WriteLine("Row " + row.Column0); _rows = new ObservableCollection<Row>(v.ToList()); dataGrid.ItemsSource = _rows; } 

Although the performance issue still exists as it restores the grid.

+4
source share
3 answers

Without virtualization, there is no chance of performance improvements!

Why is virtualization lacking? The problem of flaccid scrolling of a datagrid can be solved ... how these messages can help ... Performance WPF Datagrid , Slow and Stuttery WPF Grid Scrolling when loading large amounts of data (40 columns, 2000 rows) , http://www.codeproject.com /KB/WPF/WpfDataVirtualization.aspx .

Having said that, there is one way to improve sorting in a non-virtualized data grid.

  • Handle the DataGrid.Sorting event and set e.Handled = true in your handler. This way the datagrid will not do the sorting.
  • In the above handler, looking at the column name, you will recognize the property that the column represents or is bound to. Therefore, use this property name and use LINQ AsQueryable () to sort. This will be the fastest way to sort ItemsSource data.
  • Set the sorted collection back to ItemsSource .

We tried to use the above approach for version-independent data that displayed a lot of colors, effects and 30,000 rows of 30 columns, and the result was amazing.

Queryable LINQ Can Do Miracles!

+4
source

I had a problem with a DataGrid in which it took literally seconds to refresh after sorting a column, resizing, etc. and block the user interface of the window when it did (1000 rows, 5 columns).

This led to a problem with WPF size calculations. I had this in a grid with RowDefinition Height = "Auto", which made the rendering system try and recalculate the size of the DataGrid at runtime, measuring the size of each column and row, presumably filling the whole grid (as I understand it). He must perceive it reasonably in some way, but in this case it is not.

A quick check to make sure this is a problem is to set the height and width of the DataGrid to a fixed size throughout the test and try again. If your performance has been restored, there may be a permanent fix among these options:

  • Resize contained elements as relative (*) or fixed values
  • Set MaxHeight and MaxWidth DataGrid to a fixed value greater than it can work normally.
  • Try using a different type of container with a different resizing strategy (grid, DockPanel, etc.)
+1
source

From the updated section:

 foreach (Row row in v) System.Diagnostics.Debug.WriteLine("Row " + row.Column0); _rows = new ObservableCollection<Row>(v.ToList()); 

Why don't you turn off WriteLine? This may not be good in terms of performance. Also, is there a reason you are re-initializing the _rows variable in the new ObservableCollection? If possible, convert _rows to a property and then raise the NotifyPropertyChanged event when you change the value.

Of course, you will also have to change the data binding for the grid to this new property.

0
source

All Articles