WPF 고급 - 아키텍처, XAML 프로그래밍/WPF2016. 9. 23. 04:40
고급
https://msdn.microsoft.com/ko-kr/library/ms746927(v=vs.110).aspx
WPF 아키텍처
This topic provides a guided tour of the Windows Presentation Foundation (WPF) class hierarchy. It covers most of the major subsystems of WPF, and describes how they interact. It also details some of the choices made by the architects of WPF.
The primary WPF programming model is exposed through managed code. Early in the design phase of WPF there were a number of debates about where the line should be drawn between the managed components of the system and the unmanaged ones. The CLR provides a number of features that make development more productive and robust (including memory management, error handling, common type system, etc.) but they come at a cost.
The major components of WPF are illustrated in the figure below. The red sections of the diagram (PresentationFramework, PresentationCore, and milcore) are the major code portions of WPF. Of these, only one is an unmanaged component – milcore. Milcore is written in unmanaged code in order to enable tight integration with DirectX. All display in WPF is done through the DirectX engine, allowing for efficient hardware and software rendering. WPF also required fine control over memory and execution. The composition engine in milcore is extremely performance sensitive, and required giving up many advantages of the CLR to gain performance.
Communication between the managed and unmanaged portions of WPF is discussed later in this topic. The remainder of the managed programming model is described below.
Most objects in WPF derive from DispatcherObject, which provides the basic constructs for dealing with concurrency and threading. WPF is based on a messaging system implemented by the dispatcher. This works much like the familiar Win32 message pump; in fact, the WPF dispatcher uses User32 messages for performing cross thread calls.
There are really two core concepts to understand when discussing concurrency in WPF – the dispatcher and thread affinity.
During the design phase of WPF, the goal was to move to a single thread of execution, but a non-thread "affinitized" model. Thread affinity happens when a component uses the identity of the executing thread to store some type of state. The most common form of this is to use the thread local store (TLS) to store state. Thread affinity requires that each logical thread of execution be owned by only one physical thread in the operating system, which can become memory intensive. In the end, WPF’s threading model was kept in sync with the existing User32 threading model of single threaded execution with thread affinity. The primary reason for this was interoperability – systems like OLE 2.0, the clipboard, and Internet Explorer all require single thread affinity (STA) execution.
Given that you have objects with STA threading, you need a way to communicate between threads, and validate that you are on the correct thread. Herein lies the role of the dispatcher. The dispatcher is a basic message dispatching system, with multiple prioritized queues. Examples of messages include raw input notifications (mouse moved), framework functions (layout), or user commands (execute this method). By deriving from DispatcherObject, you create a CLR object that has STA behavior, and will be given a pointer to a dispatcher at creation time.
One of the primary architectural philosophies used in building WPF was a preference for properties over methods or events. Properties are declarative and allow you to more easily specify intent instead of action. This also supported a model driven, or data driven, system for displaying user interface content. This philosophy had the intended effect of creating more properties that you could bind to, in order to better control the behavior of an application.
In order to have more of the system driven by properties, a richer property system than what the CLR provides was needed. A simple example of this richness is change notifications. In order to enable two way binding, you need both sides of the bind to support change notification. In order to have behavior tied to property values, you need to be notified when the property value changes. The Microsoft .NET Framework has an interface, INotifyPropertyChange, which allows an object to publish change notifications, however it is optional.
WPF provides a richer property system, derived from the DependencyObject type. The property system is truly a "dependency" property system in that it tracks dependencies between property expressions and automatically revalidates property values when dependencies change. For example, if you have a property that inherits (like FontSize), the system is automatically updated if the property changes on a parent of an element that inherits the value.
The foundation of the WPF property system is the concept of a property expression. In this first release of WPF, the property expression system is closed, and the expressions are all provided as part of the framework. Expressions are why the property system doesn’t have data binding, styling, or inheritance hard coded, but rather provided by later layers within the framework.
The property system also provides for sparse storage of property values. Because objects can have dozens (if not hundreds) of properties, and most of the values are in their default state (inherited, set by styles, etc.), not every instance of an object needs to have the full weight of every property defined on it.
The final new feature of the property system is the notion of attached properties. WPF elements are built on the principle of composition and component reuse. It is often the case that some containing element (like a Grid layout element) needs additional data on child elements to control its behavior (like the Row/Column information). Instead of associating all of these properties with every element, any object is allowed to provide property definitions for any other object. This is similar to the "expando" features of JavaScript.
With a system defined, the next step is getting pixels drawn to the screen. The Visual class provides for building a tree of visual objects, each optionally containing drawing instructions and metadata about how to render those instructions (clipping, transformation, etc.). Visual is designed to be extremely lightweight and flexible, so most of the features have no public API exposure and rely heavily on protected callback functions.
Visual is really the entry point to the WPF composition system. Visual is the point of connection between these two subsystems, the managed API and the unmanaged milcore.
WPF displays data by traversing the unmanaged data structures managed by the milcore. These structures, called composition nodes, represent a hierarchical display tree with rendering instructions at each node. This tree, illustrated on the right hand side of the figure below, is only accessible through a messaging protocol.
When programming WPF, you create Visual elements, and derived types, which internally communicate to the composition tree through this messaging protocol. Each Visual in WPF may create one, none, or several composition nodes.
There is a very important architectural detail to notice here – the entire tree of visuals and drawing instructions is cached. In graphics terms, WPF uses a retained rendering system. This enables the system to repaint at high refresh rates without the composition system blocking on callbacks to user code. This helps prevent the appearance of an unresponsive application.
Another important detail that isn’t really noticeable in the diagram is how the system actually performs composition.
In User32 and GDI, the system works on an immediate mode clipping system. When a component needs to be rendered, the system establishes a clipping bounds outside of which the component isn’t allowed to touch the pixels, and then the component is asked to paint pixels in that box. This system works very well in memory constrained systems because when something changes you only have to touch the affected component – no two components ever contribute to the color of a single pixel.
WPF uses a "painter's algorithm" painting model. This means that instead of clipping each component, each component is asked to render from the back to the front of the display. This allows each component to paint over the previous component's display. The advantage of this model is that you can have complex, partially transparent shapes. With today’s modern graphics hardware, this model is relatively fast (which wasn’t the case when User32/ GDI were created).
As mentioned previously, a core philosophy of WPF is to move to a more declarative, "property centric" model of programming. In the visual system, this shows up in a couple of interesting places.
First, if you think about the retained mode graphic system, this is really moving away from an imperative DrawLine/DrawLine type model, to a data oriented model – new Line()/new Line(). This move to data driven rendering allows complex operations on the drawing instructions to be expressed using properties. The types deriving from Drawing are effectively the object model for rendering.
Second, if you evaluate the animation system, you'll see that it is almost completely declarative. Instead of requiring a developer to compute the next location, or next color, you can express animations as a set of properties on an animation object. These animations can then express the intent of the developer or designer (move this button from here to there in 5 seconds), and the system can determine the most efficient way to accomplish that.
UIElement defines core subsystems including Layout, Input, and Events.
Layout is a core concept in WPF. In many systems there is either a fixed set of layout models (HTML supports three models for layout; flow, absolute, and tables) or no model for layout (User32 really only supports absolute positioning). WPF started with the assumption that developers and designers wanted a flexible, extensible layout model, which could be driven by property values rather than imperative logic. At the UIElement level, the basic contract for layout is introduced – a two phase model with Measure and Arrange passes.
Measure allows a component to determine how much size it would like to take. This is a separate phase from Arrange because there are many situations where a parent element will ask a child to measure several times to determine its optimal position and size. The fact that parent elements ask child elements to measure demonstrates another key philosophy of WPF – size to content. All controls in WPF support the ability to size to the natural size of their content. This makes localization much easier, and allows for dynamic layout of elements as things resize. TheArrange phase allows a parent to position and determine the final size of each child.
A lot of time is often spent talking about the output side of WPF – Visual and related objects. However there is a tremendous amount of innovation on the input side as well. Probably the most fundamental change in the input model for WPF is the consistent model by which input events are routed through the system.
Input originates as a signal on a kernel mode device driver and gets routed to the correct process and thread through an intricate process involving the Windows kernel and User32. Once the User32 message corresponding to the input is routed to WPF, it is converted into a WPF raw input message and sent to the dispatcher. WPF allows for raw input events to be converted to multiple actual events, enabling features like "MouseEnter" to be implemented at a low level of the system with guaranteed delivery.
Each input event is converted to at least two events – a "preview" event and the actual event. All events in WPF have a notion of routing through the element tree. Events are said to "bubble" if they traverse from a target up the tree to the root, and are said to "tunnel" if that start at the root and traverse down to a target. Input preview events tunnel, enabling any element in the tree an opportunity to filter or take action on the event. The regular (non-preview) events then bubble from the target up to the root.
This split between the tunnel and bubble phase makes implementation of features like keyboard accelerators work in a consistent fashion in a composite world. In User32 you would implement keyboard accelerators by having a single global table containing all the accelerators you wanted to support (Ctrl+N mapping to "New"). In the dispatcher for your application you would call TranslateAccelerator which would sniff the input messages in User32 and determine if any matched a registered accelerator. In WPF this wouldn’t work because the system is fully "composable" – any element can handle and use any keyboard accelerator. Having this two phase model for input allows components to implement their own "TranslateAccelerator".
To take this one step further, UIElement also introduces the notion of CommandBindings. The WPF command system allows developers to define functionality in terms of a command end point – something that implements ICommand. Command bindings enable an element to define a mapping between an input gesture (Ctrl+N) and a command (New). Both the input gestures and command definitions are extensible, and can be wired together at usage time. This makes it trivial, for example, to allow an end user to customize the key bindings that they want to use within an application.
To this point in the topic, "core" features of WPF – features implemented in the PresentationCore assembly, have been the focus. When building WPF, a clean separation between foundational pieces (like the contract for layout with Measure and Arrange) and framework pieces (like the implementation of a specific layout like Grid) was the desired outcome. The goal was to provide an extensibility point low in the stack that would allow external developers to create their own frameworks if needed.
FrameworkElement can be looked at in two different ways. It introduces a set of policies and customizations on the subsystems introduced in lower layers of WPF. It also introduces a set of new subsystems.
The primary policy introduced by FrameworkElement is around application layout. FrameworkElement builds on the basic layout contract introduced by UIElement and adds the notion of a layout "slot" that makes it easier for layout authors to have a consistent set of property driven layout semantics. Properties like HorizontalAlignment, VerticalAlignment, MinWidth, and Margin (to name a few) give all components derived from FrameworkElement consistent behavior inside of layout containers.
FrameworkElement also provides easier API exposure to many features found in the core layers of WPF. For example, FrameworkElementprovides direct access to animation through the BeginStoryboard method. A Storyboard provides a way to script multiple animations against a set of properties.
The two most critical things that FrameworkElement introduces are data binding and styles.
The data binding subsystem in WPF should be relatively familiar to anyone that has used Windows Forms or ASP.NET for creating an application user interface (UI). In each of these systems, there is a simple way to express that you want one or more properties from a given element to be bound to a piece of data. WPF has full support for property binding, transformation, and list binding.
One of the most interesting features of data binding in WPF is the introduction of data templates. Data templates allow you to declaratively specify how a piece of data should be visualized. Instead of creating a custom user interface that can be bound to data, you can instead turn the problem around and let the data determine the display that will be created.
Styling is really a lightweight form of data binding. Using styling you can bind a set of properties from a shared definition to one or more instances of an element. Styles get applied to an element either by explicit reference (by setting the Style property) or implicitly by associating a style with the CLR type of the element.
Control’s most significant feature is templating. If you think about WPF’s composition system as a retained mode rendering system, templating allows a control to describe its rendering in a parameterized, declarative manner. A ControlTemplate is really nothing more than a script to create a set of child elements, with bindings to properties offered by the control.
Control provides a set of stock properties, Foreground, Background, Padding, to name a few, which template authors can then use to customize the display of a control. The implementation of a control provides a data model and interaction model. The interaction model defines a set of commands (like Close for a window) and bindings to input gestures (like clicking the red X in the upper corner of the window).The data model provides a set of properties to either customize the interaction model or customize the display (determined by the template).
This split between the data model (properties), interaction model (commands and events), and display model (templates) enables complete customization of a control’s look and behavior.
A common aspect of the data model of controls is the content model. If you look at a control like Button, you will see that it has a property named "Content" of type Object. In Windows Forms and ASP.NET, this property would typically be a string – however that limits the type of content you can put in a button. Content for a button can either be a simple string, a complex data object, or an entire element tree. In the case of a data object, the data template is used to construct a display.
WPF is designed to allow you to create dynamic, data driven presentation systems. Every part of the system is designed to create objects through property sets that drive behavior. Data binding is a fundamental part of the system, and is integrated at every layer.
Traditional applications create a display and then bind to some data. In WPF, everything about the control, every aspect of the display, is generated by some type of data binding. The text found inside a button is displayed by creating a composed control inside of the button and binding its display to the button’s content property.
When you begin developing WPF based applications, it should feel very familiar. You can set properties, use objects, and data bind in much the same way that you can using Windows Forms or ASP.NET. With a deeper investigation into the architecture of WPF, you'll find that the possibility exists for creating much richer applications that fundamentally treat data as the core driver of the application.
XAML Overview (WPF)
This topic describes the features of the XAML language and demonstrates how you can use XAML to write Windows Presentation Foundation (WPF) applications. This topic specifically describes XAML as implemented by WPF. XAML itself is a larger language concept than WPF.
What is XAML?
XAML is a declarative markup language. As applied to the .NET Framework programming model, XAML simplifies creating a UI for a .NET Framework application. You can create visible UI elements in the declarative XAML markup, and then separate the UI definition from the run-time logic by using code-behind files, joined to the markup through partial class definitions. XAML directly represents the instantiation of objects in a specific set of backing types defined in assemblies. This is unlike most other markup languages, which are typically an interpreted language without such a direct tie to a backing type system. XAML enables a workflow where separate parties can work on the UI and the logic of an application, using potentially different tools.
When represented as text, XAML files are XML files that generally have the .xaml extension. The files can be encoded by any XML encoding, but encoding as UTF-8 is typical.
The following example shows how you might create a button as part of a UI. This example is just intended to give you a flavor of how XAML represents common UI programming metaphors (it is not a complete sample).
<StackPanel><Button Content="Click Me"/> </StackPanel>
XAML Syntax in Brief
The following sections explain the basic forms of XAML syntax, and give a short markup example. These sections are not intended to provide complete information about each syntax form, such as how these are represented in the backing type system. For more information about the specifics of XAML syntax for each of the syntax forms introduced in this topic, see XAML Syntax In Detail.
Much of the material in the next few sections will be elementary to you, if you have previous familiarity with the XML language. This is a consequence of one of the basic design principles of XAML. XAML The XAML language defines concepts of its own, but these concepts work within the XML language and markup form.
XAML Object Elements
An object element typically declares an instance of a type. That type is defined in the assemblies that provide the backing types for a technology that uses XAML as a language.
Object element syntax always starts with an opening angle bracket (<). This is followed by the name of the type where you want to create an instance. (The name can possibly include a prefix, a concept that will be explained later.) After this, you can optionally declare attributes on the object element. To complete the object element tag, end with a closing angle bracket (>). You can instead use a self-closing form that does not have any content, by completing the tag with a forward slash and closing angle bracket in succession (/>). For example, look at the previously shown markup snippet again:
This specifies two object elements: <StackPanel> (with content, and a closing tag later), and <Button .../> (the self-closing form, with several attributes). The object elements StackPanel and Button each map to the name of a class that is defined by WPF and is part of the WPF assemblies. When you specify an object element tag, you create an instruction for XAML processing to create a new instance. Each instance is created by calling the default constructor of the underlying type when parsing and loading the XAML.
Attribute Syntax (Properties)
Properties of an object can often be expressed as attributes of the object element. An attribute syntax names the property that is being set in attribute syntax, followed by the assignment operator (=). The value of an attribute is always specified as a string that is contained within quotation marks.
Attribute syntax is the most streamlined property setting syntax and is the most intuitive syntax to use for developers who have used markup languages in the past. For example, the following markup creates a button that has red text and a blue background in addition to display text specified as Content.
<Button Background="Blue" Foreground="Red" Content="This is a button"/>
Property Element Syntax
For some properties of an object element, attribute syntax is not possible, because the object or information necessary to provide the property value cannot be adequately expressed within the quotation mark and string restrictions of attribute syntax. For these cases, a different syntax known as property element syntax can be used.
The syntax for the property element start tag is <typeName.propertyName>. Generally, the content of that tag is an object element of the type that the property takes as its value . After specifying content, you must close the property element with an end tag. The syntax for the end tag is</typeName.propertyName>.
If an attribute syntax is possible, using the attribute syntax is typically more convenient and enables a more compact markup, but that is often just a matter of style, not a technical limitation. The following example shows the same properties being set as in the previous attribute syntax example, but this time by using property element syntax for all properties of the Button.
<Button> <Button.Background> <SolidColorBrush Color="Blue"/> </Button.Background> <Button.Foreground> <SolidColorBrush Color="Red"/> </Button.Foreground> <Button.Content> This is a button </Button.Content> </Button>
Collection Syntax
The XAML language includes some optimizations that produce more human-readable markup. One such optimization is that if a particular property takes a collection type, then items that you declare in markup as child elements within that property's value become part of the collection. In this case a collection of child object elements is the value being set to the collection property.
The following example shows collection syntax for setting values of the GradientStops property:
<LinearGradientBrush> <LinearGradientBrush.GradientStops> <!-- no explicit new GradientStopCollection, parser knows how to find or create --> <GradientStop Offset="0.0" Color="Red" /> <GradientStop Offset="1.0" Color="Blue" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush>
XAML Content Properties
XAML specifies a language feature whereby a class can designate exactly one of its properties to be the XAML content property. Child elements of that object element are used to set the value of that content property. In other words, for the content property uniquely, you can omit a property element when setting that property in XAML markup and produce a more visible parent/child metaphor in the markup.
For example, Border specifies a content property of Child. The following two Border elements are treated identically. The first one takes advantage of the content property syntax and omits the Border.Child property element. The second one shows Border.Child explicitly.
<Border> <TextBox Width="300"/> </Border> <!--explicit equivalent--> <Border> <Border.Child> <TextBox Width="300"/> </Border.Child> </Border>
As a rule of the XAML language, the value of a XAML content property must be given either entirely before or entirely after any other property elements on that object element. For instance, the following markup does not compile:
<Button>I am a <Button.Background>Blue</Button.Background> blue button</Button>
For more information about this restriction on XAML content properties, see the "XAML Content Properties" section of XAML Syntax In Detail.
Text Content
A small number of XAML elements can directly process text as their content. To enable this, one of the following cases must be true:
The class must declare a content property, and that content property must be of a type assignable to a string (the type could be Object). For instance, any ContentControl uses Content as its content property and it is type Object, and this supports the following usage on a practical ContentControl such as a Button: <Button>Hello</Button>.
The type must declare a type converter, in which case the text content is used as initialization text for that type converter. For example,<Brush>Blue</Brush>. This case is less common in practice.
The type must be a known XAML language primitive.
Content Properties and Collection Syntax Combined
Consider this example:
<StackPanel> <Button>First Button</Button> <Button>Second Button</Button> </StackPanel>
Here, each Button is a child element of StackPanel. This is a streamlined and intuitive markup that omits two tags for two different reasons.
Omitted StackPanel.Children property element: StackPanel derives from Panel. Panel defines Panel.Children as its XAML content property.
Omitted UIElementCollection object element: The Panel.Children property takes the type UIElementCollection, which implements IList. The collection's element tag can be omitted, based on the XAML rules for processing collections such as IList. (In this case,UIElementCollection actually cannot be instantiated because it does not expose a default constructor, and that is why theUIElementCollection object element is shown commented out).
<StackPanel> <StackPanel.Children> <!--<UIElementCollection>--> <Button>First Button</Button> <Button>Second Button</Button> <!--</UIElementCollection>--> </StackPanel.Children> </StackPanel>
Attribute Syntax (Events)
Attribute syntax can also be used for members that are events rather than properties. In this case, the attribute's name is the name of the event. In the WPF implementation of events for XAML, the attribute's value is the name of a handler that implements that event's delegate. For example, the following markup assigns a handler for the Click event to a Button created in markup:
<Pagexmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="MyNamespace.MyPageCode"> <Button Click="ClickHandler" >Click Me!</Button> </Page>namespace MyNamespace { public partial class MyPageCode { void ClickHandler(object sender, RoutedEventArgs e) { Button b = e.Source as Button; b.Background = Brushes.Red; } } }
There is more to events and XAML in WPF than just this example of the attribute syntax. For example, you might wonder what the ClickHandlerreferenced here represents and how it is defined. This will be explained in the upcoming Events and XAML Code-Behind section of this topic.
Case and Whitespace in XAML
XAML is generally speaking case sensitive. For purposes of resolving backing types, WPF XAML is case sensitive by the same rules that the CLR is case sensitive. Object elements, property elements, and attribute names must all be specified by using the sensitive casing when compared by name to the underlying type in the assembly, or to a member of a type. XAML language keywords and primitives are also case sensitive. Values are not always case sensitive. Case sensitivity for values will depend on the type converter behavior associated with the property that takes the value, or the property value type. For example, properties that take the Boolean type can take either true or True as equivalent values, but only because the native WPF XAML parser type conversion for string to Boolean already permits these as equivalents.
WPF XAML processors and serializers will ignore or drop all nonsignificant whitespace, and will normalize any significant whitespace. This is consistent with the default whitespace behavior recommendations of the XAML specification. This behavior is generally only of consequence when you specify strings within XAML content properties. In simplest terms, XAML converts space, linefeed and tab characters into spaces, and then preserves one space if found at either end of a contiguous string. The full explanation of XAML whitespace handling is not covered in this topic. For details, see Whitespace Processing in XAML.
Markup Extensions
Markup extensions are a XAML language concept. When used to provide the value of an attribute syntax, curly braces ({ and }) indicate a markup extension usage. This usage directs the XAML processing to escape from the general treatment of attribute values as either a literal string or a string-convertible value.
The most common markup extensions used in WPF application programming are Binding, used for data binding expressions, and the resource references StaticResource and DynamicResource. By using markup extensions, you can use attribute syntax to provide values for properties even if that property does not support an attribute syntax in general. Markup extensions often use intermediate expression types to enable features such as deferring values or referencing other objects that are only present at run time.
For example, the following markup sets the value of the Style property using attribute syntax. The Style property takes an instance of the Style class, which by default could not be instantiated by an attribute syntax string. But in this case, the attribute references a particular markup extension,StaticResource. When that markup extension is processed, it returns a reference to a style that was previously instantiated as a keyed resource in a resource dictionary.
<Page.Resources><SolidColorBrush x:Key="MyBrush" Color="Gold"/> <Style TargetType="Border" x:Key="PageBackground"> <Setter Property="Background" Value="Blue"/> </Style> ... </Page.Resources> <StackPanel> <Border Style="{StaticResource PageBackground}"> ... </Border> </StackPanel>
For a reference listing of all markup extensions for XAML implemented specifically in WPF, see WPF XAML Extensions. For a reference listing of the markup extensions that are defined by System.Xaml and are more widely available for .NET Framework XAML implementations, see XAML Namespace (x:) Language Features. For more information about markup extension concepts, see Markup Extensions and WPF XAML.
Type Converters
In the XAML Syntax in Brief section, it was stated that the attribute value must be able to be set by a string. The basic, native handling of how strings are converted into other object types or primitive values is based on the String type itself, in addition to native processing for certain types such asDateTime or Uri. But many WPF types or members of those types extend the basic string attribute processing behavior, in such a way that instances of more complex object types can be specified as strings and attributes.
The Thickness structure is an example of a type that has a type conversion enabled for XAML usages. Thickness indicates measurements within a nested rectangle and is used as the value for properties such as Margin. By placing a type converter on Thickness, all properties that use a Thicknessare easier to specify in XAML because they can be specified as attributes. The following example uses a type conversion and attribute syntax to provide a value for a Margin:
<Button Margin="10,20,10,30" Content="Click me"/>
The previous attribute syntax example is equivalent to the following more verbose syntax example, where the Margin is instead set through property element syntax containing a Thickness object element. The four key properties of Thickness are set as attributes on the new instance:
<Button Content="Click me"> <Button.Margin> <Thickness Left="10" Top="20" Right="10" Bottom="30"/> </Button.Margin> </Button>
Note |
---|
There are also a limited number of objects where the type conversion is the only public way to set a property to that type without involving a subclass, because the type itself does not have a default constructor. An example is Cursor. |
For more information on how type conversion and its use for attribute syntax is supported, see TypeConverters and XAML.
XAML Root Elements and XAML Namespaces
A XAML file must have only one root element, in order to be both a well-formed XML file and a valid XAML file. For typical WPF scenarios, you use a root element that has a prominent meaning in the WPF application model (for example, Window or Page for a page, ResourceDictionary for an external dictionary, or Application for the application definition). The following example shows the root element of a typical XAML file for a WPF page, with the root element of Page.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" ...
</Page>
The root element also contains the attributes xmlns and xmlns:x. These attributes indicate to a XAML processor which XAML namespaces contain the type definitions for backing types that the markup will reference as elements. The xmlns attribute specifically indicates the default XAML namespace. Within the default XAML namespace, object elements in the markup can be specified without a prefix. For most WPF application scenarios, and for almost all of the examples given in the WPF sections of the SDK, the default XAML namespace is mapped to the WPF namespace http://schemas.microsoft.com/winfx/2006/xaml/presentation. The xmlns:x attribute indicates an additional XAML namespace, which maps the XAML language namespace http://schemas.microsoft.com/winfx/2006/xaml.
This usage of xmlns to define a scope for usage and mapping of a namescope is consistent with the XML 1.0 specification. XAML namescopes are different from XML namescopes only in that a XAML namescope also implies something about how the namescope's elements are backed by types when it comes to type resolution and parsing the XAML.
Note that the xmlns attributes are only strictly necessary on the root element of each XAML file. xmlns definitions will apply to all descendant elements of the root element (this behavior is again consistent with the XML 1.0 specification for xmlns.) xmlns attributes are also permitted on other elements underneath the root, and would apply to any descendant elements of the defining element. However, frequent definition or redefinition of XAML namespaces can result in a XAML markup style that is difficult to read.
The WPF implementation of its XAML processor includes an infrastructure that has awareness of the WPF core assemblies. The WPF core assemblies are known to contain the types that support the WPF mappings to the default XAML namespace. This is enabled through configuration that is part of your project build file and the WPF build and project systems. Therefore, declaring the default XAML namespace as the default xmlns is all that is necessary in order to reference XAML elements that come from WPF assemblies.
The x: Prefix
In the previous root element example, the prefix x: was used to map the XAML namespace http://schemas.microsoft.com/winfx/2006/xaml, which is the dedicated XAML namespace that supports XAML language constructs. This x: prefix is used for mapping this XAML namespace in the templates for projects, in examples, and in documentation throughout this SDK. The XAML namespace for the XAML language contain several programming constructs that you will use very frequently in your XAML. The following is a listing of the most common x: prefix programming constructs you will use:
x:Key: Sets a unique key for each resource in a ResourceDictionary (or similar dictionary concepts in other frameworks). x:Key will probably account for 90% of the x: usages you will see in a typical WPF application's markup.
x:Class: Specifies the CLR namespace and class name for the class that provides code-behind for a XAML page. You must have such a class to support code-behind per the WPF programming model, and therefore you almost always see x: mapped, even if there are no resources.
x:Name: Specifies a run-time object name for the instance that exists in run-time code after an object element is processed. In general, you will frequently use a WPF-defined equivalent property for x:Name. Such properties map specifically to a CLR backing property and are thus more convenient for application programming, where you frequently use run time code to find the named elements from initialized XAML. The most common such property is FrameworkElement.Name. You might still use x:Name when the equivalent WPF framework-level Nameproperty is not supported in a particular type. This occurs in certain animation scenarios.
x:Static: Enables a reference that returns a static value that is not otherwise a XAML-compatible property.
x:Type: Constructs a Type reference based on a type name. This is used to specify attributes that take Type, such as Style.TargetType, although frequently the property has native string-to-Type conversion in such a way that the x:Type markup extension usage is optional.
There are additional programming constructs in the x: prefix/XAML namespace, which are not as common. For details, see XAML Namespace (x:) Language Features.
Custom Prefixes and Custom Types in XAML
For your own custom assemblies, or for assemblies outside the WPF core of PresentationCore, PresentationFramework and WindowsBase, you can specify the assembly as part of a custom xmlns mapping. You can then reference types from that assembly in your XAML, so long as that type is correctly implemented to support the XAML usages you are attempting.
The following is a very basic example of how custom prefixes work in XAML markup. The prefix custom is defined in the root element tag, and mapped to a specific assembly that is packaged and available with the application. This assembly contains a type NumericUpDown, which is implemented to support general XAML usage as well as using a class inheritance that permits its insertion at this particular point in a WPF XAML content model. An instance of this NumericUpDown control is declared as an object element, using the prefix so that a XAML parser knows which XAML namespace contains the type, and therefore where the backing assembly is that contains the type definition.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:custom="clr-namespace:NumericUpDownCustomControl;assembly=CustomLibrary" > <StackPanel Name="LayoutRoot"> <custom:NumericUpDown Name="numericCtrl1" Width="100" Height="60"/> ... </StackPanel> </Page>
For more information about custom types in XAML, see XAML and Custom Classes for WPF.
For more information about how XML namespaces and the namespaces of the backing code in assemblies are related, see XAML Namespaces and Namespace Mapping for WPF XAML.
Events and XAML Code-Behind
Most WPF applications consist of both XAML markup and code-behind. Within a project, the XAML is written as a .xaml file, and a CLR language such as Microsoft Visual Basic or C# is used to write a code-behind file. When a XAML file is markup compiled as part of the WPF programming and application models, the location of the XAML code-behind file for a XAML file is identified by specifying a namespace and class as the x:Class attribute of the root element of the XAML.
In the examples so far, you have seen several buttons, but none of these buttons had any logical behavior associated with them yet. The primary application-level mechanism for adding a behavior for an object element is to use an existing event of the element class, and to write a specific handler for that event that is invoked when that event is raised at run time. The event name and the name of the handler to use are specified in the markup, whereas the code that implements your handler is defined in the code-behind.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="MyNamespace.MyPageCode"> <Button Click="ClickHandler" >Click Me!</Button> </Page>
namespace MyNamespace { public partial class MyPageCode { void ClickHandler(object sender, RoutedEventArgs e) { Button b = e.Source as Button; b.Background = Brushes.Red; } }
}
Notice that the code-behind file uses the CLR namespace ExampleNamespace and declares ExamplePage as a partial class within that namespace. This parallels the x:Class attribute value of ExampleNamespace.ExamplePage that was provided in the markup root. The WPF markup compiler will create a partial class for any compiled XAML file, by deriving a class from the root element type. When you provide code-behind that also defines the same partial class, the resulting code is combined within the same namespace and class of the compiled application.
For more information about requirements for code-behind programming in WPF, see the "Code-behind, Event Handler, and Partial Class Requirements" section of Code-Behind and XAML in WPF.
If you do not want to create a separate code-behind file, you can also inline your code in a XAML file. However, inline code is a less versatile technique that has substantial limitations. For details, see Code-Behind and XAML in WPF.
Routed Events
A particular event feature that is fundamental to WPF is a routed event. Routed events enable an element to handle an event that was raised by a different element, as long as the elements are connected through a tree relationship. When specifying event handling with a XAML attribute, the routed event can be listened for and handled on any element, including elements that do not list that particular event in the class members table. This is accomplished by qualifying the event name attribute with the owning class name. For instance, the parent StackPanel in the ongoingStackPanel / Button example could register a handler for the child element button's Click event by specifying the attribute Button.Click on the StackPanel object element, with your handler name as the attribute value. For more information about how routed events work, see Routed Events Overview.
XAML Named Elements
By default, the object instance that is created in an object graph by processing a XAML object element does not possess a unique identifier or object reference. In contrast, if you call a constructor in code, you almost always use the constructor result to set a variable to the constructed instance, so that you can reference the instance later in your code. In order to provide standardized access to objects that were created through a markup definition, XAML defines the x:Name attribute. You can set the value of the x:Name attribute on any object element. In your code-behind, the identifier you choose is equivalent to an instance variable that refers to the constructed instance. In all respects, named elements function as if they were object instances (the name references that instance), and your code-behind can reference the named elements to handle run-time interactions within the application. This connection between instances and variables is accomplished by the WPF XAML markup compiler, and more specifically involve features and patterns such as InitializeComponent that will not be discussed in detail in this topic.
WPF framework-level XAML elements inherit a Name property, which is equivalent to the XAML defined x:Name attribute. Certain other classes also provide property-level equivalents for x:Name, which is also generally defined as a Name property. Generally speaking, if you cannot find a Nameproperty in the members table for your chosen element/type, use x:Name instead. The x:Name values will provide an identifier to a XAML element that can be used at run time, either by specific subsystems or by utility methods such as FindName.
The following example sets Name on a StackPanel element. Then, a handler on a Button within that StackPanel references the StackPanel through its instance reference buttonContainer as set by Name.
<StackPanel Name="buttonContainer"> ... <Button Click="RemoveThis">Click to remove this button</Button>
</StackPanel>
void RemoveThis(object sender, RoutedEventArgs e) { FrameworkElement fe = e.Source as FrameworkElement; if (buttonContainer.Children.Contains(fe)) { buttonContainer.Children.Remove(fe); }
}
Just like a variable, the XAML name for an instance is governed by a concept of scope, so that names can be enforced to be unique within a certain scope that is predictable. The primary markup that defines a page denotes one unique XAML namescope, with the XAML namescope boundary being the root element of that page. However, other markup sources can interact with a page at run time, such as styles or templates within styles, and such markup sources often have their own XAML namescopes that do not necessarily connect with the XAML namescope of the page. For more information on x:Name and XAML namescopes, see Name, x:Name Directive, or WPF XAML Namescopes.
Attached Properties and Attached Events
XAML specifies a language feature that enables certain properties or events to be specified on any element, regardless of whether the property or event exists in the type's definitions for the element it is being set on. The properties version of this feature is called an attached property, the events version is called an attached event. Conceptually, you can think of attached properties and attached events as global members that can be set on any XAML element/object instance. However, that element/class or a larger infrastructure must support a backing property store for the attached values.
Attached properties in XAML are typically used through attribute syntax. In attribute syntax, you specify an attached property in the formownerType.propertyName.
Superficially, this resembles a property element usage, but in this case the ownerType you specify is always a different type than the object element where the attached property is being set. ownerType is the type that provides the accessor methods that are required by a XAML processor in order to get or set the attached property value.
The most common scenario for attached properties is to enable child elements to report a property value to their parent element.
The following example illustrates the DockPanel.Dock attached property. The DockPanel class defines the accessors for DockPanel.Dock and therefore owns the attached property. The DockPanel class also includes logic that iterates its child elements and specifically checks each element for a set value of DockPanel.Dock. If a value is found, that value is used during layout to position the child elements. Use of the DockPanel.Dock attached property and this positioning capability is in fact the motivating scenario for the DockPanel class.
<DockPanel> <Button DockPanel.Dock="Left" Width="100" Height="20">I am on the left</Button> <Button DockPanel.Dock="Right" Width="100" Height="20">I am on the right</Button> </DockPanel>
In WPF, most or all the attached properties are also implemented as dependency properties. For details, see Attached Properties Overview.
Attached events use a similar ownerType.eventName form of attribute syntax. Just like the non-attached events, the attribute value for an attached event in XAML specifies the name of the handler method that is invoked when the event is handled on the element. Attached event usages in WPF XAML are less common. For more information, see Attached Events Overview.
Base Types and XAML
Underlying WPF XAML and its XAML namespace is a collection of types that correspond to CLR objects in addition to markup elements for XAML. However, not all classes can be mapped to elements. Abstract classes, such as ButtonBase, and certain nonabstract base classes are used for inheritance in the CLR objects model. Base classes, including abstract ones, are still important to XAML development because each of the concrete XAML elements inherits members from some base class in its hierarchy. Often these members include properties that can be set as attributes on the element, or events that can be handled. FrameworkElement is the concrete base UI class of WPF at the WPF framework level. When designing UI, you will use various shape, panel, decorator, or control classes, which all derive from FrameworkElement. A related base class, FrameworkContentElement, supports document-oriented elements that work well for a flow layout presentation, using APIs that deliberately mirror the APIs inFrameworkElement. The combination of attributes at the element level and a CLR object model provides you with a set of common properties that are settable on most concrete XAML elements, regardless of the specific XAML element and its underlying type.
XAML Security
XAML is a markup language that directly represents object instantiation and execution. Therefore, elements created in XAML have the same ability to interact with system resources (network access, file system IO, for example) as the equivalent generated code does.
WPF supports the .NET Framework 4 security framework Code Access Security (CAS). This means that WPF content running in the internet zone has reduced execution permissions. "Loose XAML" (pages of noncompiled XAML interpreted at load time by a XAML viewer) and XAML browser application (XBAP) are usually run in this internet zone and use the same permission set. However, XAML loaded in to a fully trusted application has the same access to the system resources as the hosting application does. For more information, see WPF Partial Trust Security.
Loading XAML from Code
XAML can be used to define all of the UI, but it is sometimes also appropriate to define just a piece of the UI in XAML. This capability could be used to enable partial customization, local storage of information, using XAML to provide a business object, or a variety of possible scenarios. The key to these scenarios is the XamlReader class and its Load method. The input is a XAML file, and the output is an object that represents all of the run-time tree of objects that was created from that markup. You then can insert the object to be a property of another object that already exists in the application. So long as the property is an appropriate property in the content model that has eventual display capabilities and that will notify the execution engine that new content has been added into the application, you can modify a running application's contents very easily by loading in XAML. Note that this capability is generally only available in full-trust applications, because of the obvious security implications of loading files into applications as they run.
What's Next
This topic provides a basic introduction to XAML syntax concepts and terminology as it applies to WPF. For more information about the terms used here, see XAML Syntax In Detail.
If you have not already done this, try the exercises in the tutorial topic Walkthrough: My First WPF Desktop Application. When you create the markup-centric application described by the tutorial, the exercise will help reinforce many of the concepts described in this topic.
WPF uses a particular application model that is based on the Application class. For details, see Application Management Overview.
Building a WPF Application (WPF) gives you more details about how to build XAML inclusive applications from the command line and with Microsoft Visual Studio.
Dependency Properties Overview gives more information about the versatility of properties in WPF, and introduces the concept of dependency properties.
XAML Syntax In Detail
This topic defines the terms that are used to describe the elements of XAML syntax. These terms are used frequently throughout the remainder of this documentation, both for WPF documentation specifically and for the other frameworks that use XAML or the basic XAML concepts enabled by the XAML language support at the System.Xaml level. This topic expands on the basic terminology introduced in the topic XAML Overview (WPF).
The XAML Language Specification
The XAML syntax terminology defined here is also defined or referenced within the XAML language specification. XAML is a language based on XML and follows or expands upon XML structural rules. Some of the terminology is shared from or is based on the terminology commonly used when describing the XML language or the XML document object model.
For more information about the XAML language specification, download [MS-XAML] from the Microsoft Download Center.
XAML and CLR
XAML is a markup language. The common language runtime (CLR), as implied by its name, enables runtime execution. XAML is not by itself one of the common languages that is directly consumed by the CLR runtime. Instead, you can think of XAML as supporting its own type system. The particular XAML parsing system that is used by WPF is built on the CLR and the CLR type system. XAML types are mapped to CLR types to instantiate a run time representation when the XAML for WPF is parsed. For this reason, the remainder of discussion of syntax in this document will include references to the CLR type system, even though the equivalent syntax discussions in the XAML language specification do not. (Per the XAML language specification level, XAML types could be mapped to any other type system, which does not have to be the CLR, but that would require the creation and use of a different XAML parser.)
Members of Types and Class Inheritance
Properties and events as they appear as XAML members of a WPF type are often inherited from base types. For example, consider this example:<Button Background="Blue" .../>. The Background property is not an immediately declared property on the Button class, if you were to look at the class definition, reflection results, or the documentation. Instead, Background is inherited from the base Control class.
The class inheritance behavior of WPF XAML elements is a significant departure from a schema-enforced interpretation of XML markup. Class inheritance can become complex, particularly when intermediate base classes are abstract, or when interfaces are involved. This is one reason that the set of XAML elements and their permissible attributes is difficult to represent accurately and completely using the schema types that are typically used for XML programming, such as DTD or XSD format. Another reason is that extensibility and type-mapping features of the XAML language itself preclude completeness of any fixed representation of the permissible types and members.
Object Element Syntax
Object element syntax is the XAML markup syntax that instantiates a CLR class or structure by declaring an XML element. This syntax resembles the element syntax of other markup languages such as HTML. Object element syntax begins with a left angle bracket (<), followed immediately by the type name of the class or structure being instantiated. Zero or more spaces can follow the type name, and zero or more attributes may also be declared on the object element, with one or more spaces separating each attribute name="value" pair. Finally, one of the following must be true:
The element and tag must be closed by a forward slash (/) followed immediately by a right angle bracket (>).
The opening tag must be completed by a right angle bracket (>). Other object elements, property elements, or inner text, can follow the opening tag. Exactly what content may be contained here is typically constrained by the object model of the element. The equivalent closing tag for the object element must also exist, in proper nesting and balance with other opening and closing tag pairs.
XAML as implemented by .NET has a set of rules that map object elements into types, attributes into properties or events, and XAML namespaces to CLR namespaces plus assembly. For WPF and the .NET Framework, XAML object elements map to Microsoft .NET types as defined in referenced assemblies, and the attributes map to members of those types. When you reference a CLR type in XAML, you have access to the inherited members of that type as well.
For example, the following example is object element syntax that instantiates a new instance of the Button class, and also specifies a Name attribute and a value for that attribute:
<Button Name="CheckoutButton"/>
The following example is object element syntax that also includes XAML content property syntax. The inner text contained within will be used to set the TextBox XAML content property, Text.
<TextBox>This is a Text Box</TextBox>
Content Models
A class might support a usage as a XAML object element in terms of the syntax, but that element will only function properly in an application or page when it is placed in an expected position of an overall content model or element tree. For example, a MenuItem should typically only be placed as a child of a MenuBase derived class such as Menu. Content models for specific elements are documented as part of the remarks on the class pages for controls and other WPF classes that can be used as XAML elements.
Properties of Object Elements
Properties in XAML are set by a variety of possible syntaxes. Which syntax can be used for a particular property will vary, based on the underlying type system characteristics of the property that you are setting.
By setting values of properties, you add features or characteristics to objects as they exist in the run time object graph. The initial state of the created object from a object element is based on the default constructor behavior. Typically, your application will use something other than a completely default instance of any given object.
Attribute Syntax (Properties)
Attribute syntax is the XAML markup syntax that sets a value for a property by declaring an attribute on an existing object element. The attribute name must match the CLR member name of the property of the class that backs the relevant object element. The attribute name is followed by an assignment operator (=). The attribute value must be a string enclosed within quotes.
Note |
---|
You can use alternating quotes to place a literal quotation mark within an attribute. For instance you can use single quotes as a means to declare a string that contains a double quote character within it. Whether you use single or double quotes, you should use a matching pair for opening and closing the attribute value string. There are also escape sequences or other techniques available for working around character restrictions imposed by any particular XAML syntax. See XML Character Entities and XAML. |
In order to be set through attribute syntax, a property must be public and must be writeable. The value of the property in the backing type system must be a value type, or must be a reference type that can be instantiated or referenced by a XAML processor when accessing the relevant backing type.
For WPF XAML events, the event that is referenced as the attribute name must be public and have a public delegate.
The property or event must be a member of the class or structure that is instantiated by the containing object element.
Processing of Attribute Values
The string value contained within the opening and closing quotation marks is processed by a XAML processor. For properties, the default processing behavior is determined by the type of the underlying CLR property.
The attribute value is filled by one of the following, using this processing order:
If the XAML processor encounters a curly brace, or an object element that derives from MarkupExtension, then the referenced markup extension is evaluated first rather than processing the value as a string, and the object returned by the markup extension is used as the value. In many cases the object returned by a markup extension will be a reference to an existing object, or an expression that defers evaluation until run time, and is not a newly instantiated object.
If the property is declared with an attributed TypeConverter, or the value type of that property is declared with an attributed TypeConverter, the string value of the attribute is submitted to the type converter as a conversion input, and the converter will return a new object instance.
If there is no TypeConverter, a direct conversion to the property type is attempted. This final level is a direct conversion at the parser-native value between XAML language primitive types, or a check for the names of named constants in an enumeration (the parser then accesses the matching values).
Enumeration Attribute Values
Enumerations in XAML are processed intrinsically by XAML parsers, and the members of an enumeration should be specified by specifying the string name of one of the enumeration's named constants.
For nonflag enumeration values, the native behavior is to process the string of an attribute value and resolve it to one of the enumeration values. You do not specify the enumeration in the format Enumeration.Value, as you do in code. Instead, you specify only Value, andEnumeration is inferred by the type of the property you are setting. If you specify an attribute in the Enumeration.Value form, it will not resolve correctly.
For flagwise enumerations, the behavior is based on the Enum.Parse method. You can specify multiple values for a flagwise enumeration by separating each value with a comma. However, you cannot combine enumeration values that are not flagwise. For instance, you cannot use the comma syntax to attempt to create a Trigger that acts on multiple conditions of a nonflag enumeration:
<!--This will not compile, because Visibility is not a flagwise enumeration.--> ... <Trigger Property="Visibility" Value="Collapsed,Hidden"> <Setter ... /> </Trigger> ...
Flagwise enumerations that support attributes that are settable in XAML are rare in WPF. However, one such enumeration is StyleSimulations. You could, for instance, use the comma-delimited flagwise attribute syntax to modify the example provided in the Remarks for the Glyphs class;StyleSimulations = "BoldSimulation" could become StyleSimulations = "BoldSimulation,ItalicSimulation".KeyBinding.Modifiers is another property where more than one enumeration value can be specified. However, this property happens to be a special case, because the ModifierKeys enumeration supports its own type converter. The type converter for modifiers uses a plus sign (+) as a delimiter rather than a comma (,). This conversion supports the more traditional syntax to represent key combinations in Microsoft Windows programming, such as "Ctrl+Alt".
Properties and Event Member Name References
When specifying an attribute, you can reference any property or event that exists as a member of the CLR type you instantiated for the containing object element.
Or, you can reference an attached property or attached event, independent of the containing object element. (Attached properties are discussed in an upcoming section.)
You can also name any event from any object that is accessible through the default namespace by using a typeName.event partially qualified name; this syntax supports attaching handlers for routed events where the handler is intended to handle events routing from child elements, but the parent element does not also have that event in its members table. This syntax resembles an attached event syntax, but the event here is not a true attached event. Instead, you are referencing an event with a qualified name. For more information, see Routed Events Overview.
For some scenarios, property names are sometimes provided as the value of an attribute, rather than the attribute name. That property name can also include qualifiers, such as the property specified in the form ownerType.dependencyPropertyName. This scenario is common when writing styles or templates in XAML. The processing rules for property names provided as an attribute value are different, and are governed by the type of the property being set or by the behaviors of particular WPF subsystems. For details, see Styling and Templating.
Another usage for property names is when an attribute value describes a property-property relationship. This feature is used for data binding and for storyboard targets, and is enabled by the PropertyPath class and its type converter. For a more complete description of the lookup semantics, see PropertyPath XAML Syntax.
Property Element Syntax
Property element syntax is a syntax that diverges somewhat from the basic XML syntax rules for elements. In XML, the value of an attribute is a de facto string, with the only possible variation being which string encoding format is being used. In XAML, you can assign other object elements to be the value of a property. This capability is enabled by the property element syntax. 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 within, and then the property element is closed.
Specifically, the syntax begins with a left angle bracket (<), followed immediately by the type name of the class or structure that the property element syntax is contained within. This is followed immediately by a single dot (.), then by the name of a property, then by a right angle bracket (>). As with attribute syntax, that property must exist within the declared public members of the specified type. The value to be assigned to the property is contained within the property element. Typically, the value is given as one or more object elements, because specifying objects as values is the scenario that property element syntax is intended to address. Finally, an equivalent closing tag specifying the same elementTypeName.propertyNamecombination must be provided, in proper nesting and balance with other element tags.
For example, the following is property element syntax for the ContextMenu property of a Button.
<Button> <Button.ContextMenu> <ContextMenu> <MenuItem Header="1">First item</MenuItem> <MenuItem Header="2">Second item</MenuItem> </ContextMenu> </Button.ContextMenu> Right-click me!</Button>
The value within a property element can also be given as inner text, in cases where the property type being specified is a primitive value type, such asString, or an enumeration where a name is specified. These two usages are somewhat uncommon, because each of these cases could also use a simpler attribute syntax. One scenario for filling a property element with a string is for properties that are not the XAML content property but still are used for representation of UI text, and particular whitespace elements such as linefeeds are required to appear in that UI text. Attribute syntax cannot preserve linefeeds, but property element syntax can, so long as significant whitespace preservation is active (for details, see Whitespace Processing in XAML). Another scenario is so that x:Uid Directive can be applied to the property element and thus mark the value within as a value that should be localized in the WPF output BAML or by other techniques.
A property element is not represented in the WPF logical tree. A property element is just a particular syntax for setting a property, and is not an element that has an instance or object backing it. (For details on the logical tree concept, see Trees in WPF.)
For properties where both attribute and property element syntax are supported, the two syntaxes generally have the same result, although subtleties such as whitespace handling can vary slightly between syntaxes.
Collection Syntax
The XAML specification requires XAML processor implementations to identify properties where the value type is a collection. The general XAML processor implementation in .NET is based on managed code and the CLR, and it identifies collection types through one of the following:
Type implements IList.
Type implements IDictionary.
Type derives from Array (for more information about arrays in XAML, see x:Array Markup Extension.)
If the type of a property is a collection, then the inferred collection type does not need to be specified in the markup as an object element. Instead, the elements that are intended to become the items in the collection are specified as one or more child elements of the property element. Each such item is evaluated to an object during loading and added to the collection by calling the Add method of the implied collection. For example, theTriggers property of Style takes the specialized collection type TriggerCollection, which implements IList. It is not necessary to instantiate aTriggerCollection object element in the markup. Instead, you specify one or more Trigger items as elements within the Style.Triggers property element, where Trigger (or a derived class) is the type expected as the item type for the strongly typed and implicit TriggerCollection.
<Style x:Key="SpecialButton" TargetType="{x:Type Button}"> <Style.Triggers> <Trigger Property="Button.IsMouseOver" Value="true"> <Setter Property = "Background" Value="Red"/> </Trigger> <Trigger Property="Button.IsPressed" Value="true"> <Setter Property = "Foreground" Value="Green"/> </Trigger> </Style.Triggers> </Style>
A property may be both a collection type and the XAML content property for that type and derived types, which is discussed in the next section of this topic.
An implicit collection element creates a member in the logical tree representation, even though it does not appear in the markup as an element. Usually the constructor of the parent type performs the instantiation for the collection that is one of its properties, and the initially empty collection becomes part of the object tree.
Note |
---|
The generic list and dictionary interfaces (IList<T> and IDictionary<TKey, TValue>) are not supported for collection detection. However, you can use the List<T> class as a base class, because it implements IList directly, or Dictionary<TKey, TValue> as a base class, because it implementsIDictionary directly. |
In the .NET Reference pages for collection types, this syntax with the deliberate omission of the object element for a collection is occasionally noted in the XAML syntax sections as Implicit Collection Syntax.
With the exception of the root element, every object element in a XAML file that is nested as a child element of another element is really an element that is one or both of the following cases: a member of an implicit collection property of its parent element, or an element that specifies the value of the XAML content property for the parent element (XAML content properties will be discussed in an upcoming section). In other words, the relationship of parent elements and child elements in a markup page is really a single object at the root, and every object element beneath the root is either a single instance that provides a property value of the parent, or one of the items within a collection that is also a collection-type property value of the parent. This single-root concept is common with XML, and is frequently reinforced in the behavior of APIs that load XAML such as Load.
The following example is a syntax with the object element for a collection (GradientStopCollection) specified explicitly.
<LinearGradientBrush> <LinearGradientBrush.GradientStops> <GradientStopCollection> <GradientStop Offset="0.0" Color="Red" /> <GradientStop Offset="1.0" Color="Blue" /> </GradientStopCollection> </LinearGradientBrush.GradientStops> </LinearGradientBrush>
Note that it is not always possible to explicitly declare the collection. For instance, attempting to declare TriggerCollection explicitly in the previously shown Triggers example would fail. Explicitly declaring the collection requires that the collection class must support a default constructor, andTriggerCollection does not have a default constructor.
XAML Content Properties
XAML content syntax is a syntax that is only enabled on classes that specify the ContentPropertyAttribute as part of their class declaration. TheContentPropertyAttribute references the property name that is the content property for that type of element (including derived classes). When processed by a XAML processor, any child elements or inner text that are found between the opening and closing tags of the object element will be assigned to be the value of the XAML content property for that object. You are permitted to specify explicit property elements for the content property, but this usage is not generally shown in the XAML syntax sections in the .NET reference. The explicit/verbose technique has occasional value for markup clarity or as a matter of markup style, but usually the intent of a content property is to streamline the markup so that elements that are intuitively related as parent-child can be nested directly. Property element tags for other properties on an element are not assigned as "content" per a strict XAML language definition; they are processed previously in the XAML parser's processing order and are not considered to be "content".
XAML Content Property Values Must Be Contiguous
The value of a XAML content property must be given either entirely before or entirely after any other property elements on that object element. This is true whether the value of a XAML content property is specified as a string, or as one or more objects. For example, the following markup does not parse:
<Button>I am a <Button.Background>Blue</Button.Background> blue button</Button>
This is illegal essentially because if this syntax were made explicit by using property element syntax for the content property, then the content property would be set twice:
<Button> <Button.Content>I am a </Button.Content> <Button.Background>Blue</Button.Background> <Button.Content> blue button</Button.Content> </Button>
A similarly illegal example is if the content property is a collection, and child elements are interspersed with property elements:
<StackPanel> <Button>This example</Button> <StackPanel.Resources> <SolidColorBrush x:Key="BlueBrush" Color="Blue"/> </StackPanel.Resources> <Button>... is illegal XAML</Button> </StackPanel>
Content Properties and Collection Syntax Combined
In order to accept more than a single object element as content, the type of the content property must specifically be a collection type. Similar to property element syntax for collection types, a XAML processor must identify types that are collection types. If an element has a XAML content property and the type of the XAML content property is a collection, then the implied collection type does not need to be specified in the markup as an object element and the XAML content property does not need to be specified as a property element. Therefore the apparent content model in the markup can now have more than one child element assigned as the content. The following is content syntax for a Panel derived class. All Panelderived classes establish the XAML content property to be Children, which requires a value of type UIElementCollection.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > <StackPanel> <Button>Button 1</Button> <Button>Button 2</Button> <Button>Button 3</Button> </StackPanel> </Page>
Note that neither the property element for Children nor the element for the UIElementCollection is required in the markup. This is a design feature of XAML so that recursively contained elements that define a UI are more intuitively represented as a tree of nested elements with immediate parent-child element relationships, without intervening property element tags or collection objects. In fact, UIElementCollection cannot be specified explicitly in markup as an object element, by design. Because its only intended use is as an implicit collection, UIElementCollection does not expose a public default constructor and thus cannot be instantiated as an object element.
Mixing Property Elements and Object Elements in an Object with a Content Property
The XAML specification declares that a XAML processor can enforce that object elements that are used to fill the XAML content property within an object element must be contiguous, and must not be mixed. This restriction against mixing property elements and content is enforced by the WPF XAML processors.
You can have a child object element as the first immediate markup within an object element. Then you can introduce property elements. Or, you can specify one or more property elements, then content, then more property elements. But once a property element follows content, you cannot introduce any further content, you can only add property elements.
This content / property element order requirement does not apply to inner text used as content. However, it is still a good markup style to keep inner text contiguous, because significant whitespace will be difficult to detect visually in the markup if property elements are interspersed with inner text.
XAML Namespaces
None of the preceding syntax examples specified a XAML namespace other than the default XAML namespace. In typical WPF applications, the default XAML namespace is specified to be the WPF namespace. You can specify XAML namespaces other than the default XAML namespace and still use similar syntax. But then, anywhere where a class is named that is not accessible within the default XAML namespace, that class name must be preceded with the prefix of the XAML namespace as mapped to the corresponding CLR namespace. For example, <custom:Example/> is object element syntax to instantiate an instance of the Example class, where the CLR namespace containing that class (and possibly the external assembly information that contains backing types) was previously mapped to the custom prefix.
For more information about XAML namespaces, see XAML Namespaces and Namespace Mapping for WPF XAML.
Markup Extensions
XAML defines a markup extension programming entity that enables an escape from the normal XAML processor handling of string attribute values or object elements, and defers the processing to a backing class. The character that identifies a markup extension to a XAML processor when using attribute syntax is the opening curly brace ({), followed by any character other than a closing curly brace (}). The first string following the opening curly brace must reference the class that provides the particular extension behavior, where the reference may omit the substring "Extension" if that substring is part of the true class name. Thereafter, a single space may appear, and then each succeeding character is used as input by the extension implementation, up until the closing curly brace is encountered.
The .NET XAML implementation uses the MarkupExtension abstract class as the basis for all of the markup extensions supported by WPF as well as other frameworks or technologies. The markup extensions that WPF specifically implements are often intended to provide a means to reference other existing objects, or to make deferred references to objects that will be evaluated at run time. For example, a simple WPF data binding is accomplished by specifying the {Binding} markup extension in place of the value that a particular property would ordinarily take. Many of the WPF markup extensions enable an attribute syntax for properties where an attribute syntax would not otherwise be possible. For example, a Style object is a relatively complex type that contains a nested series of objects and properties. Styles in WPF are typically defined as a resource in aResourceDictionary, and then referenced through one of the two WPF markup extensions that request a resource. The markup extension defers the evaluation of the property value to a resource lookup and enables providing the value of the Style property, taking type Style, in attribute syntax as in the following example:
<Button Style="{StaticResource MyStyle}">My button</Button>
Here, StaticResource identifies the StaticResourceExtension class providing the markup extension implementation. The next string MyStyle is used as the input for the non-default StaticResourceExtension constructor, where the parameter as taken from the extension string declares the requestedResourceKey. MyStyle is expected to be the x:Key value of a Style defined as a resource. The StaticResource Markup Extension usage requests that the resource be used to provide the Style property value through static resource lookup logic at load time.
For more information about markup extensions, see Markup Extensions and WPF XAML. For a reference of markup extensions and other XAML programming features enabled in the general .NET XAML implementation, see XAML Namespace (x:) Language Features. For WPF-specific markup extensions, see WPF XAML Extensions.
Attached Properties
Attached properties are a programming concept introduced in XAML whereby properties can be owned and defined by a particular type, but set as attributes or property elements on any element. The primary scenario that attached properties are intended for is to enable child elements in a markup structure to report information to a parent element without requiring an extensively shared object model across all elements. Conversely, attached properties can be used by parent elements to report information to child elements. For more information on the purpose of attached properties and how to create your own attached properties, see Attached Properties Overview.
Attached properties use a syntax that superficially resembles property element syntax, in that you also specify a typeName.propertyNamecombination. There are two important differences:
You can use the typeName.propertyName combination even when setting an attached property through attribute syntax. Attached properties are the only case where qualifying the property name is a requirement in an attribute syntax.
You can also use property element syntax for attached properties. However, for typical property element syntax, the typeName you specify is the object element that contains the property element. If you are referring to an attached property, then the typeName is the class that defines the attached property, not the containing object element.
Attached Events
Attached events are another programming concept introduced in XAML where events can be defined by a specific type, but handlers may be attached on any object element. In the WOF implementation, often the type that defines an attached event is a static type that defines a service, and sometimes those attached events are exposed by a routed event alias in types that expose the service. Handlers for attached events are specified through attribute syntax. As with attached events, the attribute syntax is expanded for attached events to allow a typeName.eventName usage, wheretypeName is the class that provides Add and Remove event handler accessors for the attached event infrastructure, and eventName is the event name.
Anatomy of a XAML Root Element
The following table shows a typical XAML root element broken down, showing the specific attributes of a root element:
<Page | Opening object element of the root element |
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | The default (WPF) XAML namespace |
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | The XAML language XAML namespace |
x:Class="ExampleNamespace.ExampleCode" | The partial class declaration that connects markup to any code-behind defined for the partial class |
> | End of object element for the root. Object is not closed yet because the element contains child elements |
Optional and Nonrecommended XAML Usages
The following sections describe XAML usages that are technically supported by XAML processors, but that produce verbosity or other aesthetic issues that interfere with XAML files remaining human-readable when your develop applications that contain XAML sources.
Optional Property Element Usages
Optional property element usages include explicitly writing out element content properties that the XAML processor considers implicit. For example, when you declare the contents of a Menu, you could choose to explicitly declare the Items collection of the Menu as a <Menu.Items>property element tag, and place each MenuItem within <Menu.Items>, rather than using the implicit XAML processor behavior that all child elements of a Menu must be a MenuItem and are placed in the Items collection. Sometimes the optional usages can help to visually clarify the object structure as represented in the markup. Or sometimes an explicit property element usage can avoid markup that is technically functional but visually confusing, such as nested markup extensions within an attribute value.
Full typeName.memberName Qualified Attributes
The typeName.memberName form for an attribute actually works more universally than just the routed event case. But in other situations that form is superfluous and you should avoid it, if only for reasons of markup style and readability. In the following example, each of the three references to the Background attribute are completely equivalent:
<Button Background="Blue">Background</Button> <Button Button.Background="Blue">Button.Background</Button> <Button Control.Background="Blue">Control.Background</Button>
Button.Background works because the qualified lookup for that property on Button is successful (Background was inherited from Control) andButton is the class of the object element or a base class. Control.Background works because the Control class actually defines Background andControl is a Button base class.
However, the following typeName.memberName form example does not work and is thus shown commented:
<!--<Button Label.Background="Blue">Does not work</Button> -->
Label is another derived class of Control, and if you had specified Label.Background within a Label object element, this usage would have worked. However, because Label is not the class or base class of Button, the specified XAML processor behavior is to then processLabel.Background as an attached property. Label.Background is not an available attached property, and this usage fails.
baseTypeName.memberName Property Elements
In an analogous way to how the typeName.memberName form works for attribute syntax, a baseTypeName.memberName syntax works for property element syntax. For instance, the following syntax works:
<Button>Control.Background PE <Control.Background> <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> <GradientStop Color="Yellow" Offset="0.0" /> <GradientStop Color="LimeGreen" Offset="1.0" /> </LinearGradientBrush> </Control.Background> </Button>
Here, the property element was given as Control.Background even though the property element was contained in Button.
But just like typeName.memberName form for attributes, baseTypeName.memberName is poor style in markup, and you should avoid it.
Code-Behind and XAML in WPF
Code-behind is a term used to describe the code that is joined with markup-defined objects, when a XAML page is markup-compiled. This topic describes requirements for code-behind as well as an alternative inline code mechanism for code in XAML.
This topic contains the following sections:
Prerequisites
This topic assumes that you have read the XAML Overview (WPF) and have some basic knowledge of the CLR and object-oriented programming.
Code-Behind and the XAML Language
The XAML language includes language-level features that make it possible to associate code files with markup files, from the markup file side. Specifically, the XAML language defines the language features x:Class Directive, x:Subclass Directive, and x:ClassModifier Directive. Exactly how the code should be produced, and how to integrate markup and code, is not part of what the XAML language specifies. It is left up to frameworks such as WPF to determine how to integrate the code, how to use XAML in the application and programming models, and the build actions or other support that all this requires.
Code-behind, Event Handler, and Partial Class Requirements in WPF
The partial class must derive from the type that backs the root element.
Note that under the default behavior of the markup compile build actions, you can leave the derivation blank in the partial class definition on the code-behind side. The compiled result will assume the page root's backing type to be the basis for the partial class, even if it not specified. However, relying on this behavior is not a best practice.
The event handlers you write in the code behind must be instance methods and cannot be static methods. These methods must be defined by the partial class within the CLR namespace identified by x:Class. You cannot qualify the name of an event handler to instruct a XAML processor to look for an event handler for event wiring in a different class scope.
The handler must match the delegate for the appropriate event in the backing type system.
For the Microsoft Visual Basic language specifically, you can use the language-specific Handles keyword to associate handlers with instances and events in the handler declaration, instead of attaching handlers with attributes in XAML. However, this technique does have some limitations because the Handles keyword cannot support all of the specific features of the WPF event system, such as certain routed event scenarios or attached events. For details, see Visual Basic and WPF Event Handling.
x:Code
x:Code is a directive element defined in XAML. An x:Code directive element can contain inline programming code. The code that is defined inline can interact with the XAML on the same page. The following example illustrates inline C# code. Notice that the code is inside the x:Code element and that the code must be surrounded by <CDATA[...]]> to escape the contents for XML, so that a XAML processor (interpreting either the XAML schema or the WPF schema) will not try to interpret the contents literally as XML.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="MyNamespace.MyCanvasCodeInline" > <Button Name="button1" Click="Clicked">Click Me!</Button> <x:Code><![CDATA[ void Clicked(object sender, RoutedEventArgs e) { button1.Content = "Hello World"; } ]]></x:Code> </Page>
Inline Code Limitations
You should consider avoiding or limiting the use of inline code. In terms of architecture and coding philosophy, maintaining a separation between markup and code-behind keeps the designer and developer roles much more distinct. On a more technical level, the code that you write for inline code can be awkward to write, because you are always writing into the XAML generated partial class, and can only use the default XML namespace mappings. Because you cannot add using statements, you must fully qualify many of the API calls that you make. The default WPF mappings include most but not all CLR namespaces that are present in the WPF assemblies; you will have to fully qualify calls to types and members contained within the other CLR namespaces. You also cannot define anything beyond the partial class in the inline code, and all user code entities you reference must exist as a member or variable within the generated partial class. Other language specific programming features, such as macros or #ifdef against global variables or build variables, are also not available. For more information, see x:Code Intrinsic XAML Type.
XAML and Custom Classes for WPF
XAML as implemented in common language runtime (CLR) frameworks supports the ability to define a custom class or structure in any common language runtime (CLR) language, and then access that class using XAML markup. You can use a mixture of Windows Presentation Foundation (WPF)-defined types and your custom types within the same markup file, typically by mapping the custom types to a XAML namespace prefix. This topic discusses the requirements that a custom class must satisfy to be usable as a XAML element.
Custom Classes in Applications or Assemblies
Custom classes that are used in XAML can be defined in two distinct ways: within the code-behind or other code that produces the primary Windows Presentation Foundation (WPF) application, or as a class in a separate assembly, such as an executable or DLL used as a class library. Each of these approaches has particular advantages and disadvantages.
The advantage of creating a class library is that any such custom classes can be shared across many different possible applications. A separate library also makes versioning issues of applications easier to control, and simplifies creating a class where the intended class usage is as a root element on a XAML page.
The advantage of defining the custom classes in the application is that this technique is relatively lightweight and minimizes the deployment and testing issues encountered when you introduce separate assemblies beyond the main application executable.
Whether defined in the same or different assembly, custom classes need to be mapped between CLR namespace and XML namespace in order to be used in XAML as elements. See XAML Namespaces and Namespace Mapping for WPF XAML.
Requirements for a Custom Class as a XAML Element
In order to be able to be instantiated as an object element, your class must meet the following requirements:
Your custom class must be public and support a default (parameterless) public constructor. (See following section for notes regarding structures.)
Your custom class must not be a nested class. Nested classes and the "dot" in their general CLR usage syntax interfere with other WPF and/or XAML features such as attached properties.
In addition to enabling object element syntax, your object definition also enables property element syntax for any other public properties that take that object as the value type. This is because the object can now be instantiated as an object element and can fill the property element value of such a property.
Structures
Structures that you define as custom types are always able to be constructed in XAML in WPF .This is because the CLR compilers implicitly create a default constructor for a structure that initializes all property values to their defaults. In some cases, the default construction behavior and/or object element usage for a structure is not desirable. This might be because the structure is intended to fill values and function conceptually as a union, where the values contained might have mutually exclusive interpretations and thus none of its properties are settable. A WPF example of such a structure is GridLength. Generally, such structures should implement a type converter such that the values can be expressed in attribute form, using string conventions that create the different interpretations or modes of the structure's values. The structure should also expose similar behavior for code construction through a non-default constructor.
Requirements for Properties of a Custom Class as XAML Attributes
Properties must reference a by-value type (such as a primitive), or use a class for type that has either a default constructor or a dedicated type converter that a XAML processor can access. In the CLR XAML implementation, XAML processors either find such converters through native support for language primitives, or through application of TypeConverterAttribute to a type or member in backing type definitions
Alternatively, the property may reference an abstract class type, or an interface. For abstract classes or interfaces, the expectation for XAML parsing is that the property value must be filled with practical class instances that implement the interface, or instances of types that derive from the abstract class.
Properties can be declared on an abstract class, but can only be set on practical classes that derive from the abstract class. This is because creating the object element for the class at all requires a public default constructor on the class.
TypeConverter Enabled Attribute Syntax
If you provide a dedicated, attributed type converter at the class level, the applied type conversion enables attribute syntax for any property that needs to instantiate that type. A type converter does not enable object element usage of the type; only the presence of a default constructor for that type enables object element usage. Therefore, properties that are type-converter enabled are generally speaking not usable in property syntax, unless the type itself also supports object element syntax. The exception to this is that you can specify a property element syntax, but have the property element contain a string. That usage is really essentially equivalent to an attribute syntax usage, and such a usage is not common unless there is a need for more robust whitespace handling of the attribute value. For example, the following is a property element usage that takes a string, and the attribute usage equivalent:
<Button>Hallo! <Button.Language> de-DE </Button.Language> </Button>
<Button Language="de-DE">Hallo!</Button>
Examples of properties where attribute syntax is allowed but property element syntax that contains an object element is disallowed through XAML are various properties that take the Cursor type. The Cursor class has a dedicated type converter CursorConverter, but does not expose a default constructor, so the Cursor property can only be set through attribute syntax even though the actual Cursor type is a reference type.
Per-Property Type Converters
Alternatively, the property itself may declare a type converter at the property level. This enables a "mini language" that instantiates objects of the type of the property inline, by processing incoming string values of the attribute as input for a ConvertFrom operation based on the appropriate type. Typically this is done to provide a convenience accessor, and not as the sole means to enable setting a property in XAML. However, it is also possible to use type converters for attributes where you want to use existing CLR types that do not supply either a default constructor or an attributed type converter. Examples from the WPF API are certain properties that take the CultureInfo type. In this case, WPF used the existing Microsoft .NET Framework CultureInfo type to better address compatibility and migration scenarios that were used in earlier versions of frameworks, but the CultureInfo type did not support the necessary constructors or type-level type conversion to be usable as a XAML property value directly.
Whenever you expose a property that has a XAML usage, particularly if you are a control author, you should strongly consider backing that property with a dependency property. This is particularly true if you use the existing Windows Presentation Foundation (WPF) implementation of the XAML processor, because you can improve performance by using DependencyProperty backing. A dependency property will expose property system features for your property that users will come to expect for a XAML accessible property. This includes features such as animation, data binding, and style support. For more information, see Custom Dependency Properties and XAML Loading and Dependency Properties.
Writing and Attributing a Type Converter
You occasionally will need to write a custom TypeConverter derived class to provide type conversion for your property type. For instructions on how to derive from and create a type converter that can support XAML usages, and how to apply the TypeConverterAttribute, see TypeConverters and XAML.
Requirements for XAML Event Handler Attribute Syntax on Events of a Custom Class
To be usable as a CLR event, the event must be exposed as a public event on a class that supports a default constructor, or on an abstract class where the event can be accessed on derived classes. In order to be used conveniently as a routed event, your CLR event should implement explicit add and remove methods, which add and remove handlers for the CLR event signature and forward those handlers to the AddHandler andRemoveHandler methods. These methods add or remove the handlers to the routed event handler store on the instance that the event is attached to.
Note |
---|
It is possible to register handlers directly for routed events using AddHandler, and to deliberately not define a CLR event that exposes the routed event. This is not generally recommended because the event will not enable XAML attribute syntax for attaching handlers, and your resulting class will offer a less transparent XAML view of that type's capabilities. |
Writing Collection Properties
Properties that take a collection type have a XAML syntax that enables you to specify objects that are added to the collection. This syntax has two notable features.
The object that is the collection object does not need to be specified in object element syntax. The presence of that collection type is implicit whenever you specify a property in XAML that takes a collection type.
Child elements of the collection property in markup are processed to become members of the collection. Ordinarily, the code access to the members of a collection is performed through list/dictionary methods such as Add, or through an indexer. But XAML syntax does not support methods or indexers (exception: XAML 2009 can support methods, but using XAML 2009 restricts the possible WPF usages; see XAML 2009 Language Features). Collections are obviously a very common requirement for building a tree of elements, and you need some way to populate these collections in declarative XAML. Therefore, child elements of a collection property are processed by adding them to the collection that is the collection property type value.
The .NET Framework XAML Services implementation and thus the WPF XAML processor uses the following definition for what constitutes a collection property. The property type of the property must implement one of the following:
Implements IList.
Implements IDictionary or the generic equivalent (IDictionary<TKey, TValue>).
Derives from Array (for more information about arrays in XAML, see x:Array Markup Extension.)
Implements IAddChild (an interface defined by WPF).
Each of these types in CLR has an Add method, which is used by the XAML processor to add items to the underlying collection when creating the object graph.
Note |
---|
The generic List and Dictionary interfaces (IList<T> and IDictionary<TKey, TValue>) are not supported for collection detection by the WPF XAML processor. However, you can use the List<T> class as a base class, because it implements IList directly, or Dictionary<TKey, TValue> as a base class, because it implements IDictionary directly. |
When you declare a property that takes a collection, be cautious about how that property value is initialized in new instances of the type. If you are not implementing the property as a dependency property, then having the property use a backing field that calls the collection type constructor is adequate. If your property is a dependency property, then you may need to initialize the collection property as part of the default type constructor. This is because a dependency property takes its default value from metadata, and you typically do not want the initial value of a collection property to be a static, shared collection. There should be a collection instance per each containing type instance. For more information, see Custom Dependency Properties.
You can implement a custom collection type for your collection property. Because of implicit collection property treatment, the custom collection type does not need to provide a default constructor in order to be used in XAML implicitly. However, you can optionally provide a default constructor for the collection type. This can be a worthwhile practice. Unless you do provide a default constructor, you cannot explicitly declare the collection as an object element. Some markup authors might prefer to see the explicit collection as a matter of markup style. Also, a default constructor can simplify the initialization requirements when you create new objects that use your collection type as a property value.
Declaring XAML Content Properties
The XAML language defines the concept of a XAML content property. Each class that is usable in object syntax can have exactly one XAML content property. To declare a property to be the XAML content property for your class, apply the ContentPropertyAttribute as part of the class definition. Specify the name of the intended XAML content property as the Name in the attribute. The property is specified as a string by name, not as a reflection construct such asPropertyInfo.
You can specify a collection property to be the XAML content property. This results in a usage for that property whereby the object element can have one or more child elements, without any intervening collection object elements or property element tags. These elements are then treated as the value for the XAML content property and added to the backing collection instance.
Some existing XAML content properties use the property type of Object. This enables a XAML content property that can take primitive values such as a String as well as taking a single reference object value. If you follow this model, your type is responsible for type determination as well as the handling of possible types. The typical reason for an Object content type is to support both a simple means of adding object content as a string (which receives a default presentation treatment), or an advanced means of adding object content that specifies a non-default presentation or additional data.
Serializing XAML
For certain scenarios, such as if you are a control author, you may also want to assure that any object representation that can be instantiated in XAML can also be serialized back to equivalent XAML markup. Serialization requirements are not described in this topic. See Control Authoring Overview and Element Tree and Serialization.
Markup Extensions and WPF XAML
This topic introduces the concept of markup extensions for XAML, including their syntax rules, purpose, and the class object model that underlies them. Markup extensions are a general feature of the XAML language and of the .NET implementation of XAML services. This topic specifically details markup extensions for use in WPF XAML.
XAML Processors and Markup Extensions
Generally speaking, a XAML parser can either interpret an attribute value as a literal string that can be converted to a primitive, or convert it to an object by some means. One such means is by referencing a type converter; this is documented in the topic TypeConverters and XAML. However, there are scenarios where different behavior is required. For example, a XAML processor can be instructed that a value of an attribute should not result in a new object in the object graph. Instead, the attribute should result in an object graph that makes a reference to an already constructed object in another part of the graph, or a static object. Another scenario is that a XAML processor can be instructed to use a syntax that provides non-default arguments to the constructor of an object. These are the types of scenarios where a markup extension can provide the solution.
Basic Markup Extension Syntax
A markup extension can be implemented to provide values for properties in an attribute usage, properties in a property element usage, or both.
When used to provide an attribute value, the syntax that distinguishes a markup extension sequence to a XAML processor is the presence of the opening and closing curly braces ({ and }). The type of markup extension is then identified by the string token immediately following the opening curly brace.
When used in property element syntax, a markup extension is visually the same as any other element used to provide a property element value: a XAML element declaration that references the markup extension class as an element, enclosed within angle brackets (<>).
XAML-Defined Markup Extensions
Several markup extensions exist that are not specific to the WPF implementation of XAML, but are instead implementations of intrinsics or features of XAML as a language. These markup extensions are implemented in the System.Xaml assembly as part of the general .NET Framework XAML services, and are within the XAML language XAML namespace. In terms of common markup usage, these markup extensions are typically identifiable by the x: prefix in the usage. The MarkupExtension base class (also defined in System.Xaml) provides the pattern that all markup extensions should use in order to be supported in XAML readers and XAML writers, including in WPF XAML.
x:Type supplies the Type object for the named type. This facility is used most frequently in styles and templates. For details, see x:Type Markup Extension.
x:Static produces static values. The values come from value-type code entities that are not directly the type of a target property's value, but can be evaluated to that type. For details, see x:Static Markup Extension.
x:Null specifies null as a value for a property and can be used either for attributes or property element values. For details, see x:Null Markup Extension.
x:Array provides support for creation of general arrays in XAML syntax, for cases where the collection support provided by WPF base elements and control models is deliberately not used. For details, see x:Array Markup Extension.
Note |
---|
The x: prefix is used for the typical XAML namespace mapping of the XAML language intrinsics, in the root element of a XAML file or production. For example, the Visual Studio templates for WPF applications initiate a XAML file using this x: mapping. You could choose a different prefix token in your own XAML namespace mapping, but this documentation will assume the default x: mapping as a means of identifying those entities that are a defined part of the XAML namespace for the XAML language, as opposed to the WPF default namespace or other XAML namespaces not related to a specific framework. |
WPF-Specific Markup Extensions
The most common markup extensions used in WPF programming are those that support resource references (StaticResource andDynamicResource), and those that support data binding (Binding).
StaticResource provides a value for a property by substituting the value of an already defined resource. A StaticResource evaluation is ultimately made at XAML load time and does not have access to the object graph at run time. For details, see StaticResource Markup Extension.
DynamicResource provides a value for a property by deferring that value to be a run-time reference to a resource. A dynamic resource reference forces a new lookup each time that such a resource is accessed and has access to the object graph at run time. In order to get this access, DynamicResource concept is supported by dependency properties in the WPF property system, and evaluated expressions. Therefore you can only use DynamicResource for a dependency property target. For details, see DynamicResource Markup Extension.
Binding provides a data bound value for a property, using the data context that applies to the parent object at run time. This markup extension is relatively complex, because it enables a substantial inline syntax for specifying a data binding. For details, see Binding Markup Extension.
RelativeSource provides source information for a Binding that can navigate several possible relationships in the run-time object tree. This provides specialized sourcing for bindings that are created in multi-use templates or created in code without full knowledge of the surrounding object tree. For details, see RelativeSource MarkupExtension.
TemplateBinding enables a control template to use values for templated properties that come from object-model-defined properties of the class that will use the template. In other words, the property within the template definition can access a context that only exists once the template is applied. For details, see TemplateBinding Markup Extension. For more information on the practical use of TemplateBinding, seeStyling with ControlTemplates Sample.
ColorConvertedBitmap supports a relatively advanced imaging scenario. For details, see ColorConvertedBitmap Markup Extension.
ComponentResourceKey and ThemeDictionary support aspects of resource lookup, particularly for resources and themes that are packaged with custom controls. For more information, see ComponentResourceKey Markup Extension, ThemeDictionary Markup Extension, or Control Authoring Overview.
*Extension Classes
For both the general XAML language and WPF-specific markup extensions, the behavior of each markup extension is identified to a XAML processor through a *Extension class that derives from MarkupExtension, and provides an implementation of the ProvideValue method. This method on each extension provides the object that is returned when the markup extension is evaluated. The returned object is typically evaluated based on the various string tokens that are passed to the markup extension.
For example, the StaticResourceExtension class provides the surface implementation of actual resource lookup so that its ProvideValueimplementation returns the object that is requested, with the input of that particular implementation being a string that is used to look up the resource by its x:Key. Much of this implementation detail is unimportant if you are using an existing markup extension.
Some markup extensions do not use string token arguments. This is either because they return a static or consistent value, or because context for what value should be returned is available through one of the services passed through the serviceProvider parameter.
The *Extension naming pattern is for convenience and consistency. It is not necessary in order for a XAML processor to identify that class as support for a markup extension. So long as your codebase includes System.Xaml and uses .NET Framework XAML Services implementations, all that is necessary to be recognized as a XAML markup extension is to derive from MarkupExtension and to support a construction syntax. WPF defines markup extension-enabling classes that do not follow the *Extension naming pattern, for example Binding. Typically the reason for this is that the class supports scenarios beyond pure markup extension support. In the case of Binding, that class supports run-time access to methods and properties of the object for scenarios that have nothing to do with XAML.
Extension Class Interpretation of Initialization Text
The string tokens following the markup extension name and still within the braces are interpreted by a XAML processor in one of the following ways:
A comma always represents the separator or delimiter of individual tokens.
If the individual separated tokens do not contain any equals signs, each token is treated as a constructor argument. Each constructor parameter must be given as the type expected by that signature, and in the proper order expected by that signature.
Note A XAML processor must call the constructor that matches the argument count of the number of pairs. For this reason, if you are implementing a custom markup extension, do not provide multiple parameters with the same argument count. The behavior for how a XAML processor behaves if more than one markup extension constructor path with the same parameter count exists is not defined, but you should anticipate that a XAML processor is permitted to throw an exception on usage if this situation exists in the markup extension type definitions.
If the individual separated tokens contain equals signs, then a XAML processor first calls the default constructor for the markup extension. Then, each name=value pair is interpreted as a property name that exists on the markup extension, and a value to assign to that property.
If there is a parallel result between the constructor behavior and the property setting behavior in a markup extension, it does not matter which behavior you use. It is more common usage to use the property=value pairs for markup extensions that have more than one settable property, if only because it makes your markup more intentional and you are less likely to accidentally transpose constructor parameters. (When you specify property=value pairs, those properties may be in any order.) Also, there is no guarantee that a markup extension supplies a constructor parameter that sets every one of its settable properties. For example, Binding is a markup extension, with many properties that are settable through the extension in property=value form, but Binding only supports two constructors: a default constructor, and one that sets an initial path.
A literal comma cannot be passed to a markup extension without escapement.
Escape Sequences and Markup Extensions
Attribute handling in a XAML processor uses the curly braces as indicators of a markup extension sequence. It is also possible to produce a literal curly brace character attribute value if necessary, by entering an escape sequence using an empty curly brace pair followed by the literal curly brace. See {} Escape Sequence / Markup Extension.
Nesting Markup Extensions in XAML Usage
Nesting of multiple markup extensions is supported, and each markup extension will be evaluated deepest first. For example, consider the following usage:
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
In this usage, the x:Static statement is evaluated first and returns a string. That string is then used as the argument for DynamicResource.
Markup Extensions and Property Element Syntax
When used as an object element that fills a property element value, a markup extension class is visually indistinguishable from a typical type-backed object element that can be used in XAML. The practical difference between a typical object element and a markup extension is that the markup extension is either evaluated to a typed value or deferred as an expression. Therefore the mechanisms for any possible type errors of property values for the markup extension will be different, similar to how a late-bound property is treated in other programming models. An ordinary object element will be evaluated for type match against the target property it is setting when the XAML is parsed.
Most markup extensions, when used in object element syntax to fill a property element, would not have content or any further property element syntax within. Thus you would close the object element tag, and provide no child elements. Whenever any object element is encountered by a XAML processor, the constructor for that class is called, which instantiates the object created from the parsed element. A markup extension class is no different: if you want your markup extension to be usable in object element syntax, you must provide a default constructor. Some existing markup extensions have at least one required property value that must be specified for effective initialization. If so, that property value is typically given as a property attribute on the object element. In the XAML Namespace (x:) Language Features and WPF XAML Extensions reference pages, markup extensions that have required properties (and the names of required properties) will be noted. Reference pages will also note if either object element syntax or attribute syntax is disallowed for particular markup extensions. A notable case is x:Array Markup Extension, which cannot support attribute syntax because the contents of that array must be specified within the tagging as content. The array contents are handled as general objects, therefore no default type converter for the attribute is feasible. Also, x:Array Markup Extension requires a type parameter.
XAML Namespaces and Namespace Mapping for WPF XAML
This topic further explains the presence and purpose of the two XAML namespace mappings as often found in the root tag of a WPF XAML file. It also describes how to produce similar mappings for using elements that are defined in your own code, and/or within separate assemblies.
What is a XAML Namespace?
A XAML namespace is really an extension of the concept of an XML namespace. The techniques of specifying a XAML namespace rely on the XML namespace syntax, the convention of using URIs as namespace identifiers, using prefixes to provide a means to reference multiple namespaces from the same markup source, and so on. The primary concept that is added to the XAML definition of the XML namespace is that a XAML namespace implies both a scope of uniqueness for the markup usages, and also influences how markup entities are potentially backed by specific CLR namespaces and referenced assemblies. This latter consideration is also influenced by the concept of a XAML schema context. But for purposes of how WPF works with XAML namespaces, you can generally think of XAML namespaces in terms of a default XAML namespace, the XAML language namespace, and any further XAML namespaces as mapped by your XAML markup directly to specific backing CLR namespaces and referenced assemblies.
The WPF and XAML Namespace Declarations
Within the namespace declarations in the root tag of many XAML files, you will see that there are typically two XML namespace declarations. The first declaration maps the overall WPF client / framework XAML namespace as the default:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
The second declaration maps a separate XAML namespace, mapping it (typically) to the x: prefix.
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
The relationship between these declarations is that the x: prefix mapping supports the intrinsics that are part of the XAML language definition, and WPF is one implementation that uses XAML as a language and defines a vocabulary of its objects for XAML. Because the WPF vocabulary's usages will be far more common than the XAML intrinsics usages, the WPF vocabulary is mapped as the default.
The x: prefix convention for mapping the XAML language intrinsics support is followed by project templates, sample code, and the documentation of language features within this SDK. The XAML namespace defines many commonly-used features that are necessary even for basic WPF applications. For instance, in order to join any code-behind to a XAML file through a partial class, you must name that class as the x:Class attribute in the root element of the relevant XAML file. Or, any element as defined in a XAML page that you wish to access as a keyed resource should have the x:Keyattribute set on the element in question. For more information on these and other aspects of XAML see XAML Overview (WPF) or XAML Syntax In Detail.
Mapping to Custom Classes and Assemblies
You can map XML namespaces to assemblies using a series of tokens within an xmlns prefix declaration, similar to how the standard WPF and XAML-intrinsics XAML namespaces are mapped to prefixes.
The syntax takes the following possible named tokens and following values:
clr-namespace: The CLR namespace declared within the assembly that contains the public types to expose as elements.
assembly= The assembly that contains some or all of the referenced CLR namespace. This value is typically just the name of the assembly, not the path, and does not include the extension (such as .dll or .exe). The path to that assembly must be established as a project reference in the project file that contains the XAML you are trying to map. In order to incorporate versioning and strong-name signing, the assembly value can be a string as defined by AssemblyName, rather than the simple string name.
Note that the character separating the clr-namespace token from its value is a colon (:) whereas the character separating the assembly token from its value is an equals sign (=). The character to use between these two tokens is a semicolon. Also, do not include any whitespace anywhere in the declaration.
A Basic Custom Mapping Example
The following code defines an example custom class:
namespace SDKSample { public class ExampleClass : ContentControl { public ExampleClass() { ... } } }
This custom class is then compiled into a library, which per the project settings (not shown) is named SDKSampleLibrary.
In order to reference this custom class, you also need to include it as a reference for your current project, which you would typically do using the Solution Explorer UI in Visual Studio.
Now that you have a library containing a class, and a reference to it in project settings, you can add the following prefix mapping as part of your root element in XAML:
xmlns:custom="clr-namespace:SDKSample;assembly=SDKSampleLibrary"
To put it all together, the following is XAML that includes the custom mapping along with the typical default and x: mappings in the root tag, then uses a prefixed reference to instantiate ExampleClass in that UI:
<Page x:Class="WPFApplication1.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:custom="clr-namespace:SDKSample;assembly=SDKSampleLibrary"> ... <custom:ExampleClass/> ... </Page>
Mapping to Current Assemblies
assembly can be omitted if the clr-namespace referenced is being defined within the same assembly as the application code that is referencing the custom classes. Or, an equivalent syntax for this case is to specify assembly=, with no string token following the equals sign.
Custom classes cannot be used as the root element of a page if defined in the same assembly. Partial classes do not need to be mapped; only classes that are not the partial class of a page in your application need to be mapped if you intend to reference them as elements in XAML.
Mapping CLR Namespaces to XML Namespaces in an Assembly
WPF defines a CLR attribute that is consumed by XAML processors in order to map multiple CLR namespaces to a single XAML namespace. This attribute, XmlnsDefinitionAttribute, is placed at the assembly level in the source code that produces the assembly. The WPF assembly source code uses this attribute to map the various common namespaces, such as System.Windows and System.Windows.Controls, to the http://schemas.microsoft.com/winfx/2006/xaml/presentation namespace.
The XmlnsDefinitionAttribute takes two parameters: the XML/XAML namespace name, and the CLR namespace name. More than oneXmlnsDefinitionAttribute can exist to map multiple CLR namespaces to the same XML namespace. Once mapped, members of those namespaces can also be referenced without full qualification if desired by providing the appropriate using statement in the partial-class code-behind page. For more details, see XmlnsDefinitionAttribute.
Designer Namespaces and Other Prefixes From XAML Templates
If you are working with development environments and/or design tools for WPF XAML, you may notice that there are other defined XAML namespaces / prefixes within the XAML markup.
WPF Designer for Visual Studio uses a designer namespace that is typically mapped to the prefix d:. More recent project templates for WPF might pre-map this XAML namespace to support interchange of the XAML between WPF Designer for Visual Studio and other design environments. This design XAML namespace is used to perpetuate design state while roundtripping XAML-based UI in the designer. It is also used for features such asd:IsDataSource, which enable runtime data sources in a designer.
Another prefix you might see mapped is mc:. mc: is for markup compatibility, and is leveraging a markup compatibility pattern that is not necessarily XAML-specific. To some extent, the markup compatibility features can be used to exchange XAML between frameworks or across other boundaries of backing implementation, work between XAML schema contexts, provide compatibility for limited modes in designers, and so on. For more information on markup compatibility concepts and how they relate to WPF, see Markup Compatibility (mc:) Language Features.
WPF and Assembly Loading
The XAML schema context for WPF integrates with the WPF application model, which in turn uses the CLR-defined concept of AppDomain. The following sequence describes how XAML schema context interprets how to either load assemblies or find types at run time or design time, based on the WPF use of AppDomain and other factors.
Iterate through the AppDomain, looking for an already-loaded assembly that matches all aspects of the name, starting from the most recently loaded assembly.
If the name is qualified, call Assembly.Load(String) on the qualified name.
If the short name + public key token of a qualified name matches the assembly that the markup was loaded from, return that assembly.
Use the short name + public key token to call Assembly.Load(String).
If the name is unqualified, call Assembly.LoadWithPartialName.
Loose XAML does not use Step 3; there is no loaded-from assembly.
Compiled XAML for WPF (generated via XamlBuildTask) does not use the already-loaded assemblies from AppDomain (Step 1). Also, the name should never be unqualified from XamlBuildTask output, so Step 5 does not apply.
Compiled BAML (generated via PresentationBuildTask) uses all steps, although BAML also should not contain unqualified assembly names.
WPF XAML Namescopes
XAML namescopes are a concept that identifies objects that are defined in XAML. The names in a XAML namescope can be used to establish relationships between the XAML-defined names of objects and their instance equivalents in an object tree. Typically, XAML namescopes in WPF managed code are created when loading the individual XAML page roots for a XAML application. XAML namescopes as the programming object are defined by the INameScope interface and are also implemented by the practical class NameScope.
Namescopes in Loaded XAML Applications
In a broader programming or computer science context, programming concepts often include the principle of a unique identifier or name that can be used to access an object. For systems that use identifiers or names, the namescope defines the boundaries within which a process or technique will search if an object of that name is requested, or the boundaries wherein uniqueness of identifying names is enforced. These general principles are true for XAML namescopes. In WPF, XAML namescopes are created on the root element for a XAML page when the page is loaded. Each name specified within the XAML page starting at the page root is added to a pertinent XAML namescope.
In WPF XAML, elements that are common root elements (such as Page, and Window) always control a XAML namescope. If an element such asFrameworkElement or FrameworkContentElement is the root element of the page in markup, a XAML processor adds a Page root implicitly so that the Page can provide a working XAML namescope.
Note |
---|
WPF build actions create a XAML namescope for a XAML production even if no Name or x:Name attributes are defined on any elements in the XAML markup. |
If you try to use the same name twice in any XAML namescope, an exception is raised. For WPF XAML that has code-behind and is part of a compiled application, the exception is raised at build time by WPF build actions, when creating the generated class for the page during the initial markup compile. For XAML that is not markup-compiled by any build action, exceptions related to XAML namescope issues might be raised when the XAML is loaded. XAML designers might also anticipate XAML namescope issues at design time.
Adding Objects to Runtime Object Trees
The moment that XAML is parsed represents the moment in time that a WPF XAML namescope is created and defined. If you add an object to an object tree at a point in time after the XAML that produced that tree was parsed, a Name or x:Name value on the new object does not automatically update the information in a XAML namescope. To add a name for an object into a WPF XAML namescope after XAML is loaded, must call the appropriate implementation of RegisterName on the object that defines the XAML namescope, which is typically the XAML page root. If the name is not registered, the added object cannot be referenced by name through methods such as FindName, and you cannot use that name for animation targeting.
The most common scenario for application developers is that you will use RegisterName to register names into the XAML namescope on the current root of the page. RegisterName is part of an mportant scenario for storyboards that target objects for animations. For more information, see Storyboards Overview.
If you call RegisterName on an object other than the object that defines the XAML namescope, the name is still registered to the XAML namescope that the calling object is held within, as if you had called RegisterName on the XAML namescope defining object.
XAML Namescopes in Code
You can create and then use XAML namescopes in code. The APIs and the concepts involved in XAML namescope creation are the same even for a pure code usage, because the XAML processor for WPF uses these APIs and concepts when it processes XAML itself. The concepts and API exist mainly for the purpose of being able to find objects by name within an object tree that is typically defined partially or entirely in XAML.
For applications that are created programmatically, and not from loaded XAML, the object that defines a XAML namescope must implementINameScope, or be a FrameworkElement or FrameworkContentElement derived class, in order to support creation of a XAML namescope on its instances.
Also, for any element that is not loaded and processed by a XAML processor, the XAML namescope for the object is not created or initialized by default. You must explicitly create a new XAML namescope for any object that you intend to register names into subsequently. To create a XAML namescope, you call the static SetNameScope method. Specify the object that will own it as the dependencyObject parameter, and a newNameScope constructor call as the value parameter.
If the object provided as dependencyObject for SetNameScope is not a INameScope implementation, FrameworkElement orFrameworkContentElement, calling RegisterName on any child elements will have no effect. If you fail to create the new XAML namescope explicitly, then calls to RegisterName will raise an exception.
For an example of using XAML namescope APIs in code, see How to: Define a Name Scope.
XAML Namescopes in Styles and Templates
Styles and templates in WPF provide the ability to reuse and reapply content in a straightforward way. However, styles and templates might also include elements with XAML names defined at the template level. That same template might be used multiple times in a page. For this reason, styles and templates both define their own XAML namescopes, independent of whatever location in an object tree where the style or template is applied.
Consider the following example:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > <Page.Resources> <ControlTemplate x:Key="MyButtonTemplate" TargetType="{x:Type Button}"> <Border BorderBrush="Red" Name="TheBorder" BorderThickness="2"> <ContentPresenter/> </Border> </ControlTemplate> </Page.Resources> <StackPanel> <Button Template="{StaticResource MyButtonTemplate}">My first button</Button> <Button Template="{StaticResource MyButtonTemplate}">My second button</Button> </StackPanel> </Page>
Here, the same template is applied to two different buttons. If templates did not have discrete XAML namescopes, the TheBorder name used in the template would cause a name collision in the XAML namescope. Each instantiation of the template has its own XAML namescope, so in this example each instantiated template's XAML namescope would contain exactly one name.
Styles also define their own XAML namescope, mostly so that parts of storyboards can have particular names assigned. These names enable control specific behaviors that will target elements of that name, even if the template was re-defined as part of control customization.
Because of the separate XAML namescopes, finding named elements in a template is more challenging than finding a non-templated named element in a page. You first need to determine the applied template, by getting the Template property value of the control where the template is applied. Then, you call the template version of FindName, passing the control where the template was applied as the second parameter.
If you are a control author and you are generating a convention where a particular named element in an applied template is the target for a behavior that is defined by the control itself, you can use the GetTemplateChild method from your control implementation code. The GetTemplateChildmethod is protected, so only the control author has access to it.
If you are working from within a template, and need to get to the XAML namescope where the template is applied, get the value of TemplatedParent, and then call FindName there. An example of working within the template would be if you are writing the event handler implementation where the event will be raised from an element in an applied template.
XAML Namescopes and Name-related APIs
FrameworkElement has FindName, RegisterName and UnregisterName methods. If the object you call these methods on owns a XAML namescope, the methods call into the methods of the relevant XAML namescope. Otherwise, the parent element is checked to see if it owns a XAML namescope, and this process continues recursively until a XAML namescope is found (because of the XAML processor behavior, there is guaranteed to be a XAML namescope at the root). FrameworkContentElement has analogous behaviors, with the exception that no FrameworkContentElement will ever own a XAML namescope. The methods exist on FrameworkContentElement so that the calls can be forwarded eventually to a FrameworkElement parent element.
SetNameScope is used to map a new XAML namescope to an existing object. You can call SetNameScope more than once in order to reset or clear the XAML namescope, but that is not a common usage. Also, GetNameScope is not typically used from code.
XAML Namescope Implementations
The following classes implement INameScope directly:
ResourceDictionary does not use XAML names or namescopes ; it uses keys instead, because it is a dictionary implementation. The only reason that ResourceDictionary implements INameScope is so it can raise exceptions to user code that help clarify the distinction between a true XAML namescope and how a ResourceDictionary handles keys, and also to assure that XAML namescopes are not applied to a ResourceDictionary by parent elements.
FrameworkTemplate and Style implement INameScope through explicit interface definitions. The explicit implementations allow these XAML namescopes to behave conventionally when they are accessed through the INameScope interface, which is how XAML namescopes are communicated by WPF internal processes. But the explicit interface definitions are not part of the conventional API surface of FrameworkTemplateand Style, because you seldom need to call the INameScope methods on FrameworkTemplate and Style directly, and instead would use other API such as GetTemplateChild.
The following classes define their own XAML namescope, by using the System.Windows.NameScope helper class and connecting to its XAML namescope implementation through the NameScope.NameScope attached property:
Inline Styles and Templates
Windows Presentation Foundation (WPF) provides Style objects and template objects (FrameworkTemplate subclasses) as a way to define the visual appearance of an element in resources, so that they can be used multiple times. For this reason, attributes in XAML that take the types Style andFrameworkTemplate almost always make resource references to existing styles and templates rather than define new ones inline.
Limitations of Inline Styles and Templates
In Extensible Application Markup Language (XAML), style and template properties can technically be set in one of two ways. You can use attribute syntax to reference a style that was defined within a resource, for example <object Style="{StaticResource myResourceKey}" .../>. Or you can use property element syntax to define a style inline, for instance:
<object>
<object.Style>
<Style .../>
</object.Style>
</object>
The attribute usage is much more common. A style that is defined inline and not defined in resources is necessarily scoped to the containing element only, and cannot be re-used as easily because it has no resource key. In general a resource-defined style is more versatile and useful, and is more in keeping with the general Windows Presentation Foundation (WPF) programming model principle of separating program logic in code from design in markup.
Usually there is no reason to set a style or template inline, even if you only intend to use that style or template in that location. Most elements that can take a style or template also support a content property and a content model. If you are only using whatever logical tree you create through styling or templating once, it would be even easier to just fill that content property with the equivalent child elements in direct markup. This would bypass the style and template mechanisms altogether.
Other syntaxes enabled by markup extensions that return an object are also possible for styles and templates. Two such extensions that have possible scenarios include TemplateBinding and Binding.
TypeConverters and XAML
This topic introduces the purpose of type conversion from string as a general XAML language feature. In the .NET Framework, the TypeConverter class serves a particular purpose as part of the implementation for a managed custom class that can be used as a property value in XAML attribute usage. If you write a custom class, and you want instances of your class to be usable as XAML settable attribute values, you might need to apply aTypeConverterAttribute to your class, write a custom TypeConverter class, or both.
Type Conversion Concepts
XAML and String Values
When you set an attribute value in a XAML file, the initial type of that value is a string in pure text. Even other primitives such as Double are initially text strings to a XAML processor.
A XAML processor needs two pieces of information in order to process an attribute value. The first piece of information is the value 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 that is understood by the XAML parser (such as a numeric value), a direct conversion of the string is attempted. If the value is an enumeration, the string is used to check for a name match to a named constant in that enumeration. If the value is neither a parser-understood primitive nor 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. This is done by indicating a type converter class. The type converter is effectively a helper class for providing values of another class, both for the XAML scenario and also potentially for code calls in .NET code.
Using Existing Type Conversion Behavior in XAML
Depending on your familiarity with the underlying XAML concepts, you may already be using type conversion behavior in basic application XAML without realizing it. For instance, WPF defines literally hundreds of properties that take a value of type Point. A Point is a value that describes a coordinate in a two-dimensional coordinate space, and it really just has two important properties: X and Y. When you specify a point in XAML, you specify it as a string with a delimiter (typically a comma) between the X and Y values you provide. For example: <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">.
Even this simple type of Point and its simple usage in XAML involve a type converter. In this case that is the class PointConverter.
The type converter for Point defined at the class level streamlines the markup usages of all properties that take Point. Without a type converter here, you would need the following much more verbose markup for the same example shown previously:
<LinearGradientBrush>
<LinearGradientBrush.StartPoint>
<Point X="0" Y="0"/>
</LinearGradientBrush.StartPoint>
<LinearGradientBrush.EndPoint>
<Point X="1" Y="1"/>
</LinearGradientBrush.EndPoint>
<LinearGradientBrush>
Whether to use the type conversion string or a more verbose equivalent syntax is generally a coding style choice. Your XAML tooling workflow might also influence how values are set. Some XAML tools tend to emit the most verbose form of the markup because it is easier to round-trip to designer views or its own serialization mechanism.
Existing type converters can generally be discovered on WPF and .NET Framework types by checking a class (or property) for the presence of an applied TypeConverterAttribute. This attribute will name the class that is the supporting type converter for values of that type, for XAML purposes as well as potentially other purposes.
Type Converters and Markup Extensions
Markup extensions and type converters fill orthogonal roles in terms of XAML processor behavior and the scenarios that they are applied to. Although context is available for markup extension usages, type conversion behavior of properties where a markup extension provides a value is generally is not checked in the markup extension implementations. In other words, even if a markup extension returns a text string as itsProvideValue output, type conversion behavior on that string as applied to a specific property or property value type is not invoked, Generally, the purpose of a markup extension is to process a string and return an object without any type converter involved.
One common situation where a markup extension is necessary rather than a type converter is to make a reference to an object that already exists. At best, a stateless type converter could only generate a new instance, which might not be desirable. For more information on markup extensions, see Markup Extensions and WPF XAML.
Native Type Converters
In the WPF and .NET Framework implementation of the XAML parser, there are certain types that have native type conversion handling, yet are not types that might conventionally be thought of as primitives. An example of such a type is DateTime. The reason for this is based on how the .NET Framework architecture works: the type DateTime is defined in mscorlib, the most basic library in .NET. DateTime is not permitted to be attributed with an attribute that comes from another assembly that introduces a dependency (TypeConverterAttribute is from System) so the usual type converter discovery mechanism by attributing cannot be supported. Instead, the XAML parser has a list of types that need such native processing and processes these similarly to how the true primitives are processed. (In the case of DateTime this involves a call to Parse.
Implementing a Type Converter
TypeConverter
In the Point example given previously, the class PointConverter was mentioned. For .NET implementations of XAML, all type converters that are used for XAML purposes are classes that derive from the base class TypeConverter. The TypeConverter class existed in versions of .NET Framework that precede the existence of XAML; one of its original usages was to provide string conversion for property dialogs in visual designers. For XAML, the role of TypeConverter is expanded to include being the base class for to-string and from-string conversions that enable parsing a string attribute value, and possibly processing a run-time value of a particular object property back into a string for serialization as an attribute.
TypeConverter defines four members that are relevant for converting to and from strings for XAML processing purposes:
Of these, the most important method is ConvertFrom. This method converts the input string to the required object type. Strictly speaking, theConvertFrom method could be implemented to convert a much wider range of types into the converter's intended destination type, and thus serve purposes that extend beyond XAML such as supporting run-time conversions, but for XAML purposes it is only the code path that can process a String input that matters.
The next most important method is ConvertTo. If an application is converted to a markup representation (for instance, if it is saved to XAML as a file), ConvertTo is responsible for producing a markup representation. In this case, the code path that matters for XAML is when you pass adestinationType of String .
CanConvertTo and CanConvertFrom are support methods that are used when a service queries the capabilities of the TypeConverterimplementation. You must implement these methods to return true for type-specific cases that the equivalent conversion methods of your converter support. For XAML purposes, this generally means the String type.
Culture Information and Type Converters for XAML
Each TypeConverter implementation can have its own interpretation of what constitutes a valid string for a conversion, and can also use or ignore the type description passed as parameters. There is an important consideration with regard to culture and XAML type conversion. Using localizable strings as attribute values is entirely supported by XAML. But using that localizable string as type converter input with specific culture requirements is not supported, because type converters for XAML attribute values involve a necessarily fixed-language parsing behavior, using en-US culture. For more information on the design reasons for this restriction, you should consult the XAML language specification ([MS-XAML]).
As an example where culture can be an issue, some cultures use a comma as their decimal point delimiter for numbers. This will collide with the behavior that many of the WPF XAML type converters have, which is to use a comma as a delimiter (based on historical precedents such as the common X,Y form, or comma delimited lists). Even passing a culture in the surrounding XAML (setting Language or xml:lang to the sl-SIculture, an example of a culture that uses a comma for decimal in this way) does not solve the issue.
Implementing ConvertFrom
To be usable as a TypeConverter implementation that supports XAML, the ConvertFrom method for that converter must accept a string as thevalue parameter. If the string was in valid format, and can be converted by the TypeConverter implementation, then the returned object must support a cast to the type expected by the property. Otherwise, the ConvertFrom implementation must return null.
Each TypeConverter implementation can have its own interpretation of what constitutes a valid string for a conversion, and can also use or ignore the type description or culture contexts passed as parameters. However, the WPF XAML processing might not pass values to the type description context in all cases, and also might not pass culture based on xml:lang.
Note |
---|
Do not use the curly brace characters, particularly {, as a possible element of your string format. These characters are reserved as the entry and exit for a markup extension sequence. |
Implementing ConvertTo
ConvertTo is potentially used for serialization support. Serialization support through ConvertTo for your custom type and its type converter is not an absolute requirement. However, if you are implementing a control, or using serialization of as part of the features or design of your class, you should implement ConvertTo.
To be usable as a TypeConverter implementation that supports XAML, the ConvertTo method for that converter must accept an instance of the type (or a value) being supported as the value parameter. When the destinationType parameter is the type String, then the returned object must be able to be cast as String. The returned string must represent a serialized value of value. Ideally, the serialization format you choose should be capable of generating the same value if that string were passed to the ConvertFrom implementation of the same converter, without significant loss of information.
If the value cannot be serialized, or the converter does not support serialization, the ConvertTo implementation must return null, and is permitted to throw an exception in this case. But if you do throw exceptions, you should report the inability to use that conversion as part of yourCanConvertTo implementation so that the best practice of checking with CanConvertTo first to avoid exceptions is supported.
If destinationType parameter is not of type String, you can choose your own converter handling. Typically, you would revert to base implementation handling, which in the basemost ConvertTo raises a specific exception.
Implementing CanConvertTo
Your CanConvertTo implementation should return true for destinationType of type String, and otherwise defer to the base implementation.
Implementing CanConvertFrom
Your CanConvertFrom implementation should return true for sourceType of type String, and otherwise defer to the base implementation.
Applying the TypeConverterAttribute
In order for your custom type converter to be used as the acting type converter for a custom class by a XAML processor, you must apply the .NET Framework attribute TypeConverterAttribute to your class definition. The ConverterTypeName that you specify through the attribute must be the type name of your custom type converter. With this attribute applied, when a XAML processor handles values where the property type uses your custom class type, it can input strings and return object instances.
You can also provide a type converter on a per-property basis. Instead of applying a .NET Framework attribute TypeConverterAttribute to the class definition, apply it to a property definition (the main definition, not the get/set implementations within it). The type of the property must match the type that is processed by your custom type converter. With this attribute applied, when a XAMLprocessor handles values of that property, it can process input strings and return object instances. The per-property type converter technique is particularly useful if you choose to use a property type from Microsoft .NET Framework or from some other library where you cannot control the class definition and cannot apply aTypeConverterAttribute there.
WPF XAML Extensions
Binding Markup Extension
Defers a property value to be a data-bound value, creating an intermediate expression object and interpreting the data context that applies to the element and its binding at run time.
Binding Expression Usage
<object property="{Binding}" .../> -or- <object property="{Binding bindProp1=value1[, bindPropN=valueN]*}" ... /> -or- <object property="{Binding path}" .../> -or <object property="{Binding path[, bindPropN=valueN]*}" .../>
Syntax Notes
In these syntaxes, the [] and * are not literals. They are part of a notation to indicate that zero or more bindProp=value pairs can be used, with a ,separator between them and preceding bindProp=value pairs.
Any of the properties listed in the "Binding Properties That Can Be Set with the Binding Extension" section could instead be set using attributes of aBinding object element. However, that is not truly the markup extension usage of Binding, it is just the general XAML processing of attributes that set properties of the CLR Binding class. In other words, <Binding bindProp1="value1"[ bindPropN="valueN"]*/> is an equivalent syntax for attributes ofBinding object element usage instead of a Binding expression usage. To learn about the XAML attribute usage of specific properties of Binding, see the "XAML Attribute Usage" section of the relevant property of Binding in the .NET Framework Class Library.
XAML Values
bindProp1, bindPropN | The name of the Binding or BindingBase property to set. Not all Binding properties can be set with the Binding extension, and some properties are settable within a Binding expression only by using further nested markup extensions. See "Binding Properties That Can Be Set with the Binding Extension" section. |
value1, valueN | The value to set the property to. The handling of the attribute value is ultimately specific to the type and logic of the specific Bindingproperty being set. |
path | The path string that sets the implicit Binding.Path property. See also PropertyPath XAML Syntax. |
Unqualified {Binding}
The {Binding} usage shown in "Binding Expression Usage" creates a Binding object with default values, which includes an initial Binding.Path of null. This is still useful in many scenarios, because the created Binding might be relying on key data binding properties such as Binding.Path andBinding.Source being set in the run-time data context. For more information on the concept of data context, see Data Binding (WPF).
Implicit Path
The Binding markup extension uses Binding.Path as a conceptual "default property", where Path= does not need to appear in the expression. If you specify a Binding expression with an implicit path, the implicit path must appear first in the expression, prior to any other bindProp=value pairs where the Binding property is specified by name. For example: {Binding PathString}, where PathString is a string that is evaluated to be the value ofBinding.Path in the Binding created by the markup extension usage. You can append an implicit path with other named properties after the comma separator, for example, {Binding LastName, Mode=TwoWay}.
Binding Properties That Can Be Set with the Binding Extension
The syntax shown in this topic uses the generic bindProp=value approximation, because there are many read/write properties of BindingBase or Bindingthat can be set through the Binding markup extension / expression syntax. They can be set in any order, with the exception of an implicit Binding.Path. (You do have the option to explicitly specify Path=, in which case it can be set in any order). Basically, you can set zero or more of the properties in the list below, using bindProp=value pairs separated by commas.
Several of these property values require object types that do not support a native type conversion from a text syntax in XAML, and thus require markup extensions in order to be set as an attribute value. Check the XAML Attribute Usage section in the .NET Framework Class Library for each property for more information; the string you use for XAML attribute syntax with or without further markup extension usage is basically the same as the value you specify in a Binding expression, with the exception that you do not place quotation marks around each bindProp=value in the Binding expression.
BindingGroupName: a string that identifies a possible binding group. This is a relatively advanced binding concept; see reference page forBindingGroupName.
BindsDirectlyToSource: Boolean, can be either true or false. The default is false.
Converter: can be set as a bindProp=value string in the expression, but to do so requires an object reference for the value, such as aStaticResource Markup Extension. The value in this case is an instance of a custom converter class.
ConverterCulture: settable in the expression as a standards-based identifier; see the reference topic for ConverterCulture.
ConverterParameter: can be set as a bindProp=value string in the expression, but this is dependent on the type of the parameter being passed. If passing a reference type for the value, this usage requires an object reference such as a nested StaticResource Markup Extension.
ElementName: mutually exclusive versus RelativeSource and Source; each of these binding properties represents a particular binding methodology. See Data Binding Overview.
FallbackValue: can be set as a bindProp=value string in the expression, but this is dependent on the type of the value being passed. If passing a reference type, requires an object reference such as a nested StaticResource Markup Extension.
IsAsync: Boolean, can be either true or false. The default is false.
Mode: value is a constant name from the BindingMode enumeration. For example, {Binding Mode=OneWay}.
NotifyOnSourceUpdated: Boolean, can be either true or false. The default is false.
NotifyOnTargetUpdated: Boolean, can be either true or false. The default is false.
NotifyOnValidationError: Boolean, can be either true or false. The default is false.
Path: a string that describes a path into a data object or a general object model. The format provides several different conventions for traversing an object model that cannot be adequately described in this topic. See PropertyPath XAML Syntax.
RelativeSource: mutually exclusive versus with ElementName and Source; each of these binding properties represents a particular binding methodology. See Data Binding Overview. Requires a nested RelativeSource MarkupExtension usage to specify the value.
Source: mutually exclusive versus RelativeSource and ElementName; each of these binding properties represents a particular binding methodology. See Data Binding Overview. Requires a nested extension usage, typically a StaticResource Markup Extension that refers to an object data source from a keyed resource dictionary.
StringFormat: a string that describes a string format convention for the bound data. This is a relatively advanced binding concept; see reference page for StringFormat.
TargetNullValue: can be set as a bindProp=value string in the expression, but this is dependent on the type of the parameter being passed. If passing a reference type for the value, requires an object reference such as a nested StaticResource Markup Extension.
UpdateSourceTrigger: value is a constant name from the UpdateSourceTrigger enumeration. For example, {Binding UpdateSourceTrigger=LostFocus}. Specific controls potentially have different default values for this binding property. SeeUpdateSourceTrigger.
ValidatesOnDataErrors: Boolean, can be either true or false. The default is false. See Remarks.
ValidatesOnExceptions: Boolean, can be either true or false. The default is false. See Remarks.
XPath: a string that describes a path into the XMLDOM of an XML data source. See How to: Bind to XML Data Using an XMLDataProvider and XPath Queries.
The following are properties of Binding that cannot be set using the Binding markup extension/{Binding} expression form.
UpdateSourceExceptionFilter: this property expects a reference to a callback implementation. Callbacks/methods other than event handlers cannot be referenced in XAML syntax.
ValidationRules: the property takes a generic collection of ValidationRule objects. This could be expressed as a property element in a Bindingobject element, but has no readily available attribute-parsing technique for usage in a Binding expression. See reference topic forValidationRules.
Remarks
Important |
---|
In terms of dependency property precedence, a Binding expression is equivalent to a locally set value. If you set a local value for a property that previously had a Binding expression, the Binding is completely removed. For details, see Dependency Property Value Precedence. |
Describing data binding at a basic level is not covered in this topic. See Data Binding Overview.
Note |
---|
MultiBinding and PriorityBinding do not support a XAML extension syntax. You would instead use property elements. See reference topics forMultiBinding and PriorityBinding. |
Boolean values for XAML are case insensitive. For example you could specify either {Binding NotifyOnValidationError=true} or{Binding NotifyOnValidationError=True}.
Bindings that involve data validation are typically specified by an explicit Binding element rather than as a {Binding ...} expression, and settingValidatesOnDataErrors or ValidatesOnExceptions in an expression is uncommon. This is because the companion property ValidationRules cannot be readily set in the expression form. For more information, see How to: Implement Binding Validation.
Binding is a markup extension. Markup extensions are typically implemented when there is a requirement to escape attribute values to be other than literal values or handler names, and the requirement is more global than type converters attributed on certain types or properties. All markup extensions in XAML use the { and } characters in their attribute syntax, which is the convention by which a XAML processor recognizes that a markup extension must process the string contents. For more information, see Markup Extensions and WPF XAML.
Binding is an atypical markup extension in that the Binding class that implements the extension functionality for WPF's XAML implementation also implements several other methods and properties that are not related to XAML. The other members are intended to make Binding a more versatile and self-contained class that can address many data binding scenarios in addition to functioning as a XAML markup extension.
ColorConvertedBitmap Markup Extension
Provides a way to specify a bitmap source that does not have an embedded profile. Color contexts / profiles are specified by URI, as is the image source URI.
XAML Attribute Usage
<object property="{ColorConvertedBitmap imageSource sourceIIC destinationIIC}" .../>
XAML Values
imageSource | The URI of the nonprofiled bitmap. |
sourceIIC | The URI of the source profile configuration. |
destinationIIC | The URI of the destination profile configuration |
Remarks
This markup extension is intended to fill a related set of image-source property values such as UriSource.
Attribute syntax is the most common syntax used with this markup extension. ColorConvertedBitmap (or ColorConvertedBitmapExtension) cannot be used in property element syntax, because the values can only be set as values on the initial constructor, which is the string following the extension identifier.
ColorConvertedBitmap is a markup extension. Markup extensions are typically implemented when there is a requirement to escape attribute values to be other than literal values or handler names, and the requirement is more global than just putting type converters on certain types or properties. All markup extensions in XAML use the { and } characters in their attribute syntax, which is the convention by which a XAML processor recognizes that a markup extension must process the attribute. For more information, see Markup Extensions and WPF XAML.
ComponentResourceKey Markup Extension
Defines and references keys for resources that are loaded from external assemblies. This enables a resource lookup to specify a target type in an assembly, rather than an explicit resource dictionary in an assembly or on a class.
XAML Attribute Usage (setting key, compact)
<object x:Key="{ComponentResourceKey {x:Type targetTypeName}, targetID}" .../>
XAML Attribute Usage (setting key, verbose)
<object x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type targetTypeName}, ResourceID=targetID}" .../>
XAML Attribute Usage (requesting resource, compact)
<object property="{DynamicResource {ComponentResourceKey {x:Type targetTypeName}, targetID}}" .../>
XAML Attribute Usage (requesting resource, verbose)
<object property="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type targetTypeName}, ResourceID=targetID}}" .../>
XAML Values
targetTypeName | The name of the public common language runtime (CLR) type that is defined in the resource assembly. |
targetID | The key for the resource. When resources are looked up, targetID will be analogous to the x:Key Directive of the resource. |
Remarks
As seen in the usages above, a {ComponentResourceKey} markup extension usage is found in two places:
The definition of a key within a theme resource dictionary, as provided by a control author.
Accessing a theme resource from the assembly, when you are retemplating the control but want to use property values that come from resources provided by the control's themes.
For referencing component resources that come from themes, it is generally recommended that you use {DynamicResource} rather than{StaticResource}. This is shown in the usages. {DynamicResource} is recommended because the theme itself can be changed by the user. If you want the component resource that most closely matches the control author's intent for supporting a theme, you should enable your component resource reference to be dynamic also.
The TypeInTargetAssembly identifies a type that exists in the target assembly where the resource is actually defined. A ComponentResourceKey can be defined and used independently of knowing exactly where the TypeInTargetAssembly is defined, but eventually must resolve the type through referenced assemblies.
A common usage for ComponentResourceKey is to define keys that are then exposed as members of a class. For this usage, you use theComponentResourceKey class constructor, not the markup extension. For more information, see ComponentResourceKey, or the "Defining and Referencing Keys for Theme Resources" section of the topic Control Authoring Overview.
For both establishing keys and referencing keyed resources, attribute syntax is commonly used for the ComponentResourceKey markup extension.
The compact syntax shown relies on the ComponentResourceKey.ComponentResourceKey constructor signature and positional parameter usage of a markup extension. The order in which the targetTypeName and targetID are given is important. The verbose syntax relies on theComponentResourceKey.ComponentResourceKey default constructor, and then sets the TypeInTargetAssembly and ResourceId in a way that is analogous to a true attribute syntax on an object element. In the verbose syntax, the order in which the properties are set is not important. The relationship and mechanisms of these two alternatives (compact and verbose) is described in more detail in the topic Markup Extensions and WPF XAML.
Technically, the value for targetID can be any object, it does not have to be a string. However, the most common usage in WPF is to align the targetIDvalue with forms that are strings, and where such strings are valid in the XamlName Grammar.
ComponentResourceKey can be used in object element syntax. In this case, specifying the value of both the TypeInTargetAssembly and ResourceIdproperties is required to properly initialize the extension.
In the WPF XAML reader implementation, the handling for this markup extension is defined by the ComponentResourceKey class.
ComponentResourceKey is a markup extension. Markup extensions are typically implemented when there is a requirement to escape attribute values to be other than literal values or handler names, and the requirement is more global than just putting type converters on certain types or properties. All markup extensions in XAML use the { and } characters in their attribute syntax, which is the convention by which a XAML processor recognizes that a markup extension must process the attribute. For more information, see Markup Extensions and WPF XAML.
DateTime XAML Syntax
Some controls, such as Calendar and DatePicker, have properties that use the DateTime type. Although you typically specify an initial date or time for these controls in the code-behind at run time, you can specify an initial date or time in XAML. The WPF XAML parser handles parsing of DateTime values using a built-in XAML text syntax. This topic describes the specifics of the DateTime XAML text syntax.
When To Use DateTime XAML Syntax
Setting dates in XAML is not always necessary and may not even be desirable. For example, you could use the DateTime.Now property to initialize a date at run time, or you could do all your date adjustments for a calendar in the code-behind based on user input. However, there are scenarios where you may want to hard-code dates into a Calendar and DatePicker in a control template. The DateTime XAML syntax must be used for these scenarios.
DateTime XAML Syntax is a Native Behavior
DateTime is a class that is defined in the base class libraries of the CLR. Because of how the base class libraries relate to the rest of the CLR, it is not possible to apply TypeConverterAttribute to the class and use a type converter to process strings from XAML and convert them to DateTime in the run time object model. There is no DateTimeConverter class that provides the conversion behavior; the conversion behavior described in this topic is native to the WPF XAML parser.
Format Strings for DateTime XAML Syntax
You can specify the format of a DateTime with a format string. Format strings formalize the text syntax that can be used to create a value. DateTimevalues for the existing WPF controls generally only use the date components of DateTime and not the time components.
When specifying a DateTime in XAML, you can use any of the format strings interchangeably.
You can also use formats and format strings that are not specifically shown in this topic. Technically, the XAML for any DateTime value that is specified and then parsed by the WPF XAML parser uses an internal call to DateTime.Parse, therefore you could use any string accepted by DateTime.Parse for your XAML input. For more information, see DateTime.Parse.
Important |
---|
The DateTime XAML syntax always uses en-us as the CultureInfo for its native conversion. This is not influenced by Language value or xml:lang value in the XAML, because XAML attribute-level type conversion acts without that context. Do not attempt to interpolate the format strings shown here due to cultural variations, such as the order in which day and month appear. The format strings shown here are the exact format strings used when parsing the XAML regardless of other culture settings. |
The following sections describe some of the common DateTime format strings.
Short Date Pattern ("d")
The following shows the short date format for a DateTime in XAML:
M/d/YYYY
This is the simplest form that specifies all necessary information for typical usages by WPF controls, and cannot be influenced by accidental time zone offsets versus a time component, and is therefore recommended over the other formats.
For example, to specify the date of June 1, 2010, use the following string:
3/1/2010
For more information, see DateTimeFormatInfo.ShortDatePattern.
Sortable DateTime Pattern ("s")
The following shows the sortable DateTime pattern in XAML:
yyyy'-'MM'-'dd'T'HH':'mm':'ss
For example, to specify the date of June 1, 2010, use the following string (time components are all entered as 0):
2010-06-01T000:00:00
RFC1123 Pattern ("r")
The RFC1123 pattern is useful because it could be a string input from other date generators that also use the RFC1123 pattern for culture invariant reasons. The following shows the RFC1123 DateTime pattern in XAML:
ddd, dd MMM yyyy HH':'mm':'ss 'UTC'
For example, to specify the date of June 1, 2010, use the following string (time components are all entered as 0):
Mon, 01 Jun 2010 00:00:00 UTC
Other Formats and Patterns
As stated previously, a DateTime in XAML can be specified as any string that is acceptable as input for DateTime.Parse. This includes other formalized formats (for example UniversalSortableDateTimePattern), and formats that are not formalized as a particular DateTimeFormatInfo form. For example, the form YYYY/mm/dd is acceptable as input for DateTime.Parse. This topic does not attempt to describe all possible formats that work, and instead recommends the short date pattern as a standard practice.
DynamicResource Markup Extension
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
<object property="{DynamicResource key}" .../>
XAML Property Element Usage
<object> <object.property> <DynamicResource ResourceKey="key" .../> </object.property> </object>
XAML Values
key | The key for the requested resource. This key was initially assigned by the x:Key Directive if a resource was created in markup, or was provided as the key parameter when calling ResourceDictionary.Add if the resource was created in code. |
Remarks
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. This may potentially be after the XAML page is loaded. The resource value will be found based on key search against all active resource dictionaries starting from the current page scope, and is substituted for the placeholder expression from compilation.
Important |
---|
In terms of dependency property precedence, a DynamicResource expression is equivalent to the position where the dynamic resource reference is applied. If you set a local value for a property that previously had a DynamicResource expression as the local value, the DynamicResource is completely removed. For details, see Dependency Property Value Precedence. |
Certain resource access scenarios are particularly appropriate for DynamicResource as opposed to a StaticResource Markup Extension. See XAML Resources for a discussion about the relative merits and performance implications of DynamicResource and StaticResource.
The specified ResourceKey should correspond to an existing resource determined by x:Key Directive at some level in your page, application, the available control themes and external resources, or system resources, and the resource lookup will happen in that order. For more information about resource lookup for static and dynamic resources, see XAML Resources.
A resource key may be any string defined in the XamlName Grammar. A resource key may also be other object types, such as a Type. A Type key is fundamental to how controls can be styled by themes. For more information, see Control Authoring Overview.
APIs for lookup of resource values, such as FindResource, follow the same resource lookup logic as used by DynamicResource.
The alternative declarative means of referencing a resource is as a StaticResource Markup Extension.
Attribute syntax is the most common syntax used with this markup extension. The string token provided after the DynamicResource identifier string is assigned as the ResourceKey value of the underlying DynamicResourceExtension extension class.
DynamicResource can be used in object element syntax. In this case, specifying the value of the ResourceKey property is required.
DynamicResource can also be used in a verbose attribute usage that specifies the ResourceKey property as a property=value pair:
<object property="{DynamicResource ResourceKey=key}" .../>
The verbose usage is often useful for extensions that have more than one settable property, or if some properties are optional. BecauseDynamicResource has only one settable property, which is required, this verbose usage is not typical.
In the WPF XAML processor implementation, the handling for this markup extension is defined by the DynamicResourceExtension class.
DynamicResource is a markup extension. Markup extensions are typically implemented when there is a requirement to escape attribute values to be other than literal values or handler names, and the requirement is more global than just putting type converters on certain types or properties. All markup extensions in XAML use the { and } characters in their attribute syntax, which is the convention by which a XAML processor recognizes that a markup extension must process the attribute. For more information, see Markup Extensions and WPF XAML.
RelativeSource MarkupExtension
Specifies properties of a RelativeSource binding source, to be used within a Binding Markup Extension, or when setting the RelativeSource property of aBinding element established in XAML.
XAML Attribute Usage
<Binding RelativeSource="{RelativeSource modeEnumValue}" .../>
XAML Attribute Usage (nested within Binding extension)
<object property="{Binding RelativeSource={RelativeSource modeEnumValue} ...}" .../>
XAML Object Element Usage
<Binding> <Binding.RelativeSource> <RelativeSource Mode="modeEnumValue"/> </Binding.RelativeSource> </Binding> - or <Binding> <Binding.RelativeSource> <RelativeSource Mode="FindAncestor" AncestorType="{x:Type typeName}" AncestorLevel="intLevel" /> </Binding.RelativeSource> </Binding>
XAML Values
modeEnumValue | One of the following:
|
FindAncestor | The string token FindAncestor. Using this token enters a mode whereby a RelativeSource specifies an ancestor type and optionally an ancestor level. This corresponds to a RelativeSource as created with its Mode property set to FindAncestor. |
typeName | Required for FindAncestor mode. The name of a type, which fills the AncestorType property. |
intLevel | Optional for FindAncestor mode. An ancestor level (evaluated towards the parent direction in the logical tree). |
Remarks
{RelativeSource TemplatedParent} binding usages are a key technique that addresses a larger concept of the separation of a control's UI and a control's logic. This enables binding from within the template definition to the templated parent (the run time object instance where the template is applied). For this case, the TemplateBinding Markup Extension is in fact a shorthand for the following binding expression: {Binding RelativeSource={RelativeSource TemplatedParent}}. TemplateBinding or {RelativeSource TemplatedParent} usages are both only relevant within the XAML that defines a template. For more information, see TemplateBinding Markup Extension
{RelativeSource FindAncestor} is mainly used in control templates or predictable self-contained UI compositions, for cases where a control is always expected to be in a visual tree of a certain ancestor type. For example, items of an items control might use FindAncestor usages to bind to properties of their items control parent ancestor. Or, elements that are part of control composition in a template can use FindAncestor bindings to the parent elements in that same composition structure.
In the object element syntax for FindAncestor mode shown in the XAML Syntax sections, the second object element syntax is used specifically forFindAncestor mode. FindAncestor mode requires an AncestorType value. You must set AncestorType as an attribute using an x:Type Markup Extension reference to the type of ancestor to look for. The AncestorType value is used when the binding request is processed at run-time.
For FindAncestor mode, the optional property AncestorLevel can help disambiguate the ancestor lookup in cases where there is possibly more than one ancestor of that type existing in the element tree.
For more information on how to use the FindAncestor mode, see RelativeSource.
{RelativeSource Self} is useful for scenarios where one property of an instance should depend on the value of another property of the same instance, and no general dependency property relationship (such as coercion) already exists between those two properties. Although it is rare that two properties exist on an object such that the values are literally identical (and are identically typed), you can also apply a Converter parameter to a binding that has {RelativeSource Self}, and use the converter to convert between source and target types. Another scenario for {RelativeSource Self} is as part of a MultiDataTrigger.
For example, the following XAML defines a Rectangle element such that no matter what value is entered for Width, the Rectangle is always a square:<Rectangle Width="200" Height="{Binding RelativeSource={RelativeSource Self}, Path=Width}" .../>
{RelativeSource PreviousData} is useful either in data templates, or in cases where bindings are using a collection as the data source. You can use{RelativeSource PreviousData} to highlight relationships between adjacent data items in the collection. A related technique is to establish aMultiBinding between the current and previous items in the data source, and use a converter on that binding to determine the difference between the two items and their properties.
In the following example, the first TextBlock in the items template displays the current number. The second TextBlock binding is a MultiBinding that nominally has two Binding consistuents: the current record, and a binding that deliberately uses the previous data record by using {RelativeSource PreviousData}. Then, a converter on the MultiBinding calculates the difference and returns it to the binding.
<ListBox Name="fibolist"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding}"/> <TextBlock>, difference = </TextBlock> <TextBlock> <TextBlock.Text> <MultiBinding Converter="{StaticResource DiffConverter}"> <Binding/> <Binding RelativeSource="{RelativeSource PreviousData}"/> </MultiBinding> </TextBlock.Text> </TextBlock> </StackPanel> </DataTemplate> </ListBox.ItemTemplate>
Describing data binding as a concept is not covered here, see Data Binding Overview.
In the WPF XAML processor implementation, the handling for this markup extension is defined by the RelativeSource class.
RelativeSource is a markup extension. Markup extensions are typically implemented when there is a requirement to escape attribute values to be other than literal values or handler names, and the requirement is more global than just putting type converters on certain types or properties. All markup extensions in XAML use the { and } characters in their attribute syntax, which is the convention by which a XAML processor recognizes that a markup extension must process the attribute. For more information, see Markup Extensions and WPF XAML.
StaticResource Markup Extension
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
<object property="{StaticResource key}" .../>
XAML Object Element Usage
<object> <object.property> <StaticResource ResourceKey="key" .../> </object.property> </object>
XAML Values
key | The key for the requested resource. This key was initially assigned by the x:Key Directive if a resource was created in markup, or was provided as the key parameter when calling ResourceDictionary.Add if the resource was created in code. |
Remarks
Important |
---|
A StaticResource must not attempt to make a forward reference to a resource that is defined lexically further within the XAML file. Attempting to do so is not supported, and even if such a reference does not fail, attempting the forward reference will incur a load time performance penalty when the internal hash tables representing a ResourceDictionary are searched. For best results, adjust the composition of your resource dictionaries such that forward references can be avoided. If you cannot avoid a forward reference, use DynamicResource Markup Extension instead. |
The specified ResourceKey should correspond to an existing resource, identified with an x:Key Directive at some level in your page, application, the available control themes and external resources, or system resources. The resource lookup occurs in that order. For more information about resource lookup behavior for static and dynamic resources, see XAML Resources.
A resource key can be any string defined in the XamlName Grammar. A resource key can also be other object types, such as a Type. A Type key is fundamental to how controls can be styled by themes, through an implicit style key. For more information, see Control Authoring Overview.
The alternative declarative means of referencing a resource is as a DynamicResource Markup Extension.
Attribute syntax is the most common syntax used with this markup extension. The string token provided after the StaticResource identifier string is assigned as the ResourceKey value of the underlying StaticResourceExtension extension class.
StaticResource can be used in object element syntax. In this case, specifying the value of the ResourceKey property is required.
StaticResource can also be used in a verbose attribute usage that specifies the ResourceKey property as a property=value pair:
<object property="{StaticResource ResourceKey=key}" .../>
The verbose usage is often useful for extensions that have more than one settable property, or if some properties are optional. Because StaticResourcehas only one settable property, which is required, this verbose usage is not typical.
In the WPF XAML processor implementation, the handling for this markup extension is defined by the StaticResourceExtension class.
StaticResource is a markup extension. Markup extensions are typically implemented when there is a requirement to escape attribute values to be other than literal values or handler names, and the requirement is more global than just putting type converters on certain types or properties. All markup extensions in XAML use the { and } characters in their attribute syntax, which is the convention by which a XAML processor recognizes that a markup extension must process the attribute. For more information, see Markup Extensions and WPF XAML.
TemplateBinding Markup Extension
Links the value of a property in a control template to be the value of another property on the templated control.
XAML Attribute Usage
<object property="{TemplateBinding sourceProperty}" .../>
XAML Attribute Usage (for Setter property in template or style)
<Setter Property="propertyName" Value="{TemplateBinding sourceProperty}" .../>
XAML Values
propertyName | DependencyProperty.Name of the property being set in the setter syntax. |
sourceProperty | Another dependency property that exists on the type being templated, specified by its DependencyProperty.Name. - or - A "dotted-down" property name that is defined by a different type than the target type being templated. This is actually aPropertyPath. See PropertyPath XAML Syntax. |
Remarks
A TemplateBinding is an optimized form of a Binding for template scenarios, analogous to a Binding constructed with {Binding RelativeSource={RelativeSource TemplatedParent}}. A TemplateBinding is always a one-way binding, even if properties involved default to two-way binding. Both properties involved must be dependency properties.
RelativeSource is another markup extension that is sometimes used in conjunction with or instead of TemplateBinding in order to perform relative property binding within a template.
Describing control templates as a concept is not covered here; for more information, see Control Styles and Templates.
Attribute syntax is the most common syntax used with this markup extension. The string token provided after the TemplateBinding identifier string is assigned as the Property value of the underlying TemplateBindingExtension extension class.
Object element syntax is possible, but it is not shown because it has no realistic application. TemplateBinding is used to fill values within setters, using evaluated expressions, and using object element syntax for TemplateBinding to fill <Setter.Property> property element syntax is unnecessarily verbose.
TemplateBinding can also be used in a verbose attribute usage that specifies the Property property as a property=value pair:
<object property="{TemplateBinding Property=sourceProperty}" .../>
The verbose usage is often useful for extensions that have more than one settable property, or if some properties are optional. BecauseTemplateBinding has only one settable property, which is required, this verbose usage is not typical.
In the WPF XAML processor implementation, the handling for this markup extension is defined by the TemplateBindingExtension class.
TemplateBinding is a markup extension. Markup extensions are typically implemented when there is a requirement to escape attribute values to be other than literal values or handler names, and the requirement is more global than just putting type converters on certain types or properties. All markup extensions in XAML use the { and } characters in their attribute syntax, which is the convention by which a XAML processor recognizes that a markup extension must process the attribute. For more information, see Markup Extensions and WPF XAML.
ThemeDictionary Markup Extension
Provides a way for custom control authors or applications that integrate third-party controls to load theme-specific resource dictionaries to use in styling the control.
XAML Attribute Usage
<object property="{ThemeDictionary assemblyUri}" .../>
XAML Object Element Usage
<object> <object.property> <ThemeDictionary AssemblyName="assemblyUri"/> <object.property> <object>
XAML Values
assemblyUri | The uniform resource identifier (URI) of the assembly that contains theme information. Typically, this is a pack URI that references an assembly in the larger package. Assembly resources and pack URIs simplify deployment issues. For more information see Pack URIs in WPF. |
Remarks
This extension is intended to fill only one specific property value: a value for ResourceDictionary.Source.
By using this extension, you can specify a single resources-only assembly that contains some styles to use only when the Windows Aero theme is applied to the user's system, other styles when Luna theme is active, and so on. By using this extension, the contents of a control-specific resource dictionary can be automatically invalidated and reloaded to be specific for another theme when required.
The assemblyUri string (AssemblyName property value) forms the basis of a naming convention that identifies which dictionary applies for a particular theme. The ProvideValue logic for ThemeDictionary completes the convention by generating a uniform resource identifier (URI) that points to a particular theme dictionary variant, as contained within a precompiled resource assembly. Describing this convention, or theme interactions with general control styling and page/application level styling as a concept, is not covered fully here. The basic scenario for using ThemeDictionary is to specify theSource property of a ResourceDictionary declared at the application level. When you provide a URI for the assembly through a ThemeDictionaryextension rather than as a direct URI, the extension logic will provide invalidation logic that applies whenever the system theme changes.
Attribute syntax is the most common syntax used with this markup extension. The string token provided after the ThemeDictionary identifier string is assigned as the AssemblyName value of the underlying ThemeDictionaryExtension extension class.
ThemeDictionary may also be used in object element syntax. In this case, specifying the value of the AssemblyName property is required.
ThemeDictionary can also be used in a verbose attribute usage that specifies the Member property as a property=value pair:
<object property="{ThemeDictionary AssemblyName=assemblyUri}" .../>
The verbose usage is often useful for extensions that have more than one settable property, or if some properties are optional. BecauseThemeDictionary has only one settable property, which is required, this verbose usage is not typical.
In the WPF XAML processor implementation, the handling for this markup extension is defined by the ThemeDictionaryExtension class.
ThemeDictionary is a markup extension. Markup extensions are typically implemented when there is a requirement to escape attribute values to be other than literal values or handler names, and the requirement is more global than just putting type converters on certain types or properties. All markup extensions in XAML use the { and } characters in their attribute syntax, which is the convention by which a XAML processor recognizes that a markup extension must process the attribute. For more information, see Markup Extensions and WPF XAML.
PropertyPath XAML Syntax
The PropertyPath object supports a complex inline XAML syntax for setting various properties that take the PropertyPath type as their value. This topic documents the PropertyPath syntax as applied to binding and animation syntaxes.
Where PropertyPath Is Used
PropertyPath is a common object that is used in several Windows Presentation Foundation (WPF) features. Despite using the common PropertyPath to convey property path information, the usages for each feature area where PropertyPath is used as a type vary. Therefore, it is more practical to document the syntaxes on a per-feature basis.
Primarily, WPF uses PropertyPath to describe object-model paths for traversing the properties of an object data source, and to describe the target path for targeted animations.
Some style and template properties such as Setter.Property take a qualified property name that superficially resembles a PropertyPath. But this is not a true PropertyPath; instead it is a qualified owner.property string format usage that is enabled by the WPF XAML processor in combination with the type converter for DependencyProperty.
PropertyPath for Objects in Data Binding
Data binding is a WPF feature whereby you can bind to the target value of any dependency property. However, the source of such a data binding need not be a dependency property; it can be any property type that is recognized by the applicable data provider. Property paths are particularly used for the ObjectDataProvider, which is used for obtaining binding sources from common language runtime (CLR) objects and their properties.
Note that data binding to XML does not use PropertyPath, because it does not use Path in the Binding. Instead, you use XPath and specify valid XPath syntax into the XML Document Object Model (DOM) of the data. XPath is also specified as a string, but is not documented here; see How to: Bind to XML Data Using an XMLDataProvider and XPath Queries.
A key to understanding property paths in data binding is that you can target the binding to an individual property value, or you can instead bind to target properties that take lists or collections. If you are binding collections, for instance binding a ListBox that will expand depending on how many data items are in the collection, then your property path should reference the collection object, not individual collection items. The data binding engine will match the collection used as the data source to the type of the binding target automatically, resulting in behavior such as populating a ListBox with an items array.
Single Property on the Immediate Object as Data Context
<Binding Path="propertyName" .../>
propertyName must resolve to be the name of a property that is in the current DataContext for a Path usage. If your binding updates the source, that property must be read/write and the source object must be mutable.
Single Indexer on the Immediate Object as Data Context
<Binding Path="[key]" .../>
key must be either the typed index to a dictionary or hash table, or the integer index of an array. Also, the value of the key must be a type that is directly bindable to the property where it is applied. For instance, a hash table that contains string keys and string values can be used this way to bind to Text for a TextBox. Or, if the key points to a collection or subindex, you could use this syntax to bind to a target collection property. Otherwise, you need to reference a specific property, through a syntax such as <Binding Path="[key].propertyName" .../>.
You can specify the type of the index if necessary. For details on this aspect of an indexed property path, see Binding.Path.
Multiple Property (Indirect Property Targeting)
<Binding Path="propertyName.propertyName2" .../>
propertyName must resolve to be the name of a property that is the current DataContext. The path properties propertyName and propertyName2 can be any properties that exist in a relationship, where propertyName2 is a property that exists on the type that is the value of propertyName.
Single Property, Attached or Otherwise Type-Qualified
<object property="(ownerType.propertyName)" .../>
The parentheses indicate that this property in a PropertyPath should be constructed using a partial qualification. It can use an XML namespace to find the type with an appropriate mapping. The ownerType searches types that a XAML processor has access to, through the XmlnsDefinitionAttributedeclarations in each assembly. Most applications have the default XML namespace mapped to the http://schemas.microsoft.com/winfx/2006/xaml/presentation namespace, so a prefix is usually only necessary for custom types or types otherwise outside that namespace. propertyName must resolve to be the name of a property existing on the ownerType. This syntax is generally used for one of the following cases:
The path is specified in XAML that is in a style or template that does not have a specified Target Type. A qualified usage is generally not valid for cases other than this, because in non-style, non-template cases, the property exists on an instance, not a type.
The property is an attached property.
You are binding to a static property.
For use as storyboard target, the property specified as propertyName must be a DependencyProperty.
Source Traversal (Binding to Hierarchies of Collections)
<object Path="propertyName/propertyNameX" .../>
The / in this syntax is used to navigate within a hierarchical data source object, and multiple steps into the hierarchy with successive / characters are supported. The source traversal accounts for the current record pointer position, which is determined by synchronizing the data with the UI of its view. For details on binding with hierarchical data source objects, and the concept of current record pointer in data binding, see How to: Use the Master-Detail Pattern with Hierarchical Data or Data Binding Overview.
Collection Views
To reference a named collection view, prefix the collection view name with the hash character (#).
Current Record Pointer
To reference the current record pointer for a collection view or master detail data binding scenario, start the path string with a forward slash (/). Any path past the forward slash is traversed starting from the current record pointer.
Multiple Indexers
<object Path="[index1,index2...]" .../> or <object Path="propertyName[index,index2...]" .../>
If a given object supports multiple indexers, those indexers can be specified in order, similar to an array referencing syntax. The object in question can be either the current context or the value of a property that contains a multiple index object.
By default, the indexer values are typed by using the characteristics of the underlying object. You can specify the type of the index if necessary. For details on typing the indexers, see Binding.Path.
Mixing Syntaxes
Each of the syntaxes shown above can be interspersed. For instance, the following is an example that creates a property path to the color at a particular x,y of a ColorGrid property that contains a pixel grid array of SolidColorBrush objects:
<Rectangle Fill="{Binding ColorGrid[20,30].SolidColorBrushResult}" .../>
Escapes for Property Path Strings
For certain business objects, you might encounter a case where the property path string requires an escape sequence in order to parse correctly. The need to escape should be rare, because many of these characters have similar naming-interaction issues in languages that would typically be used to define the business object.
Inside indexers ([ ]), the caret character (^) escapes the next character.
You must escape (using XML entities) certain characters that are special to the XML language definition. Use & to escape the character "&". Use > to escape the end tag ">".
You must escape (using backslash \) characters that are special to the WPF XAML parser behavior for processing a markup extension.
Backslash (\) is the escape character itself.
The equal sign (=) separates property name from property value.
Comma (,) separates properties.
The right curly brace (}) is the end of a markup extension.
Note |
---|
Technically, these escapes work for a storyboard property path also, but you are usually traversing object models for existing WPF objects, and escaping should be unnecessary. |
PropertyPath for Animation Targets
The target property of an animation must be a dependency property that takes either a Freezable or a primitive type. However, the targeted property on a type and the eventual animated property can exist on different objects. For animations, a property path is used to define the connection between the named animation target object's property and the intended target animation property, by traversing object-property relationships in the property values.
General Object-Property Considerations for Animations
For more information on animation concepts in general, see Storyboards Overview and Animation Overview.
The value type or the property being animated must be either a Freezable type or a primitive. The property that starts the path must resolve to be the name of a dependency property that exists on the specified TargetName type.
In order to support cloning for animating a Freezable that is already frozen, the object specified by TargetName must be a FrameworkElement orFrameworkContentElement derived class.
Single Property on the Target Object
<animation Storyboard.TargetProperty="propertyName" .../>
propertyName must resolve to be the name of a dependency property that exists on the specified TargetName type.
Indirect Property Targeting
<animation Storyboard.TargetProperty="propertyName.propertyName2" .../>
propertyName must be a property that is either a Freezable value type or a primitive, which exists on the specified TargetName type.
propertyName2 must be the name of a dependency property that exists on the object that is the value of propertyName. In other words,propertyName2 must exist as a dependency property on the type that is the propertyName PropertyType.
Indirect targeting of animations is necessary because of applied styles and templates. In order to target an animation, you need a TargetName on a target object, and that name is established by x:Name or Name. Although template and style elements also can have names, those names are only valid within the namescope of the style and template. (If templates and styles did share namescopes with application markup, names couldn't be unique. The styles and templates are literally shared between instances and would perpetuate duplicate names.) Thus, if the individual properties of an element that you might wish to animate came from a style or template, you need to start with a named element instance that is not from a style template, and then target into the style or template visual tree to arrive at the property you wish to animate.
For instance, the Background property of a Panel is a complete Brush (actually a SolidColorBrush) that came from a theme template. To animate aBrush completely, there would need to be a BrushAnimation (probably one for every Brush type) and there is no such type. To animate a Brush, you instead animate properties of a particular Brush type. You need to get from SolidColorBrush to its Color to apply a ColorAnimation there. The property path for this example would be Background.Color.
Attached Properties
<animation Storyboard.TargetProperty="(ownerType.propertyName)" .../>
The parentheses indicate that this property in a PropertyPath should be constructed using a partial qualification. It can use an XML namespace to find the type. The ownerType searches types that a XAML processor has access to, through the XmlnsDefinitionAttribute declarations in each assembly. Most applications have the default XML namespace mapped to the http://schemas.microsoft.com/winfx/2006/xaml/presentation namespace, so a prefix is usually only necessary for custom types or types otherwise outside that namespace. propertyName must resolve to be the name of a property existing on the ownerType. The property specified as propertyName must be a DependencyProperty. (All WPF attached properties are implemented as dependency properties, so this issue is only of concern for custom attached properties.)
Indexers
<animation Storyboard.TargetProperty="propertyName.propertyName2[index].propertyName3" .../>
Most dependency properties or Freezable types do not support an indexer. Therefore, the only usage for an indexer in an animation path is at an intermediate position between the property that starts the chain on the named target and the eventual animated property. In the provided syntax, that is propertyName2. For instance, an indexer usage might be necessary if the intermediate property is a collection such as TransformGroup, in a property path such as RenderTransform.Children[1].Angle.
PropertyPath in Code
Code usage for PropertyPath, including how to construct a PropertyPath, is documented in the reference topic for PropertyPath.
In general, PropertyPath is designed to use two different constructors, one for the binding usages and simplest animation usages, and one for the complex animation usages. Use the PropertyPath(Object) signature for binding usages, where the object is a string. Use the PropertyPath(Object)signature for one-step animation paths, where the object is a DependencyProperty. Use the PropertyPath(String, Object[]) signature for complex animations. This latter constructor uses a token string for the first parameter and an array of objects that fill positions in the token string to define a property path relationship.
PresentationOptions:Freeze Attribute
Sets the IsFrozen state to true on the containing Freezable element. Default behavior for a Freezable without the PresentationOptions:Freeze attribute specified is that IsFrozen is false at load time, and dependent on general Freezable behavior at runtime.
XAML Attribute Usage
<object xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="PresentationOptions"> <freezableElement PresentationOptions:Freeze="true"/> </object>
XAML Values
PresentationOptions | An XML namespace prefix, which can be any valid prefix string, per the XML 1.0 specification. The prefix PresentationOptions is used for identification purposes in this documentation. |
freezableElement | An element that instantiates any derived class of Freezable. |
Remarks
The Freeze attribute is the only attribute or other programming element defined in thehttp://schemas.microsoft.com/winfx/2006/xaml/presentation/options XML namespace. The Freeze attribute exists in this special namespace specifically so that it can be designated as ignorable, using mc:Ignorable Attribute as part of the root element declarations. The reason that Freeze must be able to be ignorable is because not all XAML processor implementations are able to freeze a Freezable at load time; this capability is not part of the XAML specification.
The ability to process the Freeze attribute is specifically built in to the XAML processor that processes XAML for compiled applications. The attribute is not supported by any class, and the attribute syntax is not extensible or modifiable. If you are implementing your own XAML processor you can choose to parallel the freezing behavior of the WPF XAML processor when processing the Freeze attribute on Freezable elements at load time.
Any value for the Freeze attribute other than true (not case sensitive) generates a load time error. (Specifying the Freeze attribute as false is not an error, but that is already the default, so setting to false does nothing).
Markup Compatibility (mc:) Language Features
mc:Ignorable Attribute
Specifies which XML namespace prefixes encountered in a markup file may be ignored by a XAML processor. The mc:Ignorable attribute supports markup compatibility both for custom namespace mapping and for XAML versioning.
XAML Attribute Usage (Single Prefix)
<object xmlns:ignorablePrefix="ignorableUri" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="ignorablePrefix"...> <ignorablePrefix1:ThisElementCanBeIgnored/> </object>
XAML Attribute Usage (Two Prefixes)
<object xmlns:ignorablePrefix1="ignorableUri" xmlns:ignorablePrefix2="ignorableUri2" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="ignorablePrefix1 ignorablePrefix2"...> <ignorablePrefix1:ThisElementCanBeIgnored/> </object>
XAML Values
ignorablePrefix, ignorablePrefix1, etc. | Any valid prefix string, per the XML 1.0 specification. |
ignorableUri | Any valid URI for designating a namespace, per the XML 1.0 specification. |
ThisElementCanBeIgnored | An element that can be ignored by Extensible Application Markup Language (XAML) processor implementations, if the underlying type cannot be resolved. |
Remarks
The mc XML namespace prefix is the recommended prefix convention to use when mapping the XAML compatibility namespace http://schemas.openxmlformats.org/markup-compatibility/2006.
Elements or attributes where the prefix portion of the element name are identified as mc:Ignorable will not raise errors when processed by a XAML processor. If that attribute could not be resolved to an underlying type or programming construct, then that element is ignored. Note however that ignored elements might still generate additional parsing errors for additional element requirements that are side effects of that element not being processed. For instance, a particular element content model might require exactly one child element, but if the specified child element was in anmc:Ignorable prefix, and the specified child element could not be resolved to a type, then the XAML processor might raise an error.
mc:Ignorable only applies to namespace mappings to identifier strings. mc:Ignorable does not apply to namespace mappings into assemblies, which specify a CLR namespace and an assembly (or default to the current executable as the assembly).
If you are implementing a XAML processor, your processor implementation must not raise parsing or processing errors on type resolution for any element or attribute that is qualified by a prefix that is identified as mc:Ignorable. But your processor implementation can still raise exceptions that are a secondary result of an element failing to load or be processed, such as the one-child element example given earlier.
By default, a XAML processor will ignore content within an ignored element. However, you can specify an additional attribute, mc:ProcessContent Attribute, to require continued processing of content within an ignored element by the next available parent element.
Multiple prefixes can be specified in the attribute, using one or more whitespace characters as the separator, for example:mc:Ignorable="ignore1 ignore2".
The http://schemas.openxmlformats.org/markup-compatibility/2006 namespace defines other elements and attributes that are not documented within this area of the software development kit (SDK). For more information, see XML Markup Compatibility Specification.
mc:ProcessContent Attribute
Specifies which XAML elements should still have content processed by relevant parent elements, even if the immediate parent element may be ignored by a XAML processor due to specifying mc:Ignorable Attribute. The mc:ProcessContent attribute supports markup compatibility both for custom namespace mapping and for XAML versioning.
XAML Attribute Usage
<object xmlns:ignorablePrefix="ignorableUri" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="ignorablePrefix"... mc:ProcessContent="ignorablePrefix:ThisElementCanBeIgnored" > <ignorablePrefix:ThisElementCanBeIgnored> [content] </ignorablePrefix:ThisElementCanBeIgnored> </object>
XAML Values
ignorablePrefix | Any valid prefix string, per the XML 1.0 specification. |
ignorableUri | Any valid URI for designating a namespace, per the XML 1.0 specification. |
ThisElementCanBeIgnored | An element that can be ignored by Extensible Application Markup Language (XAML) processor implementations, if the underlying type cannot be resolved. |
[content] | ThisElementCanBeIgnored is marked ignorable. If the processor ignores that element, [content] is processed by object. |
Remarks
By default, a XAML processor will ignore content within an ignored element. You can specify a specific element by mc:ProcessContent, and a XAML processor will continue to process the content within the ignored element. This would typically be used if the content is nested within several tags, at least one of which is ignorable and at least one of which is not ignorable.
Multiple prefixes may be specified in the attribute, using a space separator, for example: mc:ProcessContent="ignore:Element1 ignore:Element2".
The http://schemas.openxmlformats.org/markup-compatibility/2006 namespace defines other elements and attributes that are not documented within this area of the software development kit (SDK). For more information, see XML Markup Compatibility Specification.
'프로그래밍 > WPF' 카테고리의 다른 글
WPF 고급 - 입력 (Input) (0) | 2016.10.15 |
---|---|
ObservableCollection<T>, INotifyPropertyChanged Interface (0) | 2016.10.15 |
WPF - Application Development (1) | 2016.09.08 |
Data Binding (WPF) (0) | 2016.09.04 |
Windows Presentation Foundation (0) | 2016.08.26 |