Page 3 of 3
Drawing using Shapes
As well as rendering buttons and other controls we can also use the standard WPF UIElement graphics classes, i.e. Shapes, to effectively draw on the bitmap. The sequence of steps is exactly the same as for the button. First we create the Shape:
Ellipse circle = new Ellipse();
Then we initialise it:
circle.Height = 100;
circle.Width = 100;
circle.Stroke = Brushes.Black;
circle.StrokeThickness = 1.0;
Finally we call Measure, Arrange and UpdateLayout:
circle.Measure(new Size(200, 200));
new Rect(new Size(200, 200)));
Again the size of the specified available areas just has to be bigger than the Visual object being measured and arranged.
It is also arguable that the BeginInit, EndInit calls are unnecessary for graphic Visuals and the call to Measure and UpdateLayout don't seemed to be essential - however the call to Arrange is critical.
We can also create a line to add to the circle:
Line line = new Line();
line.X1 = 60;
line.Y1 = 100;
line.X2 = 100;
line.Y2 = 20;
line.Stroke = Brushes.Magenta;
line.StrokeThickness = 1;
line.Measure(new Size(200, 200));
Rect(new Size(200, 200)));
and finally we can render both to the bitmap.
What is on top of what depends on the order of drawing - so in this case the line overlays the circle.
In a real application you would be well advised to write some general methods to render a UIElement without repeating all of the steps each time. However, if you want to draw on a bitmap you might like to use a completely different approach.
DrawingVisual is directly descended from Visual and not UIElement. Visual objects don't have the mechanisms to take part in the layout system - this is added at the UIElement level. What this means is that if you work with something closer to the Visual class, such as DrawingVisual, you can avoid the problems with the layout system altogether.
The only problem is that this involves using yet another part of the WPF system - drawing. The easiest way to see how this all works is by way of a simple example.
First we need a DrawingVisual:
DrawingVisual DV = new DrawingVisual();
From this we create a DrawingContext:
DrawingContext DC = DV.RenderOpen();
Now we can start to draw using vector drawing methods:
new Point(50, 50), 20, 20);
new Point(20,5),new Point(70,60));
Notice that we have to close the DrawingContext before making any use of it. Also notice that DrawingVisual is a vector graphic - it simply stores a list of drawing instructions.
Finally we can render the DrawingVisual to the RenderTargetBitmap and this converts the drawing instructions into pixels:
There is no need to worry about calling Measure or Arrange as the DrawingVisual doesn't take part in the layout system.
Of course you can render DrawingVisuals, UIElements and any other objects descended from Visual using the same RenderTargetBitmap and generally create a bitmap from a range of sources.