Title: Render an ellipse in a WPF program using C#
This example shows how you can render an ellipse in a WPF program. Normally to draw shapes in WPF you use some sort of object. If you add Ellipse, Line, Path, Polygon, Polyline, and Rectangle objects to a window, those shapes redraw themselves when necessary.
However, sometimes you may want to draw on a window at runtime without creating those kinds of objects. WPF programs don't provide a Paint event the way Windows Forms applications do, so that's not where you put your code. Instead you should override the window's (or other control's) OnRender method. That method provides a DrawingContext parameter named drawingContext that you can use to draw (much as a Paint event handler provides a Graphics object that you can use to draw). Drawing inside the OnRender method is reasonably simple, although there are a couple of gotchas.
First, if you're drawing on the window, you need to set the window's Background property to Transparent. If you don't, then the window seems to draw its background after the OnRender method is called so whatever you drawn doesn't appear.
Second, I have yet to figure out a good way to determine the size of the window's client area--its area without borders, title bar, menu, and so forth. Fortunately that's easy enough to work around. Just get the size of the window's main content object, which by default is a Grid control. To make that easy, in this example I set the main Grid control's Name property to grdMain. Then the code can just use grdMain.ActualWidth and grdMain.ActualHeight to get the client area's dimensions.
The following code shows how the program draws an ellipse whenever the form is rendered.
protected override void OnRender(DrawingContext drawingContext)
{
// Clear the background.
Rect bg_rect = new Rect(0, 0,
this.ActualWidth, this.ActualHeight);
drawingContext.DrawRectangle(Brushes.White, null, bg_rect);
// Make the pen to outline the ellipse.
const double pen_width = 5;
Pen pen = new Pen(Brushes.Blue, pen_width);
// Get the center of the content Grid control.
double center_x = grdMain.ActualWidth / 2;
double center_y = grdMain.ActualHeight / 2;
Point center = new Point(center_x, center_y);
// Subtract half the width of the pen from
// the center to get radius_x and radius_y
// so the ellipse just touches the sides of the form.
double radius_x = center_x - pen_width / 2;
double radius_y = center_y - pen_width / 2;
// Draw the ellipse.
drawingContext.DrawEllipse(Brushes.LightBlue,
pen, center, radius_x, radius_y);
}
First the code draws a white rectangle on the window to clear its background. It then creates a blue pen. Notice that in WPF you pass the Pen constructor a Brush not simply a color. This is because WPF fills lines instead of just drawing them. That seems odd if you're using one pixel wide lines to draw shapes, but WPF drawings are scalable. If you zoom in on a drawing, lines become thicker and then you might be able to see a shading or pattern in the line's brush. (This still seems a bit odd to me. Lots of programs draw solid lines. It's strange that WPF provides standard solid brushes but not standard solid lines.)
Note also that WPF's Pen class does not have a Dispose method so you cannot dispose pens or create them in using statements.
After it builds its pen, the program calculates the center of the client area. It subtracts half of the pen's width/height from the client area's width/height so the ellipse will just touch the window's edges. The program finishes by using the DrawingContext object's DrawEllipse method to draw the ellipse.
Aside from the gotchas, it's not much harder than rendering in a Windows Forms program's Paint event.
Download the example to experiment with it and to see additional details.
|