Lately I am confronted with quite a few cases where the performance of WPF is shady to say the least. This however does most of the time have a reason outside of the framework. In this article I want to show a few things that you can do to make your WPF application perform better and use less memory.
Layering
Layering controls in a user interface can be useful to achieve particular layouts, it however can also be misused to overcome basic layout problems that are better solved in a different way. One example is a case where a stackpanel contains three grids to make a form that has three textboxes with labels in front. This can also be done with one grid. While this is example is obviously not something most developers will do, it does happen with more complex scenarios.
When you notice that the screen loads slow and you cannot find a reason in the code that loads the data to display; Consider checking how your GUI is build. It may well be that it has a lot of layers which all have to be processed by WPF. There are known limitations with layered window constructions in Windows Vista. Most of them are solved in SP1, but it’s still a good idea to limit the amount of layers used.
Freezables
Each graphics object in WPF can have two states: Unfrozen and frozen. Most of the freezable objects used in WPF are graphics object. Because most of these objects use unmanaged resources WPF keeps track of the changes made to the freezable objects and update the unmanaged resources accordingly. This costs performance and sometimes quite a lot performance.
To improve on this you can Freeze() an object. This will make your application a lot faster on some cases. It also makes it possible to share the frozen object between threads. This last feature doesn’t actually improve performance, but make your life a whole lot easier if you work with multiple threads in WPF.
Slow listboxes
I have seen a lot of listboxes in WPF that were slow when you started the application. The main reason for this is because people have skinned their application, but failed to use a virtualizing panel for the items in the listbox that they had skinned. A virtualizing panel reuses items that are no longer visible to paint items that are currently visible. As you might have figured out: It only paints items that are visible, thus reducing the amount of work required to fill the listbox.
Dynamically building user interface components
You don’t need this very often, but I found out that it makes a huge difference in which order you add controls to the logical control tree when not working with XAML. Appearantly, WPF doesn’t handle building control trees bottom-up. It saved me 50% of the loading time of a printing job (!) reversing the code that builds the control tree of my FixedDocument class.
After reading up on this on MSDN I discovered that WPF is optimized for top-down tree building. This is done so that once a parent is constructed only the properties that have something to do with its children are validated. This saves on rendering time and I can imagine makes it simpler to create WPF controls. When you construct the tree bottom-up you end up having to revalidate the whole tree each time a control is added to the tree.
The best way to prevent this from happening is to use XAML as much as possible and to keep in mind that you need to construct control trees in code in a top-down fashion.
When to start optimizing
Optimizing WPF applications can take quite a lot of time, which you may not have when building an application for a client. All developers have this problem. WPF performance optimization is best done when you are either building custom controls or when you are starting to get to a point where you are noticing that the performance of certain areas of your application is substandard. This may sound like fixing something that you could have prevented in the first place. However most developers who work with the standard WPF controls and maybe skinning are not hitting these performance issues.
There are cases where you want to check up on performance ahead of the game:
- You are asked to create a GUI with more then 30 controls.
- You are asked to create a GUI with a complex custom control.
The moral of this story is: As long as you are not doing something really crazy you should not have to worry about these things.