WPF Wonders: Properties and Events : Page 2

Setting properties and handling events in Windows Presentation Foundation are fundamentally different than they were in Windows Forms. Find out how to deal with properties and events in both XAML and WPF-targeted code.

by Rod Stephens

Jan 22, 2009

Page 2 of 4

Simple Properties
You can set a WPF object's properties using code at run time much as you set any other object's properties. To do that, simply build a value of the appropriate type and assign it to the property.

For example, the following C# code sets the Background property of the Grid control named grdMain to a solid yellow brush.

From a coding perspective, this all looks perfectly normal (after you figure out what kinds of objects serve what purposes), but from a XAML perspective it's a bit problematic. XAML files are text files: How do you set a property to an object such as a solid brush?

The answer is that WPF provides type converters that can translate certain textual values into objects for use with some properties. For example, the following XAML code sets the grdMain control's Background attribute to the string "Yellow." The type converter for the Background attribute automatically converts the string "Yellow" into a solid yellow brush and assigns it to the control's Background property:

<Grid Name="grdMain" Background="Yellow">
...
</Grid>

This technique, where you set a property's value in an XAML attribute, is called attribute syntax or property attribute syntax. It makes good intuitive sense and it's easy to use to set simple property values such as this one.

WPF provides many other type converters to turn textual attributes into values such as doubles, colors, point coordinates, enumerated values, and sometimes even arrays of numbers.

The various attributes set the object's StrokeThickness (a double, the line's thickness), Stroke (the line's color), Points (an array of coordinate pairs, which is converted into an array of Points), StrokeDashArray (an array of drawn and skipped lengths for dashed lines), and StrokeDashCap (an enumerated value that can be Flat, Square, Round, or Triangle, which determines how WPF draws the ends of dashes). Figure 2 shows the result.

Complex Properties
The simple properties you've seen are easy enough to use in XAML but how do you handle something more exotic? For example, suppose you want to use a radial gradient brush similar to the one shown in Figure 3 for a background.

Figure 3. Baffling Backgrounds: Setting the Background property to a radial gradient brush is easy at run time but messy in XAML code.

It's easy enough to specify this background in code at run time. The following C# code creates a GradientStopCollection to store the values where the gradient should reach different colors. It uses that collection to create a new RadialGradientBrush and then assigns it to the Grid's Background property.

As you can see, this example is a little more complicated than the earlier one that set the Grid's Background property to a solid yellow brush, but the idea's the same: You create an appropriate brush object and assign it to the Grid's Background property.

But how do you do this in XAML? The type converter for the Background attribute only handles simple solid brushes with names such as "Blue," "Pink," or "PapayaWhip." (Hey, I didn't name it!) You might be able to dream up a string-based syntax to let you specify radial gradient brushes, and have those convert to gradient brush objects at run time, but it would probably be pretty messy and hard to type correctly. You'd also probably want to handle linear gradient brushes and image brushes, as well as any properties that those objects have.

Building such a type converter is possible but Microsoft took a different approach. Instead of using a complex string converter, a XAML file can use property element syntax to represent properties that are themselves complex objects. Using this method, the property is represented as an XML element in the file.

To give a control such a property, don't use the property attribute syntax. Instead, after the control's start token, create an element whose name is a concatenation of the control type, and the property's name, separated by a period, for example, . Inside that element, put the definition of the object that you want to assign to the property.

The following XAML code gives the Grid grdMain the background shown in Figure 3. The element (containing a RadialGradientBrush in this example) defines the Background property for the Grid control: .

Because this technique uses a XAML element to describe the property's value, it is called property element syntax.

Attached Properties
Using property attribute syntax and property element syntax, you can assign either simple or complex values to an object's properties. XAML also includes a third kind of property, called an attached property. Classes provide an attached properties for use by other classes.

Author's Note: Attached properties are somewhat similar to the extender provider properties provided by Windows Forms components such as ErrorProvider, HelpProvider, and ToolTip. In Windows Forms, if you add a ToolTip named ToolTip1 to a form, every control on the form (and the form itself) magically acquires a "ToolTip on ToolTip1" property (courtesy of ToolTip1).

A common use of attached properties is for communication purposes—to allow a class's children to tell it something. For example, the Grid control can define rows and columns to hold controls. When you place an Image inside the Grid, you might want to set its Row and Column properties. But the Image control doesn't have those properties. (It would be silly to give every kind of control those properties on the off chance that it was placed inside a Grid.) To handle this problem, the Grid control defines Row and Column attached properties for the children it contains.

You can set attached property values by using property attribute syntax, where the name of the attached property is the name of the class that defines it, followed by a dot, followed by the property name. For example, the following code defines an Image control positioned in row 1 column 2 of its containing Grid.

<Image Grid.Row="1" Grid.Column="2" Source="Car.jpg" />

Figure 4 shows a Grid control containing nine Images, each with different Grid.Row and Grid.Column values.

Figure 4. Great Grid: The Grid.Row and Grid.Column attached properties determine each image's row and column.

Note that the Grid class defines Row and Column properties for a control whether or not it is contained in a Grid. The following XAML code defines a WrapPanel that contains an Image. The WrapPanel arranges its children in a single row, wrapping to a new row when necessary. The Grid.Row and Grid.Column properties don't really make sense to the WrapPanel so it simply ignores them (see Figure 5).