Click here to Skip to main content
Click here to Skip to main content

Solutions for WPF Performance Issue

, 7 Jul 2014
Rate this:
Please Sign up or sign in to vote.
WPF performance

Introduction

Sometimes we encountered WPF performance issues. Issues that i had met most often are

  • Application contains Large Data GridViews(or TreeListView). TreeListView has been rendering in a real-time mode (Be refreshed every second). 
  • Application contains rich rendering UI elements. Lot of animations are triggered every 0.1 second
  • Application was running on a distance desktop (or virtual machine)  

We need to find out the reasons of performance issue then resolve these issues with our acknowledges. Here is a resume of needed acknowledges:

  1. Basic knowledges of WPF rendering.
    1. Pixel Snapping in WPF Application
    2. WPF Visual Rendering
  2. Detect issues with WPF performance suite - Performance Profiling Tools for WPF
    1. Detect Software Render
    2. Detect Undesired Rendering
  3. Make a trade-off between graphique's quality and performance.
    1. Disable Pixel Snapping and Anti-Aliased option
    2. RenderOption
    3. UIElement.CacheMode and BitmapCache
  4. Make a trade-off between architecture and performance
    1. IValueConverter and IMultiValueConverter
  5. Improving scrolling performance in WPF
  6. WPF in remote desktop
  7. Third party libarary
  8. Brief and Conclusion
  9. References

 

PS:

if("You prefer all useful official articles" == true)
{
    Console.WriteLine("Lot of paragraphs of this article are copied directely from MSDN pages");
    goto Chapiter References
}

Basic Knowledges of WPF rendering

Here will discuss two basic knowledges of WPF, Pixel snapping and Visual Rendering. These will tell you how WPF UI elements are rendered by GPU or CPU. How many visual elements will be rendered while you move your mouse through a user control (which only a green rectangle you could see).

Pixel Snapping in WPF Applications

The WPF graphics system uses device-independent units to enable resolution and device independence. Each device independent pixel automatically scales with the system's dots per inch(dpi) setting. UIElement.SnapsToDevicePixels provides WPF applications proper scaling for different dpi settings and makes the application automatically dpi-aware. 

There are two system factors that determine the size of text and graphics on your screen: resolution and DPI. Resolution describes the number of pixels that appear on the screen. As the resolution gets higher, pixels get smaller, causing graphics and text to appear smaller. A graphic displayed on a monitor set to 1024 x 768 will appear much smaller when the resolution is changed to 1600 x 1200. The other system setting, DPI, describes the size of a screen inch in pixels. Most Windows systems have a DPI of 96, which means a screen inch is 96 pixels. Increasing the DPI setting makes the screen inch larger; decreasing the DPI makes the screen inch smaller. This means that a screen inch isn't the same size as a real-world inch; on most systems, it's probably not. As you increase the DPI, DPI-aware graphics and text become larger because you've increased the size of the screen inch. Increasing the DPI can make text easier to read, especially at high resolutions.  [Ref About Resolution and Device-Independent Graphics - WPF Graphics Rendering Overview]

However, this dpi independence can create irregular edge rendering due to anti-aliasing. These artifacts, commonly seen as blurry, or semi-transparent, edges can occur when the location of an edge falls in the middle of a device pixel rather than between device pixels. To address this issue, WPF provides a way for object edges in a visual tree to snap, or become fixed, to device pixels through pixel snapping, eliminating the semi-transparent edges produced by anti-aliasing.

Actually, anti-aliased is a better technologiy than aliased. Anti-aliasing is extremely important to making text legible. With few exceptions, anti-aliased text can dramatically reduce eye strain, no to mention that it renders glyphs much closer to their intended design. For more information of Anti-aliasing, i suggest you to read this article The Ails of Typographic Anti-Aliasing

With several techniques (ex. "Pixel snapping"), grpahics of applications could be better improved. This property could help activing pixel snapping and improve graphic effects. In most cases, pixel snapping using the SnapsToDevicePixels property will provide the desired outcome. How every, this property isn't always avaliable especially when using Drawing objects or dealing with a DrawingContext so guidelines (Guidelnes assist in adjusting geometries to a device pixel grid) must be set to achieve the desired sharpness pixel snapping provides. 

