48

In case a screen of a WPF application contains lots of primitive controls, its rendering becomes sluggish. What are the recommended ways to improve the responsiveness of a WPF application in such a case, apart from adding fewer controls and using more powerful videocard?

Is there a way to somehow use offscreen buffering or something like that?

rem
  • 16,745
  • 37
  • 112
  • 180
  • Can you give some numbers? Number of controls per window etc. – NVM Mar 23 '11 at 17:32
  • @NVM Practically, now it's about one thousand custom controls per window (the custom control consists of several borders, textblocks and has about a couple of dozen dependency properties). The number of controls can grow. But already this quantity takes some uncomfortable number of seconds to visualize itself on inital rendering. Additionally it doesn't provide nice smooth scrolling when zoomed up. – rem Mar 23 '11 at 17:53
  • I am finding it difficult to visualize a UI with a thousand text boxes all at the same time in front of the user. Anyway, depending on how everything is arranged you could either use one of the built in virtualizing panels or write your own custom one which will only create the controls that are visible. That should speed up things significantly. – NVM Mar 23 '11 at 20:37
  • @NVM Thanks for pointing out the potential usefulness of virtualizing panels. I'm not sure it'll fit my particular case due to a specific layout of my elements, but nevertheless I'll take attention on this. – rem Mar 23 '11 at 21:12
  • You probably should open a new and more specific question for your app. Screenshots would also help. I dont think any general optimization answers are going to help you with this. – NVM Mar 23 '11 at 21:24
  • Perfomance is crappy for layered/transparent windows in WPF. This is the most common problem with UI rendering. http://blogs.msdn.com/b/dwayneneed/archive/2008/09/08/transparent-windows-in-wpf.aspx For general perfomance optimization guidelines see this: http://msdn.microsoft.com/en-us/library/aa970683.aspx – NVM Mar 23 '11 at 06:40

4 Answers4

53

Our team was faced with problems of rendering performance. In our case we have about 400 transport units and we should render chart of every unit with a lot of details (text labels, special marks, different geometries etc.).

In first our implementations we splitted each chart into primitives and composed whole unit's chart via Binding. It was very sad expirience. UI reaction was extremely slow.

So we decided to create one UI element per each unit, and render chart with DrawingContext. Although this was much better in performance aspect, we spent about one month improving rendering.

Some advices:

  1. Cache everything. Brushes, Colors, Geometries, Formatted Texts, Glyphs. (For example we have two classes: RenderTools and TextCache. Rendering process of each unit addresses to shared instance of both classes. So if two charts have the same text, its preparation is executed just once.)
  2. Freeze Freezable, if you are planning to use it for a long time. Especially geometries. Complex unfreezed geometries execute HitTest extremely slow.
  3. Choose the fastest ways of rendering of each primitive. For example, there is about 6 ways of text rendering, but the fastest is DrawingContext.DrawGlyphs.
  4. Use profiler to discover hot spots. For example, in our project we had geometries cache and rendered appropriate of them on demand. It seemed to be, that no improvements are possible. But one day we thought what if we will render geometries one time and cache ready visuals? In our case such approach happened acceptable. Our unit's chart has just several states. When data of chart is changed, we rebuild DrawingVisual for each state and put them into cache.

Of course, this way needs some investments, it's dull and boring work, but result is awesome.

By the way: when we turned on WPF caching option (you could find link in answers), our app hung up.

Alex Zhevzhik
  • 3,347
  • 19
  • 19
  • I realize that this post is a bit old, but I'm wondering what methods you utilized to cache the brushes, colors, and whatnot. I feel like I could possibly avoid some lag if I knew how to do this. – red_sky Jun 18 '12 at 17:17
  • 6
    [Here](http://pastebin.com/v83XZLTc) I uploaded simplified version of my RenderTools object. And [here](http://pastebin.com/e8VhuHez) is usage example. If you still have questions feel free to ask. – Alex Zhevzhik Jun 21 '12 at 14:33
13

I've had the same perf issue with a heavily customized datagrid since one year, and My conclusion is:

there is basically nothing you can do on your side (without affecting your app, i.e.: having fewer controls or using only default styles)

The link mentioned by Jens is great but useless in your case.

The "Optimizing WPF Application Performance" link provided by NVM is almost equally useless in my experience: it just appeals to common sense and I am confident you won't learn anything extraordinary either reading. Except one thing maybe: I must say this link taught me to put as much as I can in my app's resources. Because WPF does not reinstanciate anything you put in resource, it simply reuses the same resource over and over. So put as much as you can in there (styles, brushes, templates, fonts...)

all in all, there is simply no way to make things go faster in WPF just by checking an option or turning off an other. You can just pray MS rework their rendering layer in the near future to optimize it and in the meantime, try to reduce your need for effects, customized controls and so on...

David
  • 6,014
  • 4
  • 39
  • 55
3

Have a look at the new (.NET 4.0) caching option. (See here.)

Jens
  • 25,229
  • 9
  • 75
  • 117
1

I have met a similar problem and want to share my thoughts and founds. The original problem is caused by a virtualized list box that displays about 25 complex controls (a grid with a text block and a few buttons inside displaying some paths ) To research the issue I used the VisualStudio Application Timeline that allows to how much time it takes to render each control and PerfView to find out what actually WPF is doing to render each control. By default it took about 12ms to render each item. It is rather long if you need to update the list dynamically. It is difficult to use PerfView to analyse what heppens inside since WPF renders item in the parent-child hierarchy, but I got the common understanding about internall processes. WPF does following to render each item in the list:

  1. Parse template using XAML reader. As far as I can see the XAML parsing is the biggest issue.
  2. Apply styles
  3. Apply bindings

It does not take a lot of time to apply styles and bindings.

I did following to improve performance:

  1. Each button has its own template and it takes a lot of time to render it. I replaced Buttons with Borders. It takes about 4-5ms to render each item after that.
  2. Move all element settings to styles. About 3ms.
  3. Create a custom item control with a single grid in the template. I create all child elements in code and apply styles using TryFindResources method. About 2ms in the result.

After all these changes, performance looks fine but still most time is spent on loding the ListControl.Item template and the custom control template. 4. The last step: replace a ListControl with Canvas and Scrollbar controls. Now all items are created at runtime and position is calculated manually using the MeasureOverride and ArrangeOverride methods. Now it takes <1ms to render each item from which 0.5ms is spent on TextBlock rendering.

I still use styles and bindings since they do not affect performance a lot when data is changed. You can imagine that this is not a WPF solution. But I fave a few similar lists in the application and it is possible not to use templates at all.

Drreamer
  • 332
  • 1
  • 10