Composing a XAML Clip Art Scene

The Creating XAML Drawing Images with Graphic Designer posting showed how you could create DrawingImage objects that could be used as resources by a WPF application. In this posting, we'll look at composing a layered XAML clip art scene using definitions in the ResourceDictionary object of the XAML file.

At the bottom of this posting, you can find an attached XAML file containing the clip art scene (FerryScene.xaml).

Layering the Scene
The FerryScene.xaml file is a XAML animation that contains the following major drawing elements, five of which are animated:

Ferry Scene

In order for this scene to be composed correctly, all the major drawing elements must be layered order to the z-order. This means, for example, that the ferry must be closer to the foreground than the water. The FerryScene.xaml file shows an implicit z-order layering of the collection of objects in the Canvas definition -- each object is higher in the z-order (or closer to the foreground) than the preceding objects in the collection:

<

Viewbox VerticalAlignment="Top">
<Canvas Height="600" Width="1024">

    <!-- Sky and Water -->
<StackPanel ... />

    <!-- Clouds -->
<Image Canvas.Top='100' Canvas.Left='100' ... />

    <!-- Freighter -->
<Image Canvas.Top='270' Height="35" ... />

    <!-- WPF Banner -->
<TextBlock Canvas.Top ='410' FontSize='22' ... />

    <!-- Ramp -->
<Rectangle Width="4" Height="60" Margin="12,0,0,5" ... />

    <!-- Ferry Dock -->
<Image Canvas.Top='375' Height="88" ... />

    <!-- Ferry -->
<Image Canvas.Top='333' Height="120" ... />

  </Canvas>
</Viewbox>

Referencing Resources
The FerryScene.xaml file contains a number of references to drawing object resources. For example, the cloud drawing in the ferry scene references a DrawingImage that has been defined within the ResourceDictionary object of the outer-most StackPanel. The x:Key value, Clouds, is used to reference the drawing:

<

StackPanel.Resources>
<ResourceDictionary>
...
<DrawingImage x:Key="Clouds">
<DrawingImage.Drawing ... />
</DrawingImage>
...
</ResourceDictionary>
</StackPanel.Resources>

Once the drawing object is stored as a resource, it can be used by other UI elements, such as the Image object in the following lines:

<!--

Clouds -->
<Image
Canvas.Top='100'
Canvas.Left='100'
Height="80"
Source="{StaticResource Clouds}" >

The Source property uses a StaticResource reference, using the x:Key value of the DrawingImage. The Canvas.Top and Canvas.Left properties allow you to position the drawing precisely at the desired location. When you set the Height property, the referenced drawing image is automatically scaled in height. The width is also scaled in order to preserve the aspect ratio of the original drawing.

Resources Referencing Other Resources
In XAML, you can define a resource than can be used by another resource. The FerryScene.xaml file defines a LinearGradientBrush resource, whose x:Key value is set to CloudBrush. This brush resource is used by the three GeometryDrawing objects that define the cloud drawings:

<

StackPanel.Resources>
<ResourceDictionary>

<LinearGradientBrush x:Key="CloudBrush"
StartPoint="0,0.5" EndPoint="1,0.5">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#FFA8B1C2" Offset="0"/>
<GradientStop Color="#FFF0F0F0" Offset="0.619141"/>
<GradientStop Color="#FFE0E7F5" Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>

    <DrawingImage x:Key="Clouds">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="{StaticResource CloudBrush}" ... />
            <GeometryDrawing
Brush="{StaticResource CloudBrush}" ... />
            <GeometryDrawing
Brush="{StaticResource CloudBrush}" ... />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>

  </ResourceDictionary>
</StackPanel.Resources>

Defining resources, such as brushes and pens that can be re-used, is a useful technique is for reducing the size of XAML content.

Using a Viewbox to Scale Content
Notice that all the drawing objects that comprise the ferry scene are contained within a Canvas object, which is itself contained within a Viewbox object:

<

Viewbox>
<Canvas Height="600" Width="1024" ... />
</Viewbox>

A Viewbox allows the content of a single child object to stretch and scale to fill the available space of the hosting container of the XAML content. In this case, the child object is a Canvas containing all the major drawing elements of the animated scene. The two key properties of the Viewbox object are Stretch and StretchDirection.

The Stretch property describes how content should be resized to fill its allocated space. The default value is Uniform, which means to resize the content to fit in the destination dimensions of the hosting container -- this preserves the aspect ratio of all the drawing objects in the scene.

The StretchDirection property determines how scaling is applied to the contents of a Viewbox. The default value is Both, which means the content stretches to fit the hosting container according to the Stretch mode.

The end result of using the Viewbox is that if you resize the window containing the ferry scene, the drawing content is resized and rescaled appropriately. When you run the The FerryScene.xaml file, try resizing the browser window and see what happens.

Ferry Scene in a Viewbox

A Few Comments on the XAML
In most cases, a XAML application like this would define the ResourceDictionary objects in a separate XAML file. But I wanted to see if it were possible to create a complex drawing scene in a single XAML file. It is!

The drawing content resources are not as optimized as I would like them to be. For example, I ended up hand-optimizing the cloud definitions so that they share a linear gradient brush that I defined as a resource. I'll continue to experiment with different techniques for creating complex XAML clip art scenes.

Have fun,
Lorin

About Us


We are the Windows Presentation Foundation SDK writers and editors.

FerryScene.xaml