Scrolling Performance in WPF
With the beta release of .NET 3.5 SP1, scrolling received some much needed performance increases! Lets review first what we used to have and how it has now changed:
The problem:
This is a example of how a ListBoxItem can now look using WPF! Looks very nice... but it is very taxing... A item like this can contain 30+ UI Element! Imagine if I now have a list of 300 items x 30 UI Elements? It quickly escalates!
The solution (Pre SP1):
So, how do we reduce the amount of UI element to be created? VirtualizingStackPanel has been available from the start... It does a excellent job of reducing the amount of UI elements created based on what is visible on the screen. It only creates UI elements actually visible on the screen (ok, and a little bit extra), but it does a excellent job at reducing the amount of UI elements created!!! The only real draw-back of this design is that it is very processor intensive creating and destroying the needed items! This is were SP1 comes to the rescue!
The solution (SP1):
From SP1, by changing the VirtualizationMode to Recycling, the VirtualizingStackPanel tries to reuse the UI elements! This dramatically reduces the amount of create/destroying that use to happen!!! By default, the ListBox doesn't use the recycling mode, to turn it on, add the following:
VirtualizingStackPanel.VirtualizationMode="Recycling"
Another scrolling performance enhancement is deferred scrolling... Until recently I haven't even noticed that this is what Outlook uses! Next time you use outlook, look at how it scrolls large collection of items (Like 100's of mail)! The screen only updates when you actually release the mouse button... this creates the illusion of very responsive scrolling!
To turn on deferred scrolling, add the following:
ScrollViewer.IsDeferredScrollingEnabled="True"
These are very small changes that can give you HUGE performance increases!!! It is very difficult to measure scrolling performance but I have made some small test to try and see what happens!
I created 3 ListBox all using the same data source (A observable collection of a 100 strings). The first list box is a standard ListBox, the second I turned on recycling and the last I also turned on deferred scrolling!
I then wrote a little function that counts each ListBox UI elements. I am also running a BackgroundWorker thread that constantly monitor the amount of UI elements and then writes it to the screen... here is my results
The ListBox with only VirtualizingStackPanel's item count on startup is 140, while scrolling it varies from 130-450. I then did the same test with the ListBox with the mode set to Recycling. Here the count varies from 130-150 and I had the same results with deferred scrolling turned on!
From this is is relatively obvious that less UI elements gets created and thus faster response with less CPU used!
Were can I read more
Recycling that Item Container by Vincent Sybal
Also read this article by Cedric Dussud