Recently, I updated my Timer App to version 2. And, one feature I added was a whiteboard. Letting your user draw a picture is cool. It’s also quite useful if they need to express a thousand words quickly. Anyway, I wrote it and thought, “this is easy!”. So, I thought I would share the technique.
Understanding pointer events
There are several input devices supported by Windows 8. In fact, it’s because Windows supports the Pen (stylus) that I think it beats every other platform. There’s no better inking platform than Windows, but that’s not the point of this article. Other than the Pen, there’s touch (finger), and, of course, the mouse.
Pointer events are the roll-up of all those input mechanisms into a single, consistent event model. Where MouseDown is for the Mouse, PointerPressed is for whatever device the user is exercising. Pointer events make supporting multiple input types seamless.
MSDN: Touch, mouse, and pen/stylus interactions are received, processed, and managed as pointer input in Windows Store apps. Any of these interactions can produce a PointerPressed event. For more info, see Quickstart: Pointers.
PointerRoutedEventArgs expose GetCurrentPoint(element). This returns a PointerPoint (a funny name for an object) relative to the element supplied. This is useful for understanding the pointer position when the event occurred. It can also tell you which button is pressed, if any. In this demo, you will see me use it frequently. (twice)
Understanding XAML paths
Since we are drawing, we need to draw something and put it somewhere. We’ll use the XAML Canvas control to contain all our drawings (or lines). This is a textbook example of why the Canvas exists. For us, the Canvas will simply hold and present the lines our user draws (and we subsequently create).
MSDN: A Canvas is one of the Panel elements that enable layout. Canvas uses absolute positioning as its layout technique for its contained child elements. Each child element is rendered within the Canvas area. You control the positioning of elements inside the Canvas by specifying x and y coordinates. These coordinates are in pixels. The x and y coordinates are often specified by using the Canvas.Left and Canvas.Top attached properties. Canvas.Left specifies the object's distance from the left side of the containing Canvas (the x-coordinate), and Canvas.Top specifies the object's distance from the top of the containing Canvas (the y-coordinate).
In this demo we use the Path control. A path can draw far more than just a line – but we’re only going to use it for a single line. To that end, a Path is only interesting to us when we consider its Data property – where we enumerate the points along which the path will be drawn on the screen.
In the image above, we can see the basic implementation of Path. But we will do everything in code-behind. To accomplish this, we set Data to a new instance of PathGeometry. This exposes a Figures collection into which we add a single PathFigure instance. This, then, exposes a Segments collection into which we add a single PolyLineSegment instance. This provides us a Points collection into which we can add points to build out our line. It’s that simple ;).
In the code above, we initialize our path. The Data property is set to a PathGeometry, into whose Figures collection is added a PathFigure, into whose Segments collection is added a PolyLineSegment. This will provide us with the Points collection into which we can (later) add points that correspond to the moving (drawing) of the user’s mouse/pen/finger. I know I said this part twice now, but it’s the most complex part of the demo and I want to be clear.
Let’s built it!
In the video above, I build out the demo. I’m not trying to make it look too simple, but the reality is. It’s pretty simple once you know what to do. You can get all the code here.
Best of luck!