Accessing a static property from XAML
XAML provides an easy way to set values of properties—type converters and the extended property syntax allow for flexible setting of values. However, some things cannot be expressed as a simple value, such as setting a property to the value of some static property.
Getting ready
Make sure Visual Studio is up and running.
How to do it...
We'll create an application that uses a static property from within XAML:
Create a new WPF Application named
CH01.StaticProperties
.Open
MainWindow.xaml
. Replace theGrid
element with aStackPanel
.Add some shapes as shown in the following code block:
<StackPanel> <Ellipse Stroke="Black" Height="50" /> <Rectangle Stroke="Black" Height="50" /> </StackPanel>
Suppose we want to fill the ellipse with the desktop color selected by the user in Windows. WPF provides the
SystemColors
class, with many static properties that return aBrush
representing the user's choice. For the desktop, this is aDesktopBrush
property. We can try the following:<Ellipse Stroke="Black" Height="50" Fill="SystemColors.DesktopBrush" />
This throws an exception at runtime, as it cannot be converted to any "known" color (such as Red or Blue). To access a static property, we must use the
{x:Static}
markup extension, as follows:<Ellipse Stroke="Black" Height="50" Fill="{x:Static SystemColors.DesktopBrush}" />
This works. You can verify this by going to Control Panel, then selecting Personalization (on Windows 7 or 8).
Select Window Color (switch to the classic theme first if the following window is shown differently). The Window Color and Appearance dialog is displayed:
Change the desktop color and run the application again. You should see the ellipse filled with the new color.
Similarly, let's fill the rectangle with the active window caption color:
<Rectangle Stroke="Black" Height="50" Fill="{x:Static SystemColors.ActiveCaptionBrush}"/>
Running the application shows something like the following:
In this case, the active caption color on my system is a gradient, so the
ActiveCaptionBrush
provides the left side. The right side is provided by theGradientActiveCaptionBrush
property. They are both brushes. If we wanted to recreate the caption gradient within the rectangle, we would need color objects, not brushes. Fortunately, these are provided via properties in the same class, namedActiveCaptionColor
andGradientActiveCaptionColor
. Let's combine these in aLinearGradientBrush
:<Rectangle Stroke="Black" Height="50"> <Rectangle.Fill> <LinearGradientBrush EndPoint="1,0"> <GradientStop Offset="0" Color="{x:Static SystemColors.ActiveCaptionColor}" /> <GradientStop Offset="1" Color="{x:Static SystemColors.GradientActiveCaptionColor}" /> </LinearGradientBrush> </Rectangle.Fill> </Rectangle>
This is the final result:
How it works...
XAML basically has very few capabilities. It can create objects, set values for properties, and set up event handlers. This is intentional, as XAML is declarative in nature. It cannot, for instance, call methods. That would make it closer to an imperative language (such as C#), which would make its existence dubious at best.
Sometimes, however, declarative operations require more than setting up properties. A method may be involved, or some other unusual construct, but the intent may still be declarative. This is where markup extensions come in. They provide a way to extend XAML with new (hopefully declarative) capabilities.
A markup extension is a class that derives from System.Windows.Markup.MarkupExtension
and implements a single method, ProvideValue
. In this example we have used the {x:Static}
markup extension, which allows accessing any static property (whether it belongs to WPF or not; if not, a XAML namespace mapping is required as explained in the recipe Creating custom type instances in XAML in this chapter). {x:Static}
is implemented by the System.Windows.Markup.StaticExtension
class. Note that if the markup extension class ends with "Extension" we can remove it when referring to it in XAML – the XAML compiler will search with and without the word "Extension". This means {x:Static}
can be written {x:StaticExtension}
. In fact, most markup extensions end with "Extension" (a notable exception is the Binding
markup extension).
There's more...
There are other built in markup extensions. Here are some of the simplest:
{x:Null}
specifies the null reference{x:Type SomeType}
is the equivalent to thetypeof(SomeType
) operator in C#
We'll look at other markup extensions in subsequent chapters.