This article explains how to use WPF
DrawingContext api to create custom drawn elements. I have taken a simple example of a Horizontal Axis which can be reused in any chart control.
Most of the elements and controls in the WPF Standard Library such as
ComboBox for example are composed of multiple elements internally. If you inspect the visual tree of a
ComboBox, you will find that it contains a toggle button and a popup. It is a preferred method to create elements and controls by combining existing elements, but it might be an overkill in some cases. Large number of elements in a visual tree(or even small number of heavy elements) can cause the main element to become very heavy and consume more memory, thereby causing performance issues.
There is a solution to this problem and it involves letting the element take control of the rendering of its content by using
DrawingContext class. It is a very memory efficient way of building a composite element. It also simplifies the visual tree of the element and makes it lighter.
DrawingContext is a lightweight class which can be used to render rectangles, lines, text or any arbitrary geometric shapes. It can also be used to add visual effects to the rendered content. In this article, we will take the example of a horizontal axis line with labels and ticks as shown in figure below and see how we can build it using
Using the code
public class HorizontalAxis : FrameworkElement
private Pen mainPen = new Pen(Brushes.Black, 1.0);
private double startPoint = 0.0;
private double endPoint = 600.0;
protected override void OnRender(DrawingContext drawingContext)
drawingContext.DrawLine(mainPen, new Point(startPoint, ActualHeight / 2),
new Point(endPoint, ActualHeight / 2));
for (double i = 0.0; i <= endPoint; i++)
if (i % 50 == 0)
drawingContext.DrawLine(mainPen, new Point(i, ActualHeight / 2),
new Point(i, ActualHeight / 1.25));
FormattedText ft = new FormattedText(
new Typeface(new FontFamily("Segoe UI"),
drawingContext.DrawText(ft, new Point(i, ActualHeight / 1.2));
You can use the
HorizontalAxis component in your xaml file as shown below
<local:HorizontalAxis VerticalAlignment="Center" MinHeight="20"/>
As seen in the code above, I have created a custom component called
HorizontalAxis which inherits from
FrameworkElement class adds support for layouting, events, data binding and dynamic resources, styles and animation support to HorizontalAxis.
However, there is still the problem of drawing the horizontal line, ticks and labels. We can draw content by overriding the
OnRender method. The
OnRender method is an overridable method inherited from
UIElement which receives an object of type
DrawingContext as an argument. The
DrawingContext object contains useful methods to draw text and shapes(for eg.
DrawEllipse). In our case, we have used
DrawLine method draws a line between the specified points and
DrawText method draws text at the specified location.
In order to draw the ticks, we can simply draw small vertical lines which are equally spaced apart by 50 pixels. Each such vertical line has text drawn below it.
You can see the following output on the screen.
Note that when you use these commands to draw content, you are actually storing a set of render data that will be later used by the graphics system to render the content. The content is not being drawn to the screen in real time.
We can also add blur effects or any kind of effects for that matter. Just call the
PushEffect method and pass in the effect that you want as an input argument. In order to stop the effect being applied to subsequent drawings, call