Where Have All the XAML Flowers Gone?
April 5, 2006
New York City
Wherever I go, people ask me "Charles, when are you going to write a XAML version of the famous Flower program that has been delighting generations of programmers since it first appeared in OS/2 Presentation Manager Programming (1994)?"
Flower.xaml is now here, and it's a "mini-language" extravaganza.
As some of you might know, XAML once had several "mini-languages" that allowed you to cut down some XAML flab with simple (but cryptic) text strings. The mini-languages for gradient brushes and transforms have been removed. (As many of us have suspected, it's because Microsoft has decided that XAML is for tools rather than hand-coding — a horrifying attitude that means to turn us all into drag-and-drop automatons and which I am totally ignoring in my book. I'm teaching XAML, not how to get repetitive stress injuries.)
The two mini-languages left are for attributes of type Geometry (documented in Path.Data) and Transform (documented I don't know where but which simply consists of the six variable cells of Matrix). I use both of them in my XAML flower program, listed here:
-
<!-- =========================================
Flower.xaml (c) 2006 by Charles Petzold
========================================= -->
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="White">
<Viewbox>
<!-- Canvas is 200 units square with Cartesian coordinates -->
<Canvas Width="200" Height="200"
RenderTransform="1 0 0 -1 100 100" >
<Canvas.Resources>
<!-- Style to avoid too much repetition in petals -->
<Style TargetType="{x:Type Path}" x:Key="petal">
<Setter Property="Stroke" Value="Black" />
<Setter Property="Fill" Value="Red" />
<Setter Property="Data"
Value="M 0 0 C 12.5 12.5, 47.5 12.5, 60 0
C 47.5 -12.5, 12.5 -12.5, 0 0 Z" />
</Style>
</Canvas.Resources>
<!-- The green stem -->
<Path Stroke="Green" StrokeThickness="5"
Data="M -100 -100 C -100 -50, -50 50, 0 0">
</Path>
<!-- 8 Petals, many of them rotated. -->
<Path Style="{StaticResource petal}" />
<Path Style="{StaticResource petal}"
RenderTransform=".7 -.7 .7 .7 0 0" />
<Path Style="{StaticResource petal}"
RenderTransform="0 -1 1 0 0 0" />
<Path Style="{StaticResource petal}"
RenderTransform="-.7 -.7 .7 -.7 0 0" />
<Path Style="{StaticResource petal}"
RenderTransform="-1 0 0 -1 0 0" />
<Path Style="{StaticResource petal}"
RenderTransform="-.7 .7 -.7 -.7 0 0" />
<Path Style="{StaticResource petal}"
RenderTransform="0 1 -1 0 0 0" />
<Path Style="{StaticResource petal}"
RenderTransform=".7 .7 -.7 .7 0 0" />
<!-- Put yellow circle in center to attract bees -->
<Path Fill="Yellow" Stroke="Black">
<Path.Data>
<EllipseGeometry Center="0 0"
RadiusX="15" RadiusY="15" />
</Path.Data>
</Path>
</Canvas>
</Viewbox>
</Page>
Graphics transforms are a bit odd in WPF. Mostly you apply transforms directly to elements (such as controls or graphical shapes). This causes them to translated, scaled, skewed, or rotated relative to their pre-transform selves. By default, rotation is relative not to the origin of the drawing surface, but to the origin of the element.
You can also apply a transform to a Canvas, as is done here. The 200-square unit Canvas is flipped horizontally and shifted to give me a four-quadrant Cartesian coordinate system with 100 units in all four directions. If you give the Canvas a non-default Background you'll see that it's rendered mostly outside the drawing area, but because it's been subjected to a RenderTransform rather than a LayoutTransform, everybody — and particularly the Viewbox — is under the mistaken impression that it still occupies its original location.