10 Ways to Improve the Performance of Your WPF Application

Introduction

Windows Presentation Foundation (WPF) applications tend to be slower on lower end machines or on machines without graphic acceleration devices. They seem to eat up resources and make the application unstable. However, note that the performance of a WPF application depends on the hardware you have. So higher end machines obviously have a greater edge when it comes to WPF applications.

But, before we delve into the optimization techniques, it is sensible to agree that design and planning a product in its best terms can help us remove the bottlenecks in its performance. Another notable point is that the performance improvement is not a one-step process. It should be indulging and iterative part of the development process. Good design of a WPF application can remove the irrelevant aspects that hinder the performance. For example, construction of objects at run time deteriorate the application’s performance.

Although WPF offers rich User Interface with impressive navigation and much more, you should consider this only if your user base requires a rich graphics interface. Nevertheless, WPF applications offer their flexibility when it comes to UI with their customizable styles, and control templates.

WPF architecture. Blue elements are Windows components; brown ones are WPF components.
Figure 1 (Image Source: Wikipedia)

The primary factor in rendering a WPF application is behind the number of pixels in it. The hardware rendering pipeline of WPF uses Microsoft’s DirectX features on the hardware that the application is run. So if you have a dedicated GPU on the machine, the performance is immensely better.

Lower The Bitmapscalingmode to Render Images Faster

You can lower the consumption of resources on a machine when you have certain animations being processed by your WPF application. To do this, you need to use the BitmapScalingMode property of the RenderOptions object.

You would need to use the “LowQuality” option from the BitMapScalingMode enum to ensure that the image is processed using the speed algorithm instead of the default high-quality image re-sampling algorithm.

The following code snippet shows you how to do that:

  RenderOptions.SetBitmapScalingMode(imageObject,BitmapScalingMode.LowQuality);

Use The Right Elements in the Right Places

We need to use the right elements in the right places. Avoid UIElements as child or nested controls when you build the tree. The best example is the Flow Document. We often use the TextBlock element inside the FlowDocument.

  <FlowDocument>
    <Paragraph>
      <TextBlock>some text</TextBlock>
    </Paragraph>
  </FlowDocument>

Instead of doing above, we can rewrite the XAML content as shown below. The Run element is not a UIElement and involves lesser overhead while rendering.

<FlowDocument>
 <Paragraph>
   <Run>some text</Run>
 </Paragraph>
</FlowDocument>

A similar example is the usage of Content property of the Label Control. If this content is updated more than once in its lifetime and is a string, this databinding procedure can hinder the application’s performance. Since the Content is a string, it will be discarded and recreated during the databinding. Use a TextBlock in such cases and data bind to its Text property.

The unnecessary elements in the visual tree also contribute to the slowness of WPF applications. You should ideally combine the layout and optimize the default control templates.

Increase Usage of Static Resources

Static resources are pre-defined resources that can be hooked to XAML properties. It is similar to Compile-time tie up’s and does not have a performance impact. The dynamic resources on the other hand involve a run-time seek and also construction of such objects which lead to performance impacts. Doing it this way also enables you to share common resources like brushes.

Also note that the static resources need to be present at compile time.

Read the article on XAML Static Resources at DevX (Simplay XAML with Static Resources for a deeper insight into usage of Static Resources. The following XAML snippet is from this article.

A Static resource can be referenced in the following manner:

  <Button
   	 Template="{StaticResource RoundButtonWithThickEdge}"
    	 x_Name="button1" Content="Button 1" >
  </Button>

The following code snippet shows definition of the Static resource: RoundButtonWithThickEdge

   <ControlTemplate
       x:Key="RoundButtonWithThickEdge"
       TargetType="{x:Type Button}">
       <Grid>
         <Ellipse Fill="{TemplateBinding Background}"
           Stroke="{x:Null}"
           HorizontalAlignment="Stretch" x_Name="ellipse"/>
         	<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
         		<Ellipse Stroke="{x:Null}" Margin="2,3,4,5">
           		<Ellipse.Fill>
             		<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
               	<GradientStop Color="#FFFBFAFA" Offset="0"/>
              	<GradientStop Color="#1DFFFFFF" Offset="1"/>
             </LinearGradientBrush>
           </Ellipse.Fill>
         </Ellipse>
       </Grid>
     </ControlTemplate>
 

Use Controls with UI Virtualization When You Display Large Data

Imagine binding a combo box with large number of rows. Would it not make the rendering of the items in the combo box pretty slow? The slowness is caused by the time taken to compute the position of each item in such a situation. With WPF, you can defer this behavior.

This is called as UI Virtualization and it simply refers to the item container generation only on its visibility.

To achieve this, you need to set the IsVirtualizing property to true for such controls. For example, Listbox is a control which often is bound with a large set of data and is a primary candidate for UI virtualization. Other examples include Combobox, ListView, and TreeView.

Use Deferred Scrolling to Enrich User Experience

If you remember scrolling the datagrid or a listbox, it often slows down the entire application because of the continuous updates that are invoked forcibly due to the scrolling. This is the behavior by default. In such cases, we can use the “Deferred Scrolling” property of the controls to enrich the user experience.

All you have to do is set the IsDeferredScrollingEnabled attached property to true.

Use Font Cache Service to Improve the Start-up Time

The WPF applications can share the font data among them. This can be achieved through the Windows service named PresentationFontCache Service. This is automatically started with windows.

You can find this service under the Services panel (Type "Services.msc" in your run menu with the double quotes, and check for this service) and ensure that is started.

Use Unloaded Event to Unload Unnecessary Animations

Animations definitely take a toll on the resource utilization, and would also increase if they are not disposed of in the right manner. You should dispose of them when you consider them useless. Failing to do so, will consume precious resources until Mr. Garbage Collector kicks in.

For example to remove a story board, use the Remove method of the Story board in the Unload Event. The following example from MSDN shows this:

  <EventTrigger RoutedEvent="Page.Unloaded" >
          <EventTrigger.Actions>
            <RemoveStoryboard BeginStoryboardName="myBeginStoryboard" />
          </EventTrigger.Actions>
  </EventTrigger>

Use Container Recycling to Increase Performance

You can increase the performance by recycling the containers that perform the Virtualization. The following code snippet sets the ViruatlizationMode to “Recycling” which allows you to gain more performance.

This forces the container objects to be reused when the user scrolls and reaches another item.

  settingVirtualizingStackPanel.VirtualizationMode="Recycling"

Predict the Graphics Capability and Provide Features

Use the RenderCapability.Tier property to determine if the machine supports hardware acceleration, partial hardware acceleration, or no acceleration:

The sample code below shows you how to check the Tier:

  int displayTier = (System.Windows.Media.RenderCapability.Tier > 16)

  if (displayTier == 0)
  {
     //no hardware acceleration
  }
  else if (displayTier == 1)
  {
     //partial hardware acceleration
  }
  else
  {
     //supports hardware acceleration
  }

After you determine this, you can then selectively choose those capabilities that work best on the user’s hardware.

Use WPF Profiling Tools to Profile a WPF Applicaton

Profiling a WPF application is an important step to understanding its behavior. There are lots of tools in the market for profiling WPF applications.

Here is a small compilation of such tools:

The Perforator, Visual Profiler is part of the WPF Performance Suite.

Conclusion

To know more about these tools, please visit their respective homepages. Link to one of the excellent write-ups on WPFPerf can be obtained in the References.

Hope you enjoyed reading. Please leave your valuable comments.

References

Optimizing WPF Application Performance
WPF Performance Suite
Simplay XAML with Static Resources
Analyze performance issues in your WPF application with WPFPerf

Related Articles

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read