A XAML processor is defined as any program that can accept XAML as an
input language and can produce the resulting underlying classes for use by a
run-time object model.
By default, such a processor will either interpret an attribute value as a
literal string or convert it to an object on the basis of the type of the
attribute or the type converters specific to that attribute. However, there are
occasionally scenarios where different behavior is required. For instance, a
XAML processor can be instructed that a value of an attribute should instead be
a reference to an already constructed object or a static object.
A markup extension can be implemented to provide values for properties in an attribute usage, or in a property-element usage, or both. When used to provide an attribute value, the syntax requires the use of '{' and '}'. The type of markup extension is then identified by the string token immediately following the opening curly brace. The following example shows markup extension attribute usage to set a value for TargetType attribute:
<Style x:Key="MyButtonStyle" TargetType="{x:Type Button}">
Recall that property-element syntax assigns other object elements to be the value of a property. Instead of the property being specified as an attribute within the element tag, the property is specified using an opening element tag in elementTypeName.propertyName form, the value of the property is specified, and then the property element is closed. For example, the following is property element syntax for the ContextMenu property of a Button.
<!-- Cannot do something like
<Button Content="Right Click Me!" ContextMenu="??"> So we need to use
property-element syntax as shown below -->
<Button Content="Right Click Me!">
<Button.ContextMenu>
<ContextMenu>
<MenuItem
Header="1">First item</MenuItem>
<MenuItem
Header="2">Second item</MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
In WPF, the most common markup extensions are those that support resource references and data bindings such as StaticResource, DynamicResource and Binding. For example, the following shows how to set the Background color of a Border to a Brush that is defined within the application resources:
<Border x:Name="Border" Background="{StaticResource NormalBrush}"
The following is a brief overview of WPF-specific markup extensions (please refer to the given chapter for detailed information):
StaticResource provides a value for a XAML property by substituting the value of an already defined resource. See example above.
DynamicResource is the same as StaticResource except that the lookup is performed at runtime. A dynamic resource reference forces a new lookup each time that such a resource is accessed. See ControlTemplates chapter.
Binding provides a data-bound value for a property, per the data context that applies to the element. See DataBinding chapter.
RelativeSource provides source information for a Binding that can navigate several possible relationships in the run-time element tree. This provides specialized sourcing for bindings that are created in multi-use templates or created in code without full knowledge of the surrounding element tree. See DataBinding chapter.
TemplateBinding enables a ControlTemplate to use values for templated properties that come from object-model-defined properties of the class that will use the template. See ControlTemplates chapter.
An example is given below for each:
<Border x:Name="Border" Background="{DynamicResource NormalBrush}"
<Button Background="{Binding RelativeSource={RelativeSource self}, Path=Content}" Content="Red" Content="Red"/>
<ScrollBar Name="PART_HorizontalScrollBar" Maximum="{TemplateBinding ScrollableWidth}" />
There are also several markup extensions that are not specific to WPF but a part of XMAL as a language. These are typically identified by the x: prefix. The following is a brief overview of these markup extensions:
x:Type supplies the Type object for the named type. This is used most frequently in styles and templates.
x:Static produces static values from value-type code entities that are not directly the type of a property's value, but can be evaluated to that type.
x:Null specifies null as a value for a XAML property.
x:Array provides support for creation of general arrays in XAML syntax, for cases where the collection support provided by base elements and control models is deliberately not used.
The following example shows how to use x:Static but also shows that multiple markup extensions can be nested, with the deepest markup extension evaluated first:
<Button Content="My Button" Background={DynamicResource {x:Static SystemColors.ControlBrushKey}} ... />
Note that all markup extensions derive from MarkupExtension class and provide an implementation of MarkupExtension.ProvideValue method.
Data binding as a concept is described in DataBinding chapter. This section is meant to present Binding as a XAML syntax.
Binding provides a data-bound value for a property. The basic syntax is:
<object property={Binding bindingProp1=value1, bindingProp2=value2, ...} ... />
<object>
<object.property>
<Binding bindingPropertyName1="value"
bindingPropertyName2="value" bindingPropertyNameN="value"/>
</object.property>
</object>
For example:
<Button Background="{Binding Source={StaticResource myDataSource}, Path=ColorName}" />
<Button>
<Button.Background>
<Binding Source={StaticResource myDataSource},
Path=ColorName />
</Button.Background>
</Button>
You can set zero or more of the properties in the list below using property=value pairs separated by commas (as previously shown above):
ConverterCulture
ConverterParameter
NotifyOnSourceUpdated, NotifyOnTargetUpdated, NotifyOnValidationError
Resources as a concept are described under Resources in Styles & Resources chapter. This section is meant to present Resources as a XAML syntax.
StaticResource provides a value for any XAML property attribute by looking up a reference to an already defined resource. Lookup behavior for that resource is analogous to load-time lookup, which will look for resources that were previously loaded from the markup of the current XAML page as well as other application sources, and will generate that resource value as the property value in the run-time objects. XAML attribute usage is:
<object property="{StaticResource key}" .../>
Where key key was initially assigned by the x:Key Attribute. For example:
<Style x:Key="MyStyle">
<Setter Property="Control.Background" Value="Green" />
</Style>
<!--
The above style is associated with an element as follows: -->
<Button Style="{StaticResource
MyStyle}" Content="Click Me"/>
Resources as a concept are described under Resources in Styles & Resources chapter. This section is meant to present Resources as a XAML syntax.
DynamicReosurce provides a value for any XAML property attribute by deferring that value to be a reference to a defined resource. Lookup behavior for that resource is analogous to run-time lookup. XAML attribute usage is:
<object property="{DynamicResource key}" .../>
Where key key was initially assigned by the x:Key Attribute. A DynamicResource will create a temporary expression during the initial compilation and thus defer lookup for resources until the requested resource value is actually required in order to construct an object.
For example:
<Style x:Key="MyStyle">
<Setter Property="Control.Background" Value="Green" />
</Style>
<!--
The above style is associated with an element as follows: -->
<Button Style="{DynamicResource
MyStyle}" Content="Click Me"/>
TemplateBinding is used with ControlTemplate which is described in ControlTemplates section. This section is meant to present TemplateBinding as a XAML syntax.
TemplateBinding is XAML markup extension whose purpose is to create a binding between the value of a property in a template and the value of some other exposed property on the templated control:
<object property="{TemplateBinding Property=targetProperty}" .../>
where targetProperty is a dependency property that exists on the type being templated. Using a TemplateBinding is equivalent to using a Binding with the Source property set to RelativeSource.TemplatedParent. For example, the following binding:
<ScrollBar Name="PART_HorizontalScrollBar" Maximum="{TemplateBinding ScrollableWidth}" />
indicates that the Maximum property which sets the highest possible Value of the range element of the ScrollBar should be synchronized with the Maximum value that is set on the horizontal scrollbar
When you set an attribute value in XAML, the initial type of that value is String. Even other primitives such as Double are initially Strings to a XAML processor. In order to process the attribute value, XAML needs to know the type of the property that is being set. Any string that defines an attribute value and that is processed in XAML must ultimately be converted or resolved to a value of that type. If the value is a primitive, a direct conversion of the string is attempted. If the value is an enumeration, the string is used to check for a name match in that enumeration. If the value is neither a primitive or an enumeration, then the type in question must be able to provide an instance of the type, or a value, based on a converted string.
If the value is not a primitive type or enum, and there is no markup extension usage, then there must be some means of converting a String to the appropriate value. This is the role of the TypeConverter implementation. TypeConverter defines four members that are relevant for converting to and from strings for XAML processing purposes:
CanConvertTo
CanConvertFrom
ConvertTo
ConvertFrom
Of these, the most important method is ConvertFrom. This method converts the input string to the required object type.
Assume you have a Point class and a Line class containing two Point objects as following:
public class Point
{
protected double x;
protected double y;
public double X
{
get {return x;}
set {x = value;}
}
public double Y
{
get {return y;}
set {y = value;}
}
}
public class Line
{
protected Point pt1;
protected Point pt2
public Point FirstPoint
{
get {return pt1;}
set {pt1 = value;}
}
public Point SecondPoint
{
get {return pt2;}
set {pt2 = value;}
}
}
If you make Line a XAML custom class (i.e., a class that can be used in XAML) and you did not specify an associated TypeCoverter, you would have to use Line using property-element syntax:
<Line>
<Line.FirstPoint>
<Point X="0" Y="0"/>
<Line.FirstPoint>
<Line.SecondPoint>
<Point X=10" Y="10"/>
<Line.SecondPoint>
</Line>
When a TypeConverter is specified, you can use attributes to specify values for Point objects:
<Line FirstPoint="0,0" SecondPoint="10, 10"/>
The following shows how to create and use a TypeConverer:
public class PointTypeConverter :
TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext
context, Type t)
{
return (t == typeof(String));
}
public override object ConvertFrom(ITypeDescriptorContext
context,
System.Globalization.CultureInfo culture,
object val)
{
// Get data
string[] params = ((string)val).Split(',');
// Create and
initialize a Point object
Point pt = new Point();
pt.X = Convert.ToDouble(parms[0]);
pt.Y = Convert.ToDouble(parms[1]);
return pt;
}
}
[TypeConverter(typeof(PointTypeConverter))]
public class Point
{
protected double x;
protected double y;
public double X
{
get {return x;}
set {x = value;}
}
public double Y
{
get {return y;}
set {y = value;}
}
}