For more information of improving graphic effects of WPF application of Pixel Snapping, you could go to visit MSDN's official siteweb for getting more information of Pixel Snapping in WPF Applications. Techniques mentionned in this link will be useful if you continue to read my article.

PS: A sentence from Pixel Snapping in WPF Applications - "High frequency images should be avoided whenever possible in Windows Presentation Foundation (WPF) applications."

Go to MSDN's official siteweb for getting more information of Pixel Snapping in WPF Applications

Differences Between WPF and Winforms

The advantage of device-independent is obviously than WinForms's GDI mechanism. For example, un application built with GDI API use the hardware pixel as the unit of measure. In these applications, as the resolution of display device increases, the resulting image decreases. Application built in WPF use the device-independent unit (1/96-inch) as the unit of measure. When the DPI of the system is 96, the two are equivalent. For more comparison between GDI and WPF, you could read this article : Differences Between GDI and WPF (PS, this article is not provend by Microsoft neither by me).

WPF Visual Rendering

After discussion of pixel rendering layer, we'll talk about WPF's graphics rendering mechanism. WPF Graphics Rendering Overview is an unavoidable article if you don't want to miss the important performance issue of WPF. I suggest that you could read this MSDN article before continue reading my article.

But if you just want to have a short conclusion of Windows Graphics Rendering, here it is the conclusion - whatever looks like your UI control displayed, all its inner visual elements will be rendered while you might just move your mouse cross over it.

Thinking in this case : We have a ListView with more than 1000 rows and 30 columns inside. You customized the cell templates for each columns. Some of these cell templates have the complexe visual tree (for example, a ComboBox). What will be happened if you scroll your ListView? In the case of non-virtualized your ListView:

30 (number of columns) * 30 (number of rows displayed on screen) * 10 (visual elements in your cell template) = 9000 visual object will be drawed each 1/60 second.

If you don't understand the formula above, my explaination is that program enumerates all drawing objects in a drawing groupe. That's why this formular contains a number 10 which is the supposed number of drawing objects in a ComboBox. For verifing what i said, here is the link of codesource of ComboBox in MSDN. An other example from MSDN's article illustrated what it happended in a visual tree of a WPF application:

Image above shows a part of code of Xaml. A Label, a TextBox controls each display a separate visual object hierarchy in the Visual Tree Explorer panel. This proves that WPF controls have a ControlTemplate that contains the visual tree of that control. When you explicitly reference a control, you implicitly reference its visual hierarchy.

You might now be afraid of whether WPF will redraw full part of your UserControl while something was changing in your UserControl. The anwser is No. WPF will only redraw in the update region. But related with what i described above about ComboBox, I have to say Yes, the ComboBox will be fully redrawed if you do somthing on it. Read "Retained Mode Graphics" of article WPF Graphics Rendering Overview for getting more information about visual rendering behavior.

Another thing which is important, it's about WPF Graphics. WPF uses vector graphics as its redering data format. Vector graphics—which include Scalable Vector Graphics (SVG), Windows metafiles (.wmf), and TrueType fonts—store rendering data and transmit it as a list of instructions that describe how to recreate an image using graphics primitives. For example, TrueType fonts are outline fonts that describe a set of lines, curves, and commands, rather than an array of pixels. One of the key benefits of vector graphics is the ability to scale to any size and resolution.

Unlike vector graphics, bitmap graphics store rendering data as a pixel-by-pixel representation of an image, pre-rendered for a specific resolution. One of the key differences between bitmap and vector graphic formats is fidelity to the original source image. For example, when the size of a source image is modified, bitmap graphics systems stretch the image, whereas vector graphics systems scale the image, preserving the image fidelity. [Ref chapiter Vector Graphics of WPF Graphics Rendering Overview]

Detect issues with WPF performance suite - Performance Profiling Tools for WPF

There are always something wrong in the back of our WPF application. The WPF Performance Suite enables you to analize the run-time behavior of your WPF applications and determine performance optimizations that you can apply. Perforator in the Performance Profiling Tools is a performance profiling tool for analyzing the rendering behavior of your WPF application. The Perforator user interface displays a set of graphs that enable you to analyze very specific rendering behavior in parts of your application, such as the dirty rectangle addition rate and frame rate. WPF uses a rendering technique called dirty rectangle, which means that only the portions of the screen that have changed are rendered on a new rendering pass. In addition, Perforator also reports the software rendering targets and a slider to control the duration of the graphs.

