Developer Exchange Blog
Application UI Performance Tuning for WPF (Windows Presentation Foundation) Applications
Today’s complex applications often require immense amounts of data along with a large number of WPF controls in a single window. It’s no wonder UI performance can start to suffer. This article offers some straightforward solutions to improve your UI performance.
Even when your control is required to hold large amounts of data, everything isn’t displayed on the screen all the time (or at least, for the user’s sake, we hope it isn’t). However, this data is still rendered in the background which can significantly slow processing time. UI Virtualization addresses this problem by causing a control to render data only as it is needed in the viewable area. Some controls, such as the Listbox, can automatically implement UI virtualization, but most others do not. That’s no problem when you know a little about how to incorporate UI virtualization into commonly used WPF controls.
The part of a control that handles rendering data on the display is referred to as the layout control. Most WPF controls use a StackPanel as the layout control, but a VirtualizingStackPanel can be used instead. The VirtualizingStackPanel works in the same way as the StackPanel, except it incorporates UI virtualization of its data elements. By using this control, your UI performance is immediately improved because only the viewable portion of the data is processed in order to render the screen.
Unfortunately, not all controls can use a VirtualizingStackPanel as their layout control (that would just be too easy). Only controls that use the ItemsControl class to manage data items can take advantage of the VirtualizingStackPanel. Also, it’s important to note that your data must be bound to the ItemsControl in order for virtualization to work using this method.
Another option available for improved UI performance in your WPF application is to work with the UI thread. Most WPF classes are derived from the DispatcherObject class. The main purposes for the DispatcherObject class are to provide access to an object's current Dispatcher, provide access to the prioritized message loop for WPF applications, and to verify that a thread has access to the object. This verification is necessary because WPF allows UI objects to be used only by the thread on which they were created. Generally, the Dispatcher is used to send work items into the UI thread for processing. Therefore, you can use the Dispatcher to invoke UI updates from other background threads. The result is increased application responsiveness for the user because updates to the UI occur while background threads are running.
The BackgroundWorker class is still another option that does not involve UI thread handling. The BackgroundWorker class uses the AsyncOperationManager to marshal calls to update progress of the UI thread. The AsyncOperationManager is well suited for this operation because it starts up holding an instance of the proper Dispatcher context for a WPF application. You can use the BackgroundWorker to perform long data initialization operations and report progress to the UI using the BackgroundWorker.ReportProgress() call. Performance is enhanced by performing other initialization operations simultaneously while retaining the responsive feel of your application with progress reports to the user.
Timers can be another effective tool. While timers have been around for years and may not sound very exciting, WPF applications can make use of the DispatcherTimer that calls the Dispatcher to execute code at specified intervals. You can also assign a priority to the DispatcherTimer so execution of the code can be processed using a range of priority levels. The DispatcherTimer is particularly helpful when you need to manage a large number of controls that have to be rendered on a WPF window. This tool allows you to have more precise control over your UI components, making your application more responsive.
Finally, a simple and effective way to manage rendering large amounts of data is an Expander control. This control is most useful when the screen can initially display only summary information. Of course, the user will have the option to view the supporting detail when and if needed. You will just need to set the content area of the Expander to default to collapsed display. Since the controls within the content area will not be rendered until the content area is expanded, your application responsiveness is greatly improved.
While this is just a quick introduction to some of the simple and effective tools available for UI performance tuning, I hope you can see that even with the demands on today’s applications to manipulate and display immense amounts of data, the lack of UI performance doesn’t have to be the accepted trade off. Just being aware of some of the options available can help you make a tremendous difference for the end user.