Improving the WPF DataGrid performance
Over the past six months, the DXGrid team has been making progress improving our WPF data grid in two orthogonal directions. First they've been adding extra functionality you can read about here; things like printing support (including printing to PDF, HTML, XLS(X), etc, etc), editors, data validation, new item row, and so on, and second, they've been improving its performance.
Don't get me wrong, the performance was great to begin with. We've always gone after performance when scrolling, filtering, sorting, grouping and the like, and, like our other data grids for WinForms, ASP.NET and Silverlight, we've certainly concentrated on processing large data sources quickly using server mode. But there was one scenario we weren't happy with: the initial load time. That is, the time taken from starting to display a form containing a grid to the point where it's usable.
I thought it would be instructive to anyone creating a WPF application to discuss what we found and what we decided to do about it. The conclusions we reached have already affected (and will affect) our other controls and you may learn something from this investigation yourselves in your own work.
The team did a couple of spikes with profiler in hand. (Yes, it does bear pointing out explicitly: you can't decide anything about performance or know where such issues exist unless you use a profiler. There are a couple of very good ones on the market, so go buy one now if you're interested in improving performance.) The spikes gave us these two issues:
- we had a large visual element tree for each row and cell
- we had a large number of data bindings happening for each cell
The first was more due to our desire to have a very flexible and theme-able data grid, where you, the developer/designer, could manipulate appearance and effects down to the smallest detail using XAML. Once the visual tree was created (which took time), it would be reused for any further manipulations with the grid and was very fast since everything was already present. The conclusion was we should reduce the size of the visual tree to improve the initial load time.
Here's some statistics. Between the v2009.1 beta (which is all anyone has at the moment) and the v2009.2 release (coming soon), the number of visual tree elements for a text cell has been reduced from 11 to 4, and the number of visual elements for a row (excluding the cells), down from 38 to 32 (and we're dithering about removing another couple). What does that mean in terms of time? Well for a grid showing 30 active rows with 12 columns, the team have halved the initial load time. For 5 columns, it's about 2/3 of the original time.
The benefits of these optimization efforts are three-fold: first, of course, the initial load is much faster. Second, the changes also improve the speed of operations like resizing or moving columns (the visual tree needs fixing up in those scenarios too), or of expanding/collapsing groups (again, the visual tree needs fixing). In these scenarios, the time taken to fix up the visual tree was originally hidden to a certain extent by the fetching of data.
Third, despite the reduction in visual elements, we've still managed to maintain the flexibility of the tree with regard to applying themes. We felt that the ability to theme our grid was of extreme importance to the designers and developers using our WPF data grid: they should be able to easily change the appearance using XAML because, well, that's what you do with WPF. We did consider removing more visual elements and instead hard-coding the visual appearance (some work was done on this to prove it could have improved performance further), but we strongly believe that in so doing we'd have tossed out the appearance customization baby with the visual element bathwater. So, we stopped where we did because we thought that we had the right tension between flexibility and performance.
The second performance issue above was due to some inefficient programming, more than anything else. So, in order to improve things, all we had to do was improve the code that bound data, or make sure it only happened once.
So, in conclusion, when you are writing your WPF application, pay special attention to your visual tree. Just because creating a single visual element is fast, don't forget that it takes time to create a lot of them and it's all too easy to overload your visual element tree using the designer. So make sure that your own initial load times are kept in check.