Detecting Software Render

The WPF hardware rendering pipeline is significantly faster that its software rendering pipeline. Too much software rendering typically indicates a problem. Examples that would cause this behavior include tiling a Brush too much or exceeding the video card's texture size. Perforator allows drawing all areas rendered by using the software rendering pipeline with a purple tint. 

Software rendered BitmapEffect classes are slow and should be avoided. Perforator draws legacy software rendered bitmap effects with red tint.

Some my WPF applications run on the machines non graphic card. But my develop machine has a graphic card on the board. I set RenderOption.RenderMode to software, i used preforator to ensure that my application was running on the Software mode.

Detecting Undesired Rendering

Preforator provides 5 charts for real-time illustrating bad values of graph : Frame Rate, Dirty Rect Addition rate, SW IRTs Per Frame, HW IRTs Per Frame, Video Memory Usage. My applications have never been detected 3 last bad values (SW IRTs, HW IRTs, Video Memory Usage). I supposed that high values of SW IRTs Per Frame, HW IRTs Per Frame and Video Memory Usage mean the undesired renderings. 

Frame Rate reports the rate at which the application is rendering to the scree. For applications without animation, this value should be near 0. During animations in a well-performing application, Frame Rate should be close to the monitor's refresh rate (typically 60 or 75).

Dirty Rect Addition rate indicateds how many rectangular regions that  WPF has to update for each frame. Dirty rectangle refers to a rendering technique where only the portions of the screnn that have changed are rerendered. A high value indicates that a lot of regions are changing. This isn't necessarily good or bad but a value to consider with the overall performance of your application.

SW IRTs Per Frame shows the number of software intermediate render targets (IRTs) required to render one frame of the application. IRTs are expensive software surfaces that WPF must allocate and copy data to and from. Software IRTs are more expensive than hardware IRTs. IRTs are usually caused by using DrawingBrush,VisualBrushOpacity property on a Visual, or Tile modes on a TileBrush. If this number is high (for example, greater than 5), it indicates that the WPF runtime is performing a large amount of work to render your application. On a computer that supports hardware acceleration, this number should be 0. Otherwise, this number indicates that some of your scene is rendered by using the slower software pipeline.

HW IRTs Per Frame shows the number of hardware intermediate render targets (IRTs) required to render one frame of the application. IRTs are expensive hardware surfaces that WPF must allocate and copy data to and from. Intermediate render targets are usually caused by using DrawingBrushVisualBrush, or Opacityproperty on a Visual, or Tile modes on aTileBrush. If this number is high (for example, greater than 5), it indicates that the WPF runtime is performing a large amount of work to render your application. In this case, you will have to analyze all areas of your code that use the previously mentioned elements. Hardware IRTs are less expensive than software IRTs.

Video Memory Usage Tracks large allocations of video memory to WPF for texture and render targets. This metric does not track memory allocations to the video driver or memory allocations for compiling and loading pixel and vertex shaders. Exceeding the available amount of texture memory will usually cause WPF render logic to fall back to software, and that multiple displays (multi-monitor) have a multiplicative effect on the amount of video memory that is required for an application.

With using WPF Performance Suite, you could not only detect your application's performance and also the solutions. For example, after detected the problem, you may find that you've setted opacity on a high-level object (Button) instead on a low-level object (Brush). For more information of how to use WPF Performance Suite, please go to visit MSDN page linked here.

Make a trade-off between graphique's quality and performance

Unfortunately, today's computers are still not powerful enough to run perfectly WPF application. Especailly the computers cost less than 1,000 euros. Performance issue exists in our daily life. If we cannot have an WPF perfect application, we should at least have an usable application. If high graphique quality slowed down our application, we could make our application a little bit ugly for having a better performance. Esepcially your application is a financial real-time trading application, the most important objectif of your application should be robust and fast enough for refreshing real-time trades. In this case, the beauty of this app cannot help you earn more money. That's why all stock trades apps are so ugly? XD  Here discuss three way of tune graphique's quality for improving WPF performance

Disable Pixel Snapping and even Anti-Aliased option

