It's about 10 years since the first official release of WPF. We started our XAML development almost at the same time. Even with such a long history, we're still trying to improve: have we really succeeded in creating fast, flexible controls? I wasn't able to find any good WPF datagrid performance comparison out there, only a few old discussions about now-defunct controls. This benchmark is an attempt to review our strong and weak points comparing with different data grids on the market in several key use cases.

Environment


This benchmark was created in June 2016 using next datagrid controls (we used the latest trial versions available for downloading):


The benchmarks were run on HP ENVY-23 All-in-One Desktop with next parameters:

Intel i7 quad-core CPU @ 3.10 GHz
8 GB RAM
NVIDIA GeForce GT 630M display adapter, Full HD (1920 x 1080) resolution
Windows 10 Pro 64-bit OS


All grids were set to equal size, and default appearance.

WPF DataGrid Performance Test Application


Our benchmark application allows to select and run single test or run all tests one-by-one. You can select how many times to run the same test, so that to get average value in results. We did it to reduce possible side effects from OS or other applications interaction. All test results shown here were get with 10 runs. Application window is shown below:


Benchmark application window


Running a single test is handy if you want to profile some specific use case. Note: if you need comparable results for different tests, don't change window size while the tests are running. Actual view port size affects performance numbers as larger screens take more time for layout and leave less space to virtualization.


The application writes the results into an Excel file in the working folder. If you need a more detailed log file, you can uncomment output into TraceListener in App.xaml.cs file.


The main point of interest here is how to measure time for complex operations with async UI updates. After several experiments, we found what we think is the most appropriate way to get exact moment when datagrid UI has finished all updates. The full source code is attached, so you can give it a try. We will be glad to hear any feedback if you think that we can improve something.


We don't include any control binaries here. If you want to run the application, you will need the trial version of our WPF Edition and trial versions of competitors suites. All are available for free 30-day evaluation, so it shouldn't be a problem.


Benchmarks


As a data source we selected ListCollectionView and filled it with business objects defined like this:



public class Customer : INotifyPropertyChanged, IEditableObject
{
public int ID { get; set;}
public string Name { get;}
public string Country { get;}
public int CountryID { get; set;}
public bool Active { get; set;}
public string First { get; set;}
public string Last { get; set;}
public DateTime Hired { get; set;}
public double Weight { get; set;}
public string Father { get;}
public string Brother { get;}
public string Cousin { get;}
}

It gives us 12 columns of different types.


We tried to put all grids into the same conditions, so for some controls, we changed default settings to achieve this:



  • Auto-generated columns

  • Fixed column width

  • Allow adding new rows with new row position at the bottom

  • Hidden group and search panels

  • Editable cells



Every benchmark follows the same steps:



  1. Remove all UI created by the previous test, call GC.Collect and GC.WaitForPendingFinalizers so that garbage collection doesn't affect the next test;

  2. Initialize next test and Stopwatch;

  3. Run test required number of times;

  4. Measure total time and count average result;

  5. Log results.



Let's explain some implementation details about specific benchmarks.



Benchmark 1: Create control and load data


This benchmark creates a user control containing a tested datagrid, inserts it into visual tree, and fills with data. The only problem here we had with Xceed DataGridControl, which didn't work when created from code. So you'll see that attached application sets it up in XAML.


Benchmark 2: Re-load data into existing control


This benchmark sets the DataGrid's ItemsSource to null to clear both data and autogenerated columns, and then sets ItemsSource to new ListCollectionView. In code it looks like this (the same for all tested controls):



public override void Load(IList data)
{
if (data == null)
{
_grid.ItemsSource = null;
}
else
{
_grid.ItemsSource = new ListCollectionView(data);
}
}

Benchmark 3: Sort single column


We tried to reduce custom code in our tests, so in most cases we made it via ICollectionView interface:



public override void Sort(bool ascending)
{
ICollectionView dataView = CollectionViewSource.GetDefaultView(_grid.ItemsSource);
dataView.SortDescriptions.Clear();
dataView.SortDescriptions.Add(new SortDescription("ID", ascending ? ListSortDirection.Ascending : ListSortDirection.Descending));
}

This is standard, and we expected that every datagrid should support it out-of-the box. But we weren't able to make it work in Syncfusion's SfDataGrid, so we had to implement sorting via the SfDataGrid.SortDescriptions property.


We met a bit different problem in XamDataGrid from Infragistics. It can work with ICollectionView sorting, but becomes extremely slow on big data. As we wanted to get comparable results across all controls, we ended up implementing it via the FieldLayout.SortedFields property.


Benchmarks 4 and 5: Scroll on 100 rows; Scroll full grid


We thought it would be nice to mimic end-user interaction in this test, but didn't find good way for this. We could probably do this by finding ScrollBars in the visual tree and working with them, but the related code could also affect performance, so we decided to stick on bringing specific row into view. All datagrids have ScrollIntoView or similar methods to do this.



Test Results


Initial Load Time


To avoid counting JIT compilation and XAML parsing times in all other tests, we started the whole benchmark for every control from a single separate test. It's exactly the same test as in Benchmark 1. When you run it for the first time during application life time, you can see the difference with all next runs. It worth measuring as application launch time might be critical for WPF. This test shows almost the same results regardless of data size:


Initial load times



Benchmark with Fixed Width Columns


Below are the results for data sources with 1,000, 10,000 and 100,000 items.


Results for 1000 data rows with fixed width columns



Results for 10,000 data rows with fixed width columns



Results for 100,000 data rows with fixed width columns



Benchmark with Auto Width Columns


After running tests with fixed-width columns, we decided to compare how it looks with auto-sizing. We only did it for the four datagrids that support on-the-fly auto-sizing. We wanted to get comparable results in the best conditions for every tested control. So we selected default SizeToHeader option for MS's DataGrid and Telerik's RadGridView, default AutoStar option for our C1DataGrid and FieldLength.InitialAuto option for Infragistics's XamDataGrid.


Why didn't we do this test for all controls? Our C1FlexGrid, GridControl from DevExpress and Xceed's DataGridControl don't support on-the-fly auto-sizing. Apparently it's an intentional choice of control authors that allows them to focus more on performance. All these controls support auto-sizing with method calls. But to do this, you should call the correct method at the correct time. It makes it hard to measure overall performance, and you can't be sure that the results only depend on control performance. So we didn't include these controls in our comparison.


On the contrary, SfDataGrid from Syncfusion has no autosize option similar to those used in MS DataGrid and others, and since the available options become extremely slow with big data, it's incomparable with other controls. So we excluded it from this test as well.



Below are the results we got for data sources with 1,000, 10,000 and 100,000 items (the same benchmarks as with fixed-width columns).


Results for 1000 data rows with auto width columns



Results for 10,000 data rows with auto width columns



Results for 100,000 data rows with auto width columns



Some Conclusions


Our results are a bit different from what we saw in old discussions about WPF datagrid performance. Apparently, now all controls use virtualization and can handle big data sources. If you're selecting a datagrid for your new application, you can consider our test results as a starting point.


Additionally, note that we didn't test many other scenarios like grouping, filtering or column virtualization. Also, performance is not everything, so you might like or not like some control because of many other reasons, like ease of use, XAML customization, the number of features supported out-of-the-box, etc.


While working on this benchmark I read a lot of information about competing controls and got an impression that all WPF datagrids fall into two categories:



  • Performance-based grids, which were not included in tests with auto-sizing

  • Grids focused on ease of use and XAML usage


We have one of each in our WPF Edition, so you can choose which one is best for your requirements. For more information, see detailed feature comparison of C1FlexGrid, C1DataGrid and MS DataGrid in attachment.


Finally, during this whole benchmark job I couldn't help but profile our own controls. So we got another useful result from it: the 2016 v2 version of C1DataGrid is about 35% faster than in previous release.





Read 2017v1 update