Lightweight Drawing with DrawingVisuals: Part 1 of 2

Because of WPF’s layout system, designing User Interfaces has become a much more creative, organic and powerful process. However, all this power comes at a price: it is easy to adversely affect rendering performance by making complex layouts. In this post I will explain why, and how using DrawingVisuals are one way to prevent such performance bottlenecks.

Let’s take a step back and learn how layout and rendering works in WPF. In WPF there is the concept of Logical and Visual Trees. A Logical Tree can be thought of as representing the encapsulated elements contained within the Window. So for example, if you had this Window described with XAML:

<Window>
<Grid>
<Button />
<Label />
</Grid>
</Window>

The window’s Logical Tree would basically be the Grid, with the Button and Label as its children. Visual Trees are usually more complicated though. A Visual Tree can be thought of as all the visual elements that compose an element. So looking at the previous example, the Button could actually be composed as a Border that contains a Grid which contains a TextBlock, which in turn is composed of more visual elements. And the Label could be composed of one or more visual elements. What this means is WPF separates an element’s behavior from its appearance, and allows developers to easily style controls.

Developers should be mindful of the number of elements in the Visual Tree. In WPF, every object that has rendering derives from the Visual abstract class, which contains all the low-level infrastructure for said rendering. Although objects like Buttons, Rectangles, Labels etc. ultimately derive from Visual, they also derive from FrameworkElement. FrameworkElement contains support for layout, input, data binding, routed events, dependency properties, and animations. Because of this, there is overhead when creating objects that derive from FrameworkElement. Now, if you had a large and complex visual tree with each element being an instance of that class, the overhead in creating and rendering these elements becomes noticeable.

For example, I was working on a window that contained a ListBox that was bound to a collection of objects. Each ListBoxItem was rendered with a custom style that ended up being over 30 elements! Needless to say, that window had a complex Visual Tree. Using Perforator, I discovered that the Window’s Dirty Rect Addition rate (or the rate at which each UI element was being generated) was in the single digits, which is very low.

To tap-dance around this, I performed custom drawing with DrawingVisuals. DrawingVisuals derive directly from Visuals and contain support to add lightweight visuals without the overhead that FrameworkElements carry. They also have support for simple input in the form of Visual Hit Testing. Since DrawingVisuals do not contain the overhead that FrameworkElements carry, you could theoretically have hundreds of Visuals in a WPF app without significantly impacting performance, assuming your hardware is relatively current.

wpf-class-hierarchy.png
By using DrawingVisuals to style each capture in the History bin, we were able to increase the rate that each capture was generated by a factor of ~4-5. In the next part, I will show you how to make custom visuals with DrawingVisuals.

Explore posts in the same categories: WPF

Tags: , , , , , ,

You can comment below, or link to this permanent URL from your own site.

One Comment on “Lightweight Drawing with DrawingVisuals: Part 1 of 2”


  1. Very Interesting. Have you considered how animations can be applied to drawing objects within the visuals?

    Rob

    http://www.robsword.net


Comment:

You must be logged in to post a comment.