As talked in the chapiter Pixel Snapping in WPF application, WPF uses several techniques for enriching graphic effect aimed at make an pretty and easy-readiing application. Because of all these techniques need to be calculated when GPU or CPU is rendering our application. It means GPU or CPU could render our application faster when we don't care about our application's visual artifacts.

For example, if we don't care text's lisibility, we could disable pixel snapping with set SnapsToDevicePixels property to false. Set this property to true on your root element allows you enable pixel snap rendering througout the UI. For devices operating at greated than 96 dots per inch (dpi), pixel snap rendering can minimize anti-aliasing visual artifacts in the vicinity of single-unit solid lines. When inherited by FrameworkElement or any possible derived classes, FrameworkElementoverrides the metadata for this dependency property to set the Inherits metadata property to true. What this achieves is that only the outermost element in a subtree needs to specifySnapsToDevicePixels as true, and all child elements of that subtree will then reportSnapsToDevicePixels as true and will have the SnapsToDevicePixels visual effect.

Anti-Aliased also could be changed to Aliased. But i'm not sure if WPF text rendering effect will be changed after disable anti-aliased option. Some articles on the internet disccused how it works in WPF application. In most of case (99%) of WPF applications, anti-aliased rendering should be kept because of lisibility of our application.

Make the trade-off between pixel snapping and non pixel snapping for your application. Personnally say, i prefer disable Pixel Snapping, because i didn't observe the big difference in my TreeListView with small font-size. But i'm not sure that if it will fastly make us feel tired without the best user experience.   

RenderOption

RenderOptions class provides options for controlling the rendering behavior of objects. You can use the attached properties of the RenderOptions class to specify options for the rendering of text and visual elements in your WPF application. These options enable you to optimize rendering for speed or quality.

BitmapScalingMode 

Use the BitmapScalingMode property on a UIElement or DrawingGroup descendant that is animating a bitmap. When animating the scale of any bitmap, the default high-quality image re-sampling algorithm can sometimes consume sufficient system resources to cause frame rate degradation, effectively causing animations to stuffer. By setting the BitMapScalingMode property to specify algorithm is used to scale bitmap images could improving your performance : 

  • BitMapScalingMode.Fant, Use very high quality Fant bitmap scaling, which is slower than all other bitmap scaling modes, but produces higher quality output.
  • BitMapScalingMode.HighQuality, Use high quality bitmap scaling, which is slower than LowQuality mode, but produces higher quality output. The HighQuality mode is the same as the Fant mode.
  • BitMapScalingMode.Linear, Use linear bitmap scaling, which is faster than HighQuality mode, but produces lower quality output.
  • BitMapScalingMode.LowQuality, Use bilinear bitmap scaling, which is faster than HighQuality mode, but produces lower quality output. The LowQuality mode is the sae as the Linear mode.
  • BitMapScalingMode.NearestNeighbor, Use nearest-neighbor bitmap scaling, which provides performance benefits over LowQuality mode when the software rasterizer is used (very useful in Remote Desktop). This mode is often used to magnify a bitmap.

ClearTypeHint

Use the ClearTypeHint attached property to indicate that text can be rendered with ClearType in a specific part of the visual tree. ClearType text doesn't display correctly on a background that is not fully opaque. Intermediate render targets, such as Effect, OpacityMask, VisualBrush, DrawingBrush, Clip, and Opacity, can introduce backgrounds that are not fully opaque. WPF disable ClearType when it detects that the buffer into which text is drawn could have a transparent background. Set the ClearTypeHint property to Enabled to indicate that a subtree is safe for ClearType text rendering. Do this only when you can be certain that the text is rendering to a fully opaque bakcground. When an element in the subtree introduces transparency, you can enable ClearType, however, rendering issues may occur. If a portion of the subtree introduces more intermediate rendering targets, you must set ClearTypeHint again on the children of that subtree.

What is ClearType? ClearType is a software technology developed by Microsoft that improves the readability of text on existing LCDs (Liquid Crystal Displays), such as laptop screens, Pocket PC screens and flat panel monitors. ClearType works by accessing the individual vertial color stripe elements in every pixel of an LCD screen. Before ClearType running on an LCD monitor, we can now display features of text as small as a fraction of a pixel in width. The extra resolution increases the sharpness of the tiny details in text display, making it much easier to read over long durations. The ClearType available in Windows Presentation Foundation (WPF) is the latest generation of ClearType which has several improveents over version found in Microsoft Windows Graphics Device Interface (GDI). [Ref]

