A path consists of several painting instructions: moving the virtual “pen” to a certain position, drawing certain shapes, and ending the drawing. Every instruction starts with a (case-insensitive) letter that identifies the instruction and several parameters may follow.
Figure 4-6. The rectangle with the rounded corners
The first part of a path is the so-called fill rule. This takes care of a special case: what happens if elements in the path overlap. You may choose between the default value F0 and F1:
F0
Stands for EvenOdd, meaning that points that have an even number of path segments between them and the end of the canvas are considered outside the path; points with an odd number are considered inside and would be filled.
F1
Stands for NonZero, meaning that all points where a line between the point and the end of the canvas crosses the path from the left side as often as from the right side are considered inside the path.
Generally, EvenOdd is what you will want, and since it is the default value, you do not have to provide it at all.
Next up are the instructions. The first one is usually M, which stands for “move.” This moves the virtual pen to a certain position but does not start drawing. The following path would put the pen at the x coordinate 40 and the y coordinate 30:
M 40,30
Starting from that point, several shapes are possible. We will start once again with a line, denoted by the L command. You only have to provide the end point of the line―the starting point is defined by the current pen position! The following path would therefore draw a line from (40,30) to (70,80):
M 40,30 L 70,80
Special cases of lines are horizontal lines (H command) and vertical lines (V command). For horizontal lines you only need to provide the x coordinate of the end point; for vertical lines you only need to provide the y coordinate of the end point.
By using lines, you can create any geometric shape that does not have curves. For curves, however, several options exits. The A command draws an elliptical arc. You need to provide a set of parameters:
The x and y radius of the ellipsis
The rotation angle of the ellipsis (use degrees)
Whether the angle is larger than 180 degrees (1) or not (0)
Whether the arc is drawn in positive direction (1) or not (0)
The end point of the arc
The following markup would create an arc from (50,50) to (100,50), using an x and y radius of 75 each, with a 90 degrees rotation angle in positive direction:
M 50,50 A 50,50 90 0 1 100,50
A type of curve that is very common in the vector graphics field are Bézier curves, named after French automobile designer Pierre Bézier. Assume that you have two points, A and B. Bézier defined a couple of mathematical equations that define curves between those points. The easiest one is a linear curve, but they are easy to draw without any extra help from Silverlight. However, there are more complex variants. A quadratic Bézier curve (called that because in the defining formula values are squared) uses a so-called control point to shape the exact look of the curve. The associated Silverlight path command, Q, provides the coordinates of this control point and also of the end point; remember that the start point is again defined by the current position of the pen.
The following markup moves the pen to (125,125) and creates a Bézier curve to (175, 75), using (110, 60) as a control point:
M 125,125 Q 110,60 175,75
A cubic Bézier curve goes one step further and uses two control points. The associated SIlverlight path command is C. Here is an example: the curve goes from (150,125) to (50,100), using the two control points (125,175) and (20,125).
There are more advanced Bézier curves available, as well: They take the previous point of the curve into account, making the curve look more smooth. For “smooth,” sister of the quadratic Bézier curve uses the S command, and the “smooth” cubic Bézier curve uses T. The syntax is the same as with the Q and C commands.
One final command is missing, it is called Z and closes a path, meaning that the pen draws a straight line to the beginning of the path.
Example 4-8 shows several of the previous path commands in action. In Figure 4-7,working clockwise, you can see a straight line (red), an elliptic arc (yellow) to the right of the straight line, a quadratic Bézier curve (green) to the right of the arc, and a cubic Bézier (blue) curve. The control points for the Bézier curves have been marked with an X so you can see which points the curves are approaching. These markers have been also created using a path (drawing two crossing lines).
Example 4-8. Using Paths, the XAML file (Path.xaml)
<Path Data="M 125,75 Q 200,100 175,125" Stroke="Green" StrokeThickness="5" /> <Path Data="M 195,95 L 205,105 M 205,95 L 195,105" Stroke="Black" StrokeThickness="2" />
<Path Data="M 150,125 C 125,175 20,125 50,100" Stroke="Blue" StrokeThickness="5" /> <Path Data="M 120,170 L 130,180 M 130,170 L 120,180" Stroke="Black" StrokeThickness="2" /> <Path Data="M 15,120 L 25,130 M 25,120 L 15,130" Stroke="Black" StrokeThickness="2" />
</Canvas>
As mentioned at the beginning of this section, creating a path manually can be painful, so you should use a graphics software for that. However, you can now analyze and understand paths that are created by vector graphic programs.
If you have used SVG before, this path syntax will be very similar to what you are used to. Most vector formats use the same features for their paths, so the syntaxes are very alike.
Figure 4-7. Various paths
One more shape should not be forgotten: An ellipse, represented by the <Ellipse> element. The most important attributes are Width and Height, defining the size of the ellipse. Example 4-9 shows such an ellipse, and Figure 4-8 has the browser output.
Example 4-9. Using an Ellipse, the XAML file (Ellipse.xaml)
When the ellipse has the same width and height, you get―a circle.
Geometry Elements
An alternative approach to drawing shapes is to use a so-called geometry element. It can be compared to shapes (there are lines, rectangles, paths, etc.), but this element doesn't draw itself. Instead, it can be used within other elements defining how they look. For instance, the Clip property of an UI object can be set to a geometry element defining a path. This path then defines the outer border of the UI object. Or, you could use a geometry element as the Data property of a <Path> element, and, therefore, provide the layout of the path.
Figure 4-8. The ellipse
There are several geometry elements, including EllipseGeometry, LineGeometry, Path Geometry, and RectangleGeometry. The following is an example that clips an image by using a path (later, Example 4-16 will show a different approach to reach the sameeffect):
If you don’t specify the position of an element, it is positioned at the origin (0, 0) of the display area. You can try this out yourself: Create a Silverlight XAML file and put some <TextBlock> elements on it. The text contents within those elements will overlap, since all text is displayed with the top left corner at (0, 0).
This can be changed for most elements by setting their Canvas.Top and Canvas.Left properties. These properties denote the x and y coordinate of the element, respectively.
The following text block would be shown 50 pixels to the right, 100 pixels to the bottom:
The clue is that all elements within the canvas are positioned relative to the surrounding canvas. Have a look at Example 4-10, for instance. It contains several canvases, eachhave (except for the outer one) Canvas.Top="50" and Canvas.Top="50". Inside the innermost <Canvas> element resides a <TextBlock> element with Canvas.Left="50" and Canvas.Top="50" as well. Each of those indentations always refer to the parent canvas and are no absolute coordinates. Therefore, each canvas starts 50 pixels to the right and 50 pixels to the bottom from where its parent canvas starts. The Canvas.Left and Canvas.Top properties are also called dependency properties: they depend on their parent <Canvas> element. Likewise, <Canvas> elements may be called dependency objects. Figure 4-9shows the browser output.
Example 4-10. Nested, positioned canvases in the XAML file (Canvas.xaml)
Only <Canvas> elements that have a fixed width and height show their background color. If you omit this information, the background remains the default, which in our example is white.
Of course these canvases overlap each other. Silverlight uses the following approach: All elements are stacked onto each other, so there is a (virtual) third dimension. Therefore, the text from Example 4-10 resides on top of all canvases, since this element comeslast in the document. This is the reason why the text can be seen at all. In CSS, there
Figure 4-9.The nested canvases
is a property called z-index that assigns the “z coordinate” of an element: the higher the value, the further up on the stack it is.
Silverlight uses the same principle. You may assign a z-index by setting the Canvas.ZIn dex property. Note that you can also nest z-index values; however, these values are only compared on the same element level. Assume that you have a canvas with z-index 3 that contains two rectangles with z-index 2 and z-index 1. The rectangle with the higher z-index is placed above the one with the lower z-index. However, the outer canvas will not overlap the rectangles, although its z-index is higher.
Example 4-11 is a variation of Example 4-10: everything except the outer canvas isgone, but we added rectangles. Usually they would overlap similar to Figure 4-9, butthis time we set Canvas.ZIndex so that the “inner” elements have a lower z-index. Therefore, the first rectangle is drawn over the second one, the second one is drawn over the third one, and so on. The lowest z-index is assigned to the text block. This text block is now overlapped by the blue rectangle. Therefore, the text itself is not visible, as Figure 4-10shows.
Example 4-11. Setting the z-index, the XAML file (ZIndex.xaml)