I prefer set ClearTypeHint property always on Auto instead of Enable. Because ClearType in Windows Presentation Foundation (WPF) can take advantage of hardware acceleration for better performance and to reduce CPU load and system memory requirements. By using the pixel shaders and video memory of a graphics card. Unfortunately there's no GPU in our server machine! But maybe one day they will install a graphics card without tell me. 

PS : Disabling ClearType in Windows sets Windows Presentation Foundation (WPF) anti-aliasing to grayscale mode.

EdgeMode

Use the EdgeMode attached property to improve rendering performance by specifying that a visual object should be rendered with aliased edges. Text objects are always displayed with anti-aliasing, and are unaffected by setting the edge mode value. When you set the  edge mode value of a visual object, all the descendant drawing primitives of the visual object are set to the same edge mode value.

The image above illustrated a clear difference between after (Left) and before (Right) setting RenderOptions' properties. If cell template of a column In a TreeListView contains an Image and a TextBlock, setting RenderOptions as the left side in the picture above could have obviously an performance improvement. Conclusion, with setting RenderOptions's properties, you can make a fair-enough trade-off between quality and performance. 

Set the CacheMode property when you need to increase performance for content that is time consuming to render. BitmapCache inherited from CacheMode, it creates and caches a bitmap representation of a UIElement. Use the BitmapCache class to improve rendering performance of a complex UIElement. Create a BitmapCache and assign it to CacheMode property of a UIElement to cache the element and its subtree as a bitmap in video memory. This is useful when you need to animate, translate or scale a UIElement as quickly as possible. This approach enables a tradeoff between performance and visual quality while content is cached.

  • Set the RenderAtScale property to scale the bitmap cache. This is useful if an element will be zoomed, and you want the element to render more clearly than it would if the cache were simply generated at the element’s native resolution.
  • Set the SnapsToDevicePixels property when the cache displays content that requires pixel-alignment to render correctly, such as ClearType text. This property is ignored by theBitmapCacheBrush and Viewport2DVisual3D classes.

Caching a control does not affect mouse-over behavior, so mouse-over hit testing operates as if it the bitmap were a live control. Cache regeneration occurs only when the structure of the UIElement or its subtree changes, or when the CacheMode settings change. Setting the RenderAtScale or EnableClearType properties causes cache regeneration. Changes to the parent visual tree of the cached UIElement, such as transforms, scales, opacities, and effects, do not affect the cache.

The cache functions when hardware acceleration is not available. In this case, the bitmap is rendered in software, and the maximum bitmap dimensions are 2048 x 2048.

<!-- The following XAML creates a BitmapCache with default properties and assigns -->
<!-- it as the CacheM -->
<Canvas.CacheMode>
    <BitmapCache EnableClearType="False"
                 RenderAtScale="1"
                 SnapsToDevicePixels="False />
</Canvas.CacheMode>

PS: RenderOptions and TextOptions do not propagate through a cached element. You may have to set these options again in child elements below the cache.

Now we mentionned here 3 ways for increase WPF performance, both approach will decrease graphique quality. But sometimes we have to sacrifice one thing and earn another thing which is more important.

Make a trade-off between architecture and performance

Unfortunately once again. WPF or C# provided several ways for constructing a good loose-couple project's architecture. Especailly for WPF, seperating clearly View layer from other layers of the project is a welcome "design pattern". Most of us prefer each module has its own business. But sometimes, we couldn't have a perfect architecture with a perfect performance.

IValueConverter and IMultiValueConverter

We might have an object model class which is generated by Linq to Sql Classes. This class contains only properties who represent the definitions of a business, like Id of an product, adress of an product or price of a product. But in our presentation layer of the application, products's information are often showed in a GridView with several "decorations". One of these decorations could be charge of indicating the level of price of a product. Products cost more than 200 Euros could be considered like a very expensive one and then in the GridView, the background of row of this product could be rendered as the color Red. In this case, we use often an IValueConverter for drawing GridView's rows background for avoiding change Model layer class.

But IValueConverter or IMultiValueConverter causes often an performance issue. Mentionned in article Reflection for WPF Rockstars, IValueConverter is realized by Reflection. Just one IValueConverter doesn't cause a big performance issue. But using IValueConverter in a GridView could cause a performance issue, because each time we scroll the GridView, the rows will be redisplayed on the screen recall IValueConverter for redrawing its background. You could run your applications on debug mode for watching what will happen once you scroll your GridView which contains IValueConverters inside cell template. 

By the way, i'm not sure if IValueConverter used .Net reflection. But it truely needs to be rebinding when it was invoked and after it finished its job.

In most of case, i remove complicated IValueConverter and IMultiValueConverter from the TreeListViews which contains thousands of rows (also more than 20 columns). In this case, i've to redefine my model class with using inheritance or rewrite a new model class manually, then add color properties inside my new model class. It might not be a good solution, i'm glad to hear your opinion Smile | :)  

Improve scrolling performance in WPF

The performance issue i cared most was TreeListView scrolling issue,  a TreeListView with thousands upons thousands rows and more than 20 columns, could be unbearable because of the lags when it's been scrolling. I found an Microsoft article of year 2007 which talked scrolling performance bottlenecks and the solutions for these bottlenecks. You could download Scrolling_in_WPF.pdf. Here's the snapshot of an paragraphe in the document - Faster Databindings

Data binding is immensely useful and, when used properly, fairly fast. Before taking the time to work around using bindings, be sure to profile your application (see the "Resources" section) to ensure that it is indeed the bottleneck.

In this section, we'll assume that, on each scroll, your application is reevaluating a series of bindings as described in the preceding section. There are roughly two ways to get rid of this cost: Don't use data binding at all, or give the data-binding engine a little help.

Expected Performance Benefits

The expected benefits depend on which implementation you choose. It's possible to remove entirely the cost (25 percent) of data binding by just not using the feature. You can also choose to "help" the data-binding engine, which will remove about half of the data-binding cost.

Suggested Implementation

Removing Bindings

Getting rid of data binding is a sure way to get rid of that 25 percent bottleneck, but it isn't likely worth the cost; if you've chosen to use data binding, it is probably for a reason. You'll lose tons of great features, such as the use of DataTemplates, and you'll have to manage yourself all of the updates to data.

Because this implementation is highly application-dependent and fairly straightforward (although work-intensive), we won't discuss it further here.

Helping the Data-Binding Engine

The problem with our sample application is that, each time we scroll, we set the Content property on each container in the view to a new data item. This internally causes the ContentPresenter to update its DataContext property, which means that all of its bindings are now invalid. The data-binding engine here has no choice but to reactivate every BindingExpression; that is, it needs to attach it to the common language runtime (CLR) property in question, and transfer the value to the target DependencyProperty.

Both of these operations split the time roughly equally. There's nothing that we can do about transferring the value; if it changes, that has to happen. We can, however, avoid attaching the binding to the data object.

The trick here is always to keep the ContentPresenter pointed at the same object. To do so:

  • Create a proxy object that has the same properties as the data item.

    • It should hold on to an instance of the data item, and forward calls to the data item to its properties.

    • It should implement INotifyPropertyChanged.

    • Modify your DataTemplates to reference the proxy object, instead of the data item.

  • Have each container point to a proxy object, instead of a data item.

  • When scrolling, find each container's proxy object, and change its data item. If the proxy fires its PropertyChanged event, the bindings will be updated properly.

The ContainerListFastBinding.cs in the code sample shows how this can be done.

Performance Bottlenecks

As mentioned earlier, the binding optimization is expected to cut the cost of data binding in half for our target scenario. The numbers now look like the following:

Contribution (percent) Operation
34 Arranging (22 percent is TextBlock.OnRender)
26 Measuring (almost all TextBlock)
17 Rendering
11 Data binding (BindingExpression.TransferValue)

Table 3. Performance of recycling containers, and optimizing data binding

These are all mandatory operations. Although they look like large bottlenecks, it means that this implementation is about is fast is it will get. The sample application literally only displays TextBlocks; it should come as no surprise that almost all of the time is spent preparing and rendering them.

There is also a savings that is not captured in this table. By avoiding changing the Content property, we're also avoiding a tree walk on each container to update dependent children (because the property is inheritable). It's a relatively small cost, but it is still there.

WPF in remote desktop

With all solutions we talked above, in most of case, we now could have a perfect WPF application. It has a very fast performance with smooth graphics.  Because of MVVM design pattern and other .Net design pattern tool (like Unity), the WPF applications are often more robust than others. 

We tested and runned our application in our local machine, our boss and us were cheering for our great WPF application. We installed it on the server machine, we rerunned our wonderful application in our local machine once again, the application runned slowly even unusable!!! What happened! Is it because our server machine is too old and not powerful? Oh god, no, it's a super powerful machine. Then what happened? Why our application runs slowly in our server machine? This could be an explanation: 

Starting with the release of NET 3.5 SP1 (including NET 4), WPF renders the application content using a software rasterizer on the server and then remotes the content as bitmaps in all cases. Bitmaps are highly compressed by the uderlying RDC stack and only regions that changed are being updated. Also note that WPF does not currently have efficient occlusion support, so for instance animations that are completely hidden behind other opaque WPF elements will force invalidation and RDP update. 

When apps use GDI (such as many Win32 and Winforms apps do), only the GDI primitives are remoted. In many cases this can be more efficient than remoting WPF apps since WPF apps remotes bitmaps which typically result in more content being sent over the wire than a similar GDI-based app. The additional data may result in slower performance depending on network bandwidth and the size and frequency of updates.

However, in most scenarios, on reasonably fast connections, this is not an issue and in some scenarios (e.g. complex 3D scenes) remoting bitmaps can even present an advantage. Noticeable performance issues can appear in low bandwith situations and when there is significant amout of data that must be remoted. For example, fast scrolling text file, playing video, or lots of animations.

[Ref Optimizing Visual Studio 2010 and WPF applications for Remote Desktop]

Now, we could get a simple conclution for improving WPF in remote desktop performance : 
  • Use WPF performance suite (mentionned above) for detecting regions of your WPF app taht are un-intentionally being invalidated. E.g. Remove complicated UI element in the cell template of an TreeListView.
  • Reduce the size of bitmaps transfered between server and local machine. 
  • Find out the best trade-off between Graphic Quality and Performance.
  • Find a good system of remote connection, following the best Graphic Card and the application system. For example, Critrix has a better solution for WPF in its XenApp 7.x system
  • Tune your Remote Desktop Connection (RDC) settings. For example, tune "Choose file color depth of the remote session" in the Remot Desktop Connection's config panel.
  • Use lightweight drawing classes as what we'll discuss in the next chapiter Third-Party Library.
For more useful informations of improving WPF performance in remote desktop, here is un article i read - Optimizing Visual Studio 2010 and WPF applications for Remote Desktop 
 
With the acknowledge above, sometimes we could have a conclusion immediately when the performance of our application is not good on the remote server "The remote server is badly configured!". Actually, i didn't encounter any performance problem of running my application in a simple RDP (on windows8 et +). My experience told me that a default access of a RDP remote server should give us always a good user experience except the case of low bandwidth. But do the same thing in a viruatlizaed remote server is more complicated. It might give you a bad performance because of virtulization server's shortages. For example, Virutal Processor scheduling might be runned in a wrong way. Understand the strategy of your remote applications server could help you avoiding some performance issue. Here is a article about Virutal Processor Scheduling.   
 
Tips in case of inevitable of performance issue:
  • For large data TreeListView, you could set IsDefferedScrolling to True.

Third-Party Library

If you encountered some performance issue of your TreeListView or GridView, i strong recommend you that using third-party libraries instead of crying hidden behind your boss. There are many third-party libararies for WPF or Xaml/C#. I didn't try all of them, but they could help you to reduce your developement cycle and bring you a robust product. What i used often is DevExpress, it's not advertise here, but it has really helped me a lot. Here is a brief technical introduction about its DXGrid's Optimized Mode :

"Starting from version 14.1, the GridControl introduces optimized mode. It is enabled by default and provides a greatly improved scrolling performance and a reduced load time for hot starts after loading the first instance.

In-place Editing

In optimized mode GridControl uses the new DevExpress.Xpf.Editors.InplaceBaseEdit editor to display cells content. It is used for different column types - Text, ComboBox and even CheckBox columns. This is a special lightweight editor that does not have a default visual tree.

Setting in-place editors with the DataViewBase.CellTemplate property generates unoptimized editors. To use optimized editors, place a DevExpress.Xpf.Editors.InplaceBaseEdit editor with the Name property set to “PART_Editor” inside the cell template. With this approach, the editor settings are taken from the ColumnBase.EditSettings property of the GridColumn.

Since implicit editor styles do not work in optimized mode, either use a style for DevExpress.Xpf.Editors.InplaceBaseEdit or create the required editor using the DataViewBase.CellTemplate. To set a custom style for the editor in edit mode, use the EditCoreStyle property of DevExpress.Xpf.Editors.InplaceBaseEdit.

Row and Cell Resources

When the GridControl is in optimized mode, it uses special lightweight visual elements and templates. Thus, custom styles or resources that were working in previous versions may not work in 14.1 by default. To provide compatibility with older versions, set the TableView.UseLightweightTemplates property to None to enable the previous version of the visual tree. To migrate an application created in version 13.2 or older, rewrite the overridden resources for new visual elements. In the attachment there is a  table with the corresponding elements of both modes.

The following public styles require another target type in optimized mode.

For TableView.RowStyle, the target type is DevExpress.Xpf.Grid.RowControl.

For DataViewBase.CellStyle, the target type is DevExpress.Xpf.Grid.LightweightCellEditor.

The base style is as follows."  

Brief and Conclusion

In real life project, if you do it correctely, data binding doesn't cause a bad performance. So making your code urgly and difficult to maintain is not a good way.  If you could optimize style templates, you could have a obviously better performance. Use animations and rich graphic effect only when necessary. Applications running on remote server could have scrolling lags, but you should make sure that the lags are not caused by your WPF application itself.

References

Pixel Snapping in WPF Applications.

WPF Graphics Rendering Overview.

WPF Performance Suite.

RenderOptions

CacheMode and BitmapChache

Optimizing Visual Studio 2010 and WPF applications for Remote Desktop

Improve scrolling performance in WPF (.pdf file attached)

WPF in Visual Studio 2010 Performance tuning - wrote by Paul Harrington – Principal Developer, Visual Studio Platform Team 

History

Updated the chapiter WPF in remote desktop

-----------------------------------

Added chapiter Brief and Conclusion

-----------------------------

Added chapiter Improve scrolling performance in WPF

Added new references

------------------------------

Added chapter - Make a trade-off between architecture and performance. IValueConverter and IMultiValueConverter

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

comiscience
Software Developer (Senior) Exoé
France France
A foolish 18 years old boy
Just got an Microsoft C# Specialist Certification. Objectif of this year : MCSD

Comments and Discussions

 
QuestionBroken link, Pinmemberfredatcodeproject7-Jul-14 7:50 
AnswerRe: Broken link, Pinpremiumcomiscience7-Jul-14 9:06 
GeneralRe: Broken link, Pinmemberfredatcodeproject8-Jul-14 7:47 
GeneralRe: Broken link, Pinpremiumcomiscience8-Jul-14 20:25 
GeneralRe: Broken link, Pinmemberfredatcodeproject10-Jul-14 8:01 
GeneralRe: Broken link, Pinpremiumcomiscience10-Jul-14 8:39 
GeneralRe: Broken link, Pinmemberfredatcodeproject11-Jul-14 11:23 
GeneralRe: Broken link, Pinpremiumcomiscience11-Jul-14 23:53 
GeneralRe: Broken link, Pinmemberfredatcodeproject12-Jul-14 5:52 
GeneralRe: Broken link, Pinpremiumcomiscience9-Jul-14 22:41 
GeneralRe: Broken link, Pinmemberfredatcodeproject10-Jul-14 8:00 
QuestionAttachment PinmemberMember 36942827-Jun-14 6:48 
AnswerRe: Attachment Pinpremiumcomiscience27-Jun-14 22:44 
GeneralMy vote of 5 PinprofessionalManikandan1017-Jun-14 4:37 
GeneralGreat article comiscience! PinpremiumVolynsky Alex15-Jun-14 7:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 7 Jul 2014
Article Copyright 2014 by comiscience
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid