0% found this document useful (0 votes)
36 views

Dotnet Desktop WPF Advanced Netframeworkdesktop 4.8

The document provides an overview of the Windows Presentation Foundation (WPF) architecture. It describes the major components of WPF including the managed and unmanaged code portions. It discusses key concepts like the dispatcher for handling concurrency, the dependency property system, and how visual elements are rendered through the composition system to the display.

Uploaded by

jlgultraboom
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
36 views

Dotnet Desktop WPF Advanced Netframeworkdesktop 4.8

The document provides an overview of the Windows Presentation Foundation (WPF) architecture. It describes the major components of WPF including the managed and unmanaged code portions. It discusses key concepts like the dispatcher for handling concurrency, the dependency property system, and how visual elements are rendered through the composition system to the display.

Uploaded by

jlgultraboom
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1269

Tell us about your PDF experience.

Advanced (Windows Presentation


Foundation)
Article • 11/07/2022

This section describes some of the advanced areas in WPF.

In This Section
WPF Architecture
XAML in WPF
Base Element Classes
Element Tree and Serialization
WPF Property System
Events in WPF
Input
Drag and Drop
Resources
Documents
Globalization and Localization
Layout
Types migrated from WPF to System.Xaml
Migration and Interoperability
Performance
Threading Model
Unmanaged WPF API Reference
WPF Architecture
Article • 02/06/2023

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.

System.Object
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.

System.Threading.DispatcherObject
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.

System.Windows.DependencyObject
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.

System.Windows.Media.Visual
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.

System.Windows.UIElement
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. The Arrange 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 they 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.

System.Windows.FrameworkElement
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, FrameworkElement provides 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.

System.Windows.Controls.Control
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.

Summary
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.

See also
Visual
UIElement
ICommand
FrameworkElement
DispatcherObject
CommandBinding
Control
Data Binding Overview
Layout
Animation Overview
XAML in WPF
Article • 08/10/2023

Extensible Application Markup Language (XAML) is a markup language for declarative


application programming. Windows Presentation Foundation (WPF) implements a XAML
processor implementation and provides XAML language support. The WPF types are
implemented such that they can provide the required type backing for a XAML
representation. In general, you can create the majority of your WPF application UI in
XAML markup.

In This Section
XAML in WPF
XAML Syntax In Detail
Code-Behind and XAML in WPF
XAML and Custom Classes for WPF
Markup Extensions and WPF XAML
XAML Namespaces and Namespace Mapping for WPF XAML
WPF XAML Namescopes
Inline Styles and Templates
White-space Processing in XAML
TypeConverters and XAML
XML Character Entities and XAML
XAML Namespace (x:) Language Features
WPF XAML Extensions
Markup Compatibility (mc:) Language Features

Related Sections
WPF Architecture
Base Elements
Element Tree and Serialization
Properties
Events
Input
Resources
Styling and Templating
Threading Model
XAML overview in WPF (.NET
Framework)
Article • 02/16/2023

This article describes the features of the XAML language and demonstrates how you can
use XAML to write Windows Presentation Foundation (WPF) apps. This article 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 app. 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 that are 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 app, 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 intended to give you a flavor of how XAML represents common UI
programming metaphors (it is not a complete sample).

XAML

<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, 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. 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 referenced by the 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 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.

XAML

<StackPanel>
<Button Content="Click Me"/>
</StackPanel>

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 of the underlying type. Each
instance is created by calling the parameterless 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. The
attribute syntax names the object property that is being set, 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 .

XAML

<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 the 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 .

XAML

<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.

XAML

<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.

XAML

<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.

XAML

<Button>I am a
<Button.Background>Blue</Button.Background>
blue button</Button>

For more information about the specifics of XAML syntax, see 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 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>
converts the content value of Blue into a 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.

XAML

<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 parameterless constructor, and that is why the UIElementCollection
object element is shown commented out).

XAML

<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:

XAML

<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ExampleNamespace.ExamplePage">
<Button Click="Button_Click" >Click Me!</Button>
</Page>

There is more to events and XAML in WPF than just this example of the attribute syntax.
For example, you might wonder what the ClickHandler referenced here represents and
how it is defined. This will be explained in the upcoming Events and XAML code-behind
section of this article.
Case and white space in XAML
In general, XAML is 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 white space,
and will normalize any significant white space. This is consistent with the default white-
space behavior recommendations of the XAML specification. This behavior is 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 white-space handling is not covered in this article. For more information, see
White space 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 app 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.

XAML

<Page.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
<Style TargetType="Border" x:Key="PageBackground">
<Setter Property="Background" Value="Blue"/>
</Style>

XAML

</Page.Resources>
<StackPanel>
<Border Style="{StaticResource PageBackground}">

XAML

</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 as DateTime 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 Thickness are 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:
XAML

<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:

XAML

<Button Content="Click me">


<Button.Margin>
<Thickness Left="10" Top="20" Right="10" Bottom="30"/>
</Button.Margin>
</Button>

7 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 parameterless constructor. An example is Cursor.

For more information on type conversion, 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 app model (for example, Window or Page for a page,
ResourceDictionary for an external dictionary, or Application for the app definition). The
following example shows the root element of a typical XAML file for a WPF page, with
the root element of Page.

XAML

<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

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 app
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.

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
contains several programming constructs that you will use 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
percent of the x: usages you will see in a typical WPF app'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 app 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 Name property 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 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 app. 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.

XAML

<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 code namespaces in assemblies
are related, see XAML Namespaces and Namespace Mapping for WPF XAML.

Events and XAML code-behind


Most WPF apps 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.

XAML

<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ExampleNamespace.ExamplePage">
<Button Click="Button_Click" >Click Me!</Button>
</Page>

C#

namespace ExampleNamespace
{
public partial class ExamplePage
{
void Button_Click(object sender, RoutedEventArgs e)
{
Button b = e.Source as Button;
b.Foreground = 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 app.

For more information about requirements for code-behind programming in WPF, see
Code-behind, Event Handler, and Partial Class Requirements 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 more informaiton, 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 ongoing StackPanel / 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, 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 app. 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
article.

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 Name property 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.

XAML

<StackPanel Name="buttonContainer">
XAML

<Button Click="RemoveThis">Click to remove this button</Button>


</StackPanel>

C#

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 form ownerType.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.

XAML

<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 more information, 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 non-abstract
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 in
FrameworkElement. 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. XAML loaded in to a fully trusted app has the same access to the system resources
as the hosting app does.

Code Access Security (CAS) in WPF


WPF for .NET Framework supports 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 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 app. 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 app, you can modify a running app's contents easily by loading in XAML. For
.NET Framework, this capability is generally only available in full-trust applications,
because of the obvious security implications of loading files into applications as they
run.
See also
XAML Syntax In Detail
XAML and Custom Classes for WPF
XAML Namespace (x:) Language Features
WPF XAML Extensions
Base Elements Overview
Trees in WPF
XAML Syntax In Detail
Article • 02/06/2023

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 in 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 .NET, XAML object elements map to .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:
XAML

<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.

XAML

<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 parameterless 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.
7 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:

1. 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.

2. 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.
3. 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, and Enumeration 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:

XAML

<!--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.propertyName combination 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.

XAML

<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 as String, 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 white-space 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 white-space
preservation is active (for details, see White space 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 white-space
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, the Triggers property of Style takes the specialized collection type
TriggerCollection, which implements IList. It is not necessary to instantiate a
TriggerCollection 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.

XAML

<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.

7 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 implements IDictionary 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.

XAML

<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 parameterless constructor, and TriggerCollection does not have a
parameterless 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. The
ContentPropertyAttribute 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:

XAML

<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:

XAML

<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:

XAML

<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 Panel derived classes establish the XAML content property
to be Children, which requires a value of type UIElementCollection.

XAML

<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 parameterless 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 white space 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 a ResourceDictionary, 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 requested ResourceKey. 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.propertyName combination. 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, where typeName
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:

Attribute Description

<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 you 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:

XAML

<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) and Button is the class of the object
element or a base class. Control.Background works because the Control class actually
defines Background and Control is a Button base class.

However, the following typeName.memberName form example does not work and is
thus shown commented:

XAML

<!--<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
process Label.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:

XAML
<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.

See also
XAML in WPF
XAML Namespace (x:) Language Features
WPF XAML Extensions
Dependency Properties Overview
TypeConverters and XAML
XAML and Custom Classes for WPF
Code-Behind and XAML in WPF
Article • 08/10/2023

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

Code-Behind and the XAML Language

Code-behind, Event Handler, and Partial Class Requirements in WPF

x:Code

Inline Code Limitations

Prerequisites
This topic assumes that you have read the XAML in 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.

XAML

<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.

See also
XAML in WPF
x:Code Intrinsic XAML Type
Building a WPF Application
XAML Syntax In Detail
XAML and Custom Classes for WPF
Article • 02/06/2023

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 parameterless 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-parameterless 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 parameterless 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 parameterless 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 parameterless 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 white-space handling of
the attribute value. For example, the following is a property element usage that takes a
string, and the attribute usage equivalent:

XAML

<Button>Hallo!
<Button.Language>
de-DE
</Button.Language>
</Button>

XAML

<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 parameterless 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 parameterless 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 parameterless 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 and
RemoveHandler methods. These methods add or remove the handlers to the routed
event handler store on the instance that the event is attached to.

7 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.

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.
7 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 parameterless constructor in order to be used in XAML implicitly. However,
you can optionally provide a parameterless constructor for the collection type. This can
be a worthwhile practice. Unless you do provide a parameterless 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
parameterless 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 as PropertyInfo.

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.

See also
XAML in WPF
Custom Dependency Properties
Control Authoring Overview
Base Elements Overview
XAML Loading and Dependency Properties
Markup Extensions and WPF XAML
Article • 02/06/2023

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.

7 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 and DynamicResource ), 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 , see Styling 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 ProvideValue implementation 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.

7 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 constructors 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 parameterless 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
parameterless 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:
XAML

<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 parameterless 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.

See also
XAML in WPF
XAML Namespace (x:) Language Features
WPF XAML Extensions
StaticResource Markup Extension
Binding Markup Extension
DynamicResource Markup Extension
x:Type Markup Extension
XAML Namespaces and Namespace
Mapping for WPF XAML
Article • 03/17/2022

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:Key attribute
set on the element in question. For more information on these and other aspects of
XAML see XAML in 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
white space anywhere in the declaration.

A Basic Custom Mapping Example


The following code defines an example custom class:
C#

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:

XAML

<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 one XmlnsDefinitionAttribute 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 as d: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.

1. Iterate through the AppDomain, looking for an already-loaded assembly that


matches all aspects of the name, starting from the most recently loaded assembly.

2. If the name is qualified, call Assembly.Load(String) on the qualified name.

3. If the short name + public key token of a qualified name matches the assembly
that the markup was loaded from, return that assembly.

4. Use the short name + public key token to call Assembly.Load(String).

5. 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.

See also
Understanding XML Namespaces
XAML in WPF
WPF XAML Namescopes
Article • 02/06/2023

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 as FrameworkElement 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.

7 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, you 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 important 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 implement INameScope, 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 new
NameScope constructor call as the value parameter.

If the object provided as dependencyObject for SetNameScope is not a INameScope


implementation, FrameworkElement or FrameworkContentElement, 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 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:

XAML

<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 GetTemplateChild method 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:

NameScope

Style

ResourceDictionary

FrameworkTemplate

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 FrameworkTemplate
and 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:

FrameworkElement

FrameworkContentElement

See also
XAML Namespaces and Namespace Mapping for WPF XAML
x:Name Directive
Inline Styles and Templates
Article • 08/10/2023

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 and FrameworkTemplate 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.

See also
Styling and Templating
TypeConverters and XAML
Article • 02/06/2023

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 a TypeConverterAttribute 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:

XAML

<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 its
ProvideValue 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:

CanConvertTo

CanConvertFrom

ConvertTo
ConvertFrom

Of these, the most important method is ConvertFrom. This method converts the input
string to the required object type. Strictly speaking, the ConvertFrom 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 a destinationType of String .

CanConvertTo and CanConvertFrom are support methods that are used when a service
queries the capabilities of the TypeConverter implementation. 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-SI
culture, 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 the value 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 .

7 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 your CanConvertTo 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 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
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 XAML processor 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 a TypeConverterAttribute there.

See also
TypeConverter
XAML in WPF
Markup Extensions and WPF XAML
XAML Syntax In Detail
WPF XAML Extensions
Article • 02/06/2023

In This Section
Binding Markup Extension
ColorConvertedBitmap Markup Extension
ComponentResourceKey Markup Extension
DynamicResource Markup Extension
RelativeSource MarkupExtension
StaticResource Markup Extension
TemplateBinding Markup Extension
ThemeDictionary Markup Extension
PropertyPath XAML Syntax
PresentationOptions:Freeze Attribute
Binding Markup Extension
Article • 02/06/2023

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


XAML

<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 a Binding 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 of Binding 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
Value Description
Value Description

bindProp1, The name of the Binding or BindingBase property to set. Not all Binding properties
bindPropN 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, The value to set the property to. The handling of the attribute value is ultimately
valueN specific to the type and logic of the specific Binding property 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 and Binding.Source being set in the run-time data context. For
more information on the concept of data context, see Data Binding.

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 of Binding.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 Binding that 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 for BindingGroupName.

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 a StaticResource 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. See
UpdateSourceTrigger.

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
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 Binding object element, but has
no readily available attribute-parsing technique for usage in a Binding expression.
See reference topic for ValidationRules.

XmlNamespaceManager

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.

7 Note

MultiBinding and PriorityBinding do not support a XAML extension syntax. You


would instead use property elements. See reference topics for MultiBinding 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 setting ValidatesOnDataErrors
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 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.

See also
Binding
Data Binding Overview
XAML in WPF
Markup Extensions and WPF XAML
ColorConvertedBitmap Markup
Extension
Article • 02/06/2023

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


XML

<object property="{ColorConvertedBitmap imageSource sourceIIC


destinationIIC}" ... />

XAML Values
Value Description

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.

See also
UriSource
Markup Extensions and WPF XAML
Imaging Overview
ComponentResourceKey Markup
Extension
Article • 02/06/2023

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)


XML

<object x:Key="{ComponentResourceKey {x:Type targetTypeName}, targetID}" ...


/>

XAML Attribute Usage (setting key, verbose)


XML

<object x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type


targetTypeName}, ResourceID=targetID}" ... />

XAML Attribute Usage (requesting resource,


compact)
XML

<object property="{DynamicResource {ComponentResourceKey {x:Type


targetTypeName}, targetID}}" ... />

XAML Attribute Usage (requesting resource,


verbose)
XML

<object property="{DynamicResource {ComponentResourceKey


TypeInTargetAssembly={x:Type targetTypeName}, ResourceID=targetID}}" ... />
XAML Values
Value Description

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 the ComponentResourceKey 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 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 the

ComponentResourceKey parameterless 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 targetID value 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 ResourceId properties 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.

See also
ComponentResourceKey
ControlTemplate
Control Authoring Overview
XAML in WPF
Markup Extensions and WPF XAML
DateTime XAML Syntax
Article • 02/06/2023

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. DateTime values 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.

See also
XAML in WPF
DynamicResource Markup Extension
Article • 02/06/2023

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


XML

<object property="{DynamicResource key}" ... />

XAML Property Element Usage


XML

<object>
<object.property>
<DynamicResource ResourceKey="key" ... />
</object.property>
</object>

XAML Values
Value Description

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:

XML
<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. Because DynamicResource 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.

See also
XAML Resources
Resources and Code
x:Key Directive
XAML in WPF
Markup Extensions and WPF XAML
StaticResource Markup Extension
Markup Extensions and WPF XAML
RelativeSource MarkupExtension
Article • 03/17/2022

Specifies properties of a RelativeSource binding source, to be used within a Binding


Markup Extension, or when setting the RelativeSource property of a Binding element
established in XAML.

XAML Attribute Usage


XML

<Binding RelativeSource="{RelativeSource modeEnumValue}" ... />

XAML Attribute Usage (nested within Binding


extension)
XML

<object property="{Binding RelativeSource={RelativeSource modeEnumValue}


...}" ... />

XAML Object Element Usage


XML

<Binding>
<Binding.RelativeSource>
<RelativeSource Mode="modeEnumValue"/>
</Binding.RelativeSource>
</Binding>

-or-

XML

<Binding>
<Binding.RelativeSource>
<RelativeSource
Mode="FindAncestor"
AncestorType="{x:Type typeName}"
AncestorLevel="intLevel"
/>
</Binding.RelativeSource>
</Binding>

XAML Values
Value Description

modeEnumValue One of the following:

- The string token Self ; corresponds to a RelativeSource as created with its


Mode property set to Self.
- The string token TemplatedParent ; corresponds to a RelativeSource as created
with its Mode property set to TemplatedParent.
- The string token PreviousData ; corresponds to a RelativeSource as created with
its Mode property set to PreviousData.
- See below for information on FindAncestor mode.

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 for FindAncestor 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 a MultiBinding 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
constituents: 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.
XML

<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>
</ListBox>

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.

See also
Binding
Styling and Templating
XAML in WPF
Markup Extensions and WPF XAML
Data Binding Overview
Binding Declarations Overview
x:Type Markup Extension
StaticResource Markup Extension
Article • 02/06/2023

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


XML

<object property="{StaticResource key}" ... />

XAML Object Element Usage


XML

<object>
<object.property>
<StaticResource ResourceKey="key" ... />
</object.property>
</object>

XAML Values
Value Description

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:

XML

<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 StaticResource 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 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.

See also
Styling and Templating
XAML in WPF
Markup Extensions and WPF XAML
XAML Resources
Resources and Code
TemplateBinding Markup Extension
Article • 02/06/2023

Links the value of a property in a control template to be the value of another property
on the templated control.

XAML Attribute Usage


XML

<object property="{TemplateBinding sourceProperty}" ... />

XAML Attribute Usage (for Setter property in


template or style)
XML

<Setter Property="propertyName" Value="{TemplateBinding sourceProperty}" ...


/>

XAML Values
Value Description

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 a PropertyPath. 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}, Mode=OneWay} . A TemplateBinding is always a one-way binding, even if

properties involved default to two-way binding. Both properties involved must be


dependency properties. In order to achieve two-way binding to a templated parent use
the following binding statement instead {Binding RelativeSource={RelativeSource
TemplatedParent}, Mode=TwoWay, Path=MyDependencyProperty} .

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:

XML

<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. Because TemplateBinding 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.
See also
Style
ControlTemplate
Styling and Templating
XAML in WPF
Markup Extensions and WPF XAML
RelativeSource MarkupExtension
Binding Markup Extension
ThemeDictionary Markup Extension
Article • 02/06/2023

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


XML

<object property="{ThemeDictionary assemblyUri}" ... />

XAML Object Element Usage


XML

<object>
<object.property>
<ThemeDictionary AssemblyName="assemblyUri"/>
<object.property>
<object>

XAML Values
Value Description

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 only when the 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 the Source property of a ResourceDictionary declared at the application level.
When you provide a URI for the assembly through a ThemeDictionary extension 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:

XML

<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. Because ThemeDictionary 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.

See also
Styling and Templating
XAML in WPF
Markup Extensions and WPF XAML
WPF Application Resource, Content, and Data Files
PropertyPath XAML Syntax
Article • 08/18/2022

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 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


XML

<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


XML

<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)


XML

<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


XML

<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 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 . 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)


XML

<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 Use
the Master-Detail Pattern with Hierarchical Data or Data Binding Overview.

7 Note

Superficially, this syntax resembles XPath. A true XPath expression for binding to an
XML data source is not used as a Path value and should instead be used for the
mutually exclusive XPath property.

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
XAML

<object Path="[index1,index2...]" ... />

or

XAML

<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:

XML

<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.

7 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 or FrameworkContentElement
derived class.

Single Property on the Target Object


XML

<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


XML

<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 a Brush 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
XML

<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 WPF attached properties are implemented as

dependency properties, so this issue is only of concern for custom attached properties.)

Indexers
XML

<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.

See also
PropertyPath
Data Binding Overview
Storyboards Overview
PresentationOptions:Freeze Attribute
Article • 08/10/2023

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


XAML

<object

xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/pres
entation/options"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="PresentationOptions">
<freezableElement PresentationOptions:Freeze="true"/>
</object>

XAML Values
Value Description

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 the
http://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).

See also
Freezable
Freezable Objects Overview
mc:Ignorable Attribute
Markup Compatibility (mc:) Language
Features
Article • 02/06/2023

In This Section
mc:Ignorable Attribute
mc:ProcessContent Attribute
mc:Ignorable Attribute
Article • 02/06/2023

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)


XAML

<object
xmlns:ignorablePrefix="ignorableUri"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="ignorablePrefix"...>
<ignorablePrefix1:ThisElementCanBeIgnored/>
</object>

XAML Attribute Usage (Two Prefixes)


XAML

<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
Value Description

ignorablePrefix, Any valid prefix string, per the XML 1.0 specification.
ignorablePrefix1, etc.

ignorableUri Any valid URI for designating a namespace, per the XML 1.0
specification.
Value Description

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 an mc: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 white-space
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 SDK. For
more information, see XML Markup Compatibility Specification.

See also
XamlReader
PresentationOptions:Freeze Attribute
XAML in WPF
Documents in WPF
mc:ProcessContent Attribute
Article • 03/17/2022

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


XAML

<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
Value Description

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 SDK. For
more information, see XML Markup Compatibility Specification.

See also
mc:Ignorable Attribute
XAML in WPF
Base Elements
Article • 02/06/2023

Four key classes--UIElement, ContentElement, FrameworkElement, and


FrameworkContentElement--implement a substantial percentage of the common
element functionality available in WPF programming. These four classes are referred to
in this SDK as the base element classes.

In This Section
Base Elements Overview
Freezable Objects Overview
Alignment, Margins, and Padding Overview
How-to Topics

Reference
UIElement

ContentElement

FrameworkElement

FrameworkContentElement

Related Sections
WPF Architecture
XAML in WPF
Element Tree and Serialization
Properties
Events
Input
Resources
Styling and Templating
Threading Model
Base Elements Overview
Article • 02/06/2023

A high percentage of classes in Windows Presentation Foundation (WPF) are derived


from four classes which are commonly referred to in the SDK documentation as the base
element classes. These classes are UIElement, FrameworkElement, ContentElement, and
FrameworkContentElement. The DependencyObject class is also related, because it is a
common base class of both UIElement and ContentElement

Base Element APIs in WPF Classes


Both UIElement and ContentElement are derived from DependencyObject, through
somewhat different pathways. The split at this level deals with how a UIElement or
ContentElement are used in a user interface and what purpose they serve in an
application. UIElement also has Visual in its class hierarchy, which is a class that exposes
the lower-level graphics support underlying the Windows Presentation Foundation
(WPF). Visual provides a rendering framework by defining independent rectangular
screen regions. In practice, UIElement is for elements that will support a larger object
model, are intended to render and layout into regions that can be described as
rectangular screen regions, and where the content model is deliberately more open, to
allow different combinations of elements. ContentElement does not derive from Visual;
its model is that a ContentElement would be consumed by something else, such as a
reader or viewer that would then interpret the elements and produce the complete
Visual for Windows Presentation Foundation (WPF) to consume. Certain UIElement
classes are intended to be content hosts: they provide the hosting and rendering for
one or more ContentElement classes (DocumentViewer is an example of such a class).
ContentElement is used as base class for elements with somewhat smaller object models
and that more address the text, information, or document content that might be hosted
within a UIElement.

Framework-Level and Core-Level


UIElement serves as the base class for FrameworkElement, and ContentElement serves
as the base class for FrameworkContentElement. The reason for this next level of classes
is to support a WPF core level that is separate from a WPF framework level, with this
division also existing in how the APIs are divided between the PresentationCore and
PresentationFramework assemblies. The WPF framework level presents a more complete
solution for basic application needs, including the implementation of the layout
manager for presentation. The WPF core level provides a way to use much of WPF
without taking the overhead of the additional assembly. The distinction between these
levels very rarely matters for most typical application development scenarios, and in
general you should think of the WPF APIs as a whole and not concern yourself with the
difference between WPF framework level and WPF core level. You might need to know
about the level distinctions if your application design chooses to replace substantial
quantities of WPF framework level functionality, for instance if your overall solution
already has its own implementations of user interface (UI) composition and layout.

Choosing Which Element to Derive From


The most practical way to create a custom class that extends WPF is by deriving from
one of the WPF classes where you get as much as possible of your desired functionality
through the existing class hierarchy. This section lists the functionality that comes with
three of the most important element classes to help you decide which class to inherit
from.

If you are implementing a control, which is really one of the more common reasons for
deriving from a WPF class, you probably want to derive from a class that is a practical
control, a control family base class, or at least from the Control base class. For some
guidance and practical examples, see Control Authoring Overview.

If you are not creating a control and need to derive from a class that is higher in the
hierarchy, the following sections are intended as a guide for what characteristics are
defined in each base element class.

If you create a class that derives from DependencyObject, you inherit the following
functionality:

GetValue and SetValue support, and general property system support.

Ability to use dependency properties and attached properties that are


implemented as dependency properties.

If you create a class that derives from UIElement, you inherit the following functionality
in addition to that provided by DependencyObject:

Basic support for animated property values. For more information, see Animation
Overview.

Basic input event support, and commanding support. For more information, see
Input Overview and Commanding Overview.

Virtual methods that can be overridden to provide information to a layout system.


If you create a class that derives from FrameworkElement, you inherit the following
functionality in addition to that provided by UIElement:

Support for styling and storyboards. For more information, see Style and
Storyboards Overview.

Support for data binding. For more information, see Data Binding Overview.

Support for dynamic resource references. For more information, see XAML
Resources.

Property value inheritance support, and other flags in the metadata that help
report conditions about properties to framework services such as data binding,
styles, or the framework implementation of layout. For more information, see
Framework Property Metadata.

The concept of the logical tree. For more information, see Trees in WPF.

Support for the practical WPF framework-level implementation of the layout


system, including an OnPropertyChanged override that can detect changes to
properties that influence layout.

If you create a class that derives from ContentElement, you inherit the following
functionality in addition to that provided by DependencyObject:

Support for animations. For more information, see Animation Overview.

Basic input event support, and commanding support. For more information, see
Input Overview and Commanding Overview.

If you create a class that derives from FrameworkContentElement, you get the following
functionality in addition to that provided by ContentElement:

Support for styling and storyboards. For more information, see Style and
Animation Overview.

Support for data binding. For more information, see Data Binding Overview.

Support for dynamic resource references. For more information, see XAML
Resources.

Property value inheritance support, and other flags in the metadata that help
report conditions about properties to framework services like data binding, styles,
or the framework implementation of layout. For more information, see Framework
Property Metadata.
You do not inherit access to layout system modifications (such as
ArrangeOverride). Layout system implementations are only available on
FrameworkElement. However, you inherit an OnPropertyChanged override that can
detect changes to properties that influence layout and report these to any content
hosts.

Content models are documented for a variety of classes. The content model for a class is
one possible factor you should consider if you want to find an appropriate class to
derive from. For more information, see WPF Content Model.

Other Base Classes

DispatcherObject
DispatcherObject provides support for the WPF threading model and enables all objects
created for WPF applications to be associated with a Dispatcher. Even if you do not
derive from UIElement, DependencyObject, or Visual, you should consider deriving from
DispatcherObject in order to get this threading model support. For more information,
see Threading Model.

Visual
Visual implements the concept of a 2D object that generally requires visual presentation
in a roughly rectangular region. The actual rendering of a Visual happens in other
classes (it is not self-contained), but the Visual class provides a known type that is used
by rendering processes at various levels. Visual implements hit testing, but it does not
expose events that report hit-testing positives (these are in UIElement). For more
information, see Visual Layer Programming.

Freezable
Freezable simulates immutability in a mutable object by providing the means to
generate copies of the object when an immutable object is required or desired for
performance reasons. The Freezable type provides a common basis for certain graphics
elements such as geometries and brushes, as well as animations. Notably, a Freezable is
not a Visual; it can hold properties that become subproperties when the Freezable is
applied to fill a property value of another object, and those subproperties might affect
rendering. For more information, see Freezable Objects Overview.

Animatable
Animatable is a Freezable derived class that specifically adds the animation control layer
and some utility members so that currently animated properties can be distinguished
from nonanimated properties.

Control
Control is the intended base class for the type of object that is variously termed a
control or component, depending on the technology. In general, WPF control classes
are classes that either directly represent a UI control or participate closely in control
composition. The primary functionality that Control enables is control templating.

See also
Control
Dependency Properties Overview
Control Authoring Overview
WPF Architecture
Freezable Objects Overview
Article • 08/04/2022

This topic describes how to effectively use and create Freezable objects, which provide
special features that can help improve application performance. Examples of freezable
objects include brushes, pens, transformations, geometries, and animations.

What Is a Freezable?
A Freezable is a special type of object that has two states: unfrozen and frozen. When
unfrozen, a Freezable appears to behave like any other object. When frozen, a Freezable
can no longer be modified.

A Freezable provides a Changed event to notify observers of any modifications to the


object. Freezing a Freezable can improve its performance, because it no longer needs to
spend resources on change notifications. A frozen Freezable can also be shared across
threads, while an unfrozen Freezable cannot.

Although the Freezable class has many applications, most Freezable objects in Windows
Presentation Foundation (WPF) are related to the graphics sub-system.

The Freezable class makes it easier to use certain graphics system objects and can help
improve application performance. Examples of types that inherit from Freezable include
the Brush, Transform, and Geometry classes. Because they contain unmanaged
resources, the system must monitor these objects for modifications, and then update
their corresponding unmanaged resources when there is a change to the original object.
Even if you don't actually modify a graphics system object, the system must still spend
some of its resources monitoring the object, in case you do change it.

For example, suppose you create a SolidColorBrush brush and use it to paint the
background of a button.

C#

Button myButton = new Button();


SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
myButton.Background = myBrush;

When the button is rendered, the WPF graphics sub-system uses the information you
provided to paint a group of pixels to create the appearance of a button. Although you
used a solid color brush to describe how the button should be painted, your solid color
brush doesn't actually do the painting. The graphics system generates fast, low-level
objects for the button and the brush, and it is those objects that actually appear on the
screen.

If you were to modify the brush, those low-level objects would have to be regenerated.
The freezable class is what gives a brush the ability to find its corresponding generated,
low-level objects and to update them when it changes. When this ability is enabled, the
brush is said to be "unfrozen."

A freezable's Freeze method enables you to disable this self-updating ability. You can
use this method to make the brush become "frozen," or unmodifiable.

7 Note

Not every Freezable object can be frozen. To avoid throwing an


InvalidOperationException, check the value of the Freezable object's CanFreeze
property to determine whether it can be frozen before attempting to freeze it.

C#

if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}

When you no longer need to modify a freezable, freezing it provides performance


benefits. If you were to freeze the brush in this example, the graphics system would no
longer need to monitor it for changes. The graphics system can also make other
optimizations, because it knows the brush won't change.

7 Note

For convenience, freezable objects remain unfrozen unless you explicitly freeze
them.

Using Freezables
Using an unfrozen freezable is like using any other type of object. In the following
example, the color of a SolidColorBrush is changed from yellow to red after it's used to
paint the background of a button. The graphics system works behind the scenes to
automatically change the button from yellow to red the next time the screen is
refreshed.

C#

Button myButton = new Button();


SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
myButton.Background = myBrush;

// Changes the button's background to red.


myBrush.Color = Colors.Red;

Freezing a Freezable
To make a Freezable unmodifiable, you call its Freeze method. When you freeze an
object that contains freezable objects, those objects are frozen as well. For example, if
you freeze a PathGeometry, the figures and segments it contains would be frozen too.

A Freezable can't be frozen if any of the following are true:

It has animated or data bound properties.

It has properties set by a dynamic resource. (See the XAML Resources for more
information about dynamic resources.)

It contains Freezable sub-objects that can't be frozen.

If these conditions are false, and you don't intend to modify the Freezable, then you
should freeze it to gain the performance benefits described earlier.

Once you call a freezable's Freeze method, it can no longer be modified. Attempting to
modify a frozen object causes an InvalidOperationException to be thrown. The following
code throws an exception, because we attempt to modify the brush after it's been
frozen.

C#

Button myButton = new Button();


SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);

if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
myButton.Background = myBrush;

try {

// Throws an InvalidOperationException, because the brush is frozen.


myBrush.Color = Colors.Red;
}catch(InvalidOperationException ex)
{
MessageBox.Show("Invalid operation: " + ex.ToString());
}

To avoid throwing this exception, you can use the IsFrozen method to determine
whether a Freezable is frozen.

C#

Button myButton = new Button();


SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);

if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}

myButton.Background = myBrush;

if (myBrush.IsFrozen) // Evaluates to true.


{
// If the brush is frozen, create a clone and
// modify the clone.
SolidColorBrush myBrushClone = myBrush.Clone();
myBrushClone.Color = Colors.Red;
myButton.Background = myBrushClone;
}
else
{
// If the brush is not frozen,
// it can be modified directly.
myBrush.Color = Colors.Red;
}

In the preceding code example, a modifiable copy was made of a frozen object using
the Clone method. The next section discusses cloning in more detail.

7 Note
Because a frozen freezable cannot be animated, the animation system will
automatically create modifiable clones of frozen Freezable objects when you try to
animate them with a Storyboard. To eliminate the performance overhead caused
by cloning, leave an object unfrozen if you intend to animate it. For more
information about animating with storyboards, see the Storyboards Overview.

Freezing from Markup


To freeze a Freezable object declared in markup, you use the
PresentationOptions:Freeze attribute. In the following example, a SolidColorBrush is

declared as a page resource and frozen. It is then used to set the background of a
button.

XAML

<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/pres
entation/options"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="PresentationOptions">

<Page.Resources>

<!-- This resource is frozen. -->


<SolidColorBrush
x:Key="MyBrush"
PresentationOptions:Freeze="True"
Color="Red" />
</Page.Resources>

<StackPanel>

<Button Content="A Button"


Background="{StaticResource MyBrush}">
</Button>

</StackPanel>
</Page>

To use the Freeze attribute, you must map to the presentation options namespace:
http://schemas.microsoft.com/winfx/2006/xaml/presentation/options .

PresentationOptions is the recommended prefix for mapping this namespace:


XAML

xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/pres
entation/options"

Because not all XAML readers recognize this attribute, it's recommended that you use
the mc:Ignorable Attribute to mark the Presentation:Freeze attribute as ignorable:

XAML

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="PresentationOptions"

For more information, see the mc:Ignorable Attribute page.

"Unfreezing" a Freezable
Once frozen, a Freezable can never be modified or unfrozen; however, you can create an
unfrozen clone using the Clone or CloneCurrentValue method.

In the following example, the button's background is set with a brush and that brush is
then frozen. An unfrozen copy is made of the brush using the Clone method. The clone
is modified and used to change the button's background from yellow to red.

C#

Button myButton = new Button();


SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);

// Freezing a Freezable before it provides


// performance improvements if you don't
// intend on modifying it.
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}

myButton.Background = myBrush;

// If you need to modify a frozen brush,


// the Clone method can be used to
// create a modifiable copy.
SolidColorBrush myBrushClone = myBrush.Clone();

// Changing myBrushClone does not change


// the color of myButton, because its
// background is still set by myBrush.
myBrushClone.Color = Colors.Red;

// Replacing myBrush with myBrushClone


// makes the button change to red.
myButton.Background = myBrushClone;

7 Note

Regardless of which clone method you use, animations are never copied to the new
Freezable.

The Clone and CloneCurrentValue methods produce deep copies of the freezable. If the
freezable contains other frozen freezable objects, they are also cloned and made
modifiable. For example, if you clone a frozen PathGeometry to make it modifiable, the
figures and segments it contains are also copied and made modifiable.

Creating Your Own Freezable Class


A class that derives from Freezable gains the following features.

Special states: a read-only (frozen) and a writable state.

Thread safety: a frozen Freezable can be shared across threads.

Detailed change notification: Unlike other DependencyObjects, Freezable objects


provide change notifications when sub-property values change.

Easy cloning: the Freezable class has already implemented several methods that
produce deep clones.

A Freezable is a type of DependencyObject, and therefore uses the dependency


property system. Your class properties don't have to be dependency properties, but
using dependency properties will reduce the amount of code you have to write, because
the Freezable class was designed with dependency properties in mind. For more
information about the dependency property system, see the Dependency Properties
Overview.

Every Freezable subclass must override the CreateInstanceCore method. If your class
uses dependency properties for all its data, you're finished.

If your class contains non-dependency property data members, you must also override
the following methods:

CloneCore
CloneCurrentValueCore

GetAsFrozenCore

GetCurrentValueAsFrozenCore

FreezeCore

You must also observe the following rules for accessing and writing to data members
that are not dependency properties:

At the beginning of any API that reads non-dependency property data members,
call the ReadPreamble method.

At the beginning of any API that writes non-dependency property data members,
call the WritePreamble method. (Once you've called WritePreamble in an API, you
don't need to make an additional call to ReadPreamble if you also read non-
dependency property data members.)

Call the WritePostscript method before exiting methods that write to non-
dependency property data members.

If your class contains non-dependency-property data members that are


DependencyObject objects, you must also call the OnFreezablePropertyChanged
method each time you change one of their values, even if you're setting the member to
null .

7 Note

It's very important that you begin each Freezable method you override with a call
to the base implementation.

For an example of a custom Freezable class, see the Custom Animation Sample .

See also
Freezable
Custom Animation Sample
Dependency Properties Overview
Custom Dependency Properties
Alignment, Margins, and Padding
Overview
Article • 03/17/2022

The FrameworkElement class exposes several properties that are used to precisely
position child elements. This topic discusses four of the most important properties:
HorizontalAlignment, Margin, Padding, and VerticalAlignment. The effects of these
properties are important to understand, because they provide the basis for controlling
the position of elements in Windows Presentation Foundation (WPF) applications.

Introduction to Element Positioning


There are numerous ways to position elements using WPF. However, achieving ideal
layout goes beyond simply choosing the right Panel element. Fine control of positioning
requires an understanding of the HorizontalAlignment, Margin, Padding, and
VerticalAlignment properties.

The following illustration shows a layout scenario that utilizes several positioning
properties.

At first glance, the Button elements in this illustration may appear to be placed
randomly. However, their positions are actually precisely controlled by using a
combination of margins, alignments, and padding.

The following example describes how to create the layout in the preceding illustration. A
Border element encapsulates a parent StackPanel, with a Padding value of 15 device
independent pixels. This accounts for the narrow LightBlue band that surrounds the
child StackPanel. Child elements of the StackPanel are used to illustrate each of the
various positioning properties that are detailed in this topic. Three Button elements are
used to demonstrate both the Margin and HorizontalAlignment properties.

C#
// Create the application's main Window.
mainWindow = new Window ();
mainWindow.Title = "Margins, Padding and Alignment Sample";

// Add a Border
myBorder = new Border();
myBorder.Background = Brushes.LightBlue;
myBorder.BorderBrush = Brushes.Black;
myBorder.Padding = new Thickness(15);
myBorder.BorderThickness = new Thickness(2);

myStackPanel = new StackPanel();


myStackPanel.Background = Brushes.White;
myStackPanel.HorizontalAlignment = HorizontalAlignment.Center;
myStackPanel.VerticalAlignment = VerticalAlignment.Top;

TextBlock myTextBlock = new TextBlock();


myTextBlock.Margin = new Thickness(5, 0, 5, 0);
myTextBlock.FontSize = 18;
myTextBlock.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock.Text = "Alignment, Margin and Padding Sample";
Button myButton1 = new Button();
myButton1.HorizontalAlignment = HorizontalAlignment.Left;
myButton1.Margin = new Thickness(20);
myButton1.Content = "Button 1";
Button myButton2 = new Button();
myButton2.HorizontalAlignment = HorizontalAlignment.Right;
myButton2.Margin = new Thickness(10);
myButton2.Content = "Button 2";
Button myButton3 = new Button();
myButton3.HorizontalAlignment = HorizontalAlignment.Stretch;
myButton3.Margin = new Thickness(0);
myButton3.Content = "Button 3";

// Add child elements to the parent StackPanel.


myStackPanel.Children.Add(myTextBlock);
myStackPanel.Children.Add(myButton1);
myStackPanel.Children.Add(myButton2);
myStackPanel.Children.Add(myButton3);

// Add the StackPanel as the lone Child of the Border.


myBorder.Child = myStackPanel;

// Add the Border as the Content of the Parent Window Object.


mainWindow.Content = myBorder;
mainWindow.Show ();

The following diagram provides a close-up view of the various positioning properties
that are used in the preceding sample. Subsequent sections in this topic describe in
greater detail how to use each positioning property.
Understanding Alignment Properties
The HorizontalAlignment and VerticalAlignment properties describe how a child element
should be positioned within a parent element's allocated layout space. By using these
properties together, you can position child elements precisely. For example, child
elements of a DockPanel can specify four different horizontal alignments: Left, Right, or
Center, or to Stretch to fill available space. Similar values are available for vertical
positioning.

7 Note

Explicitly-set Height and Width properties on an element take precedence over the
Stretch property value. Attempting to set Height, Width, and a
HorizontalAlignment value of Stretch results in the Stretch request being
ignored.

HorizontalAlignment Property
The HorizontalAlignment property declares the horizontal alignment characteristics to
apply to child elements. The following table shows each of the possible values of the
HorizontalAlignment property.

Member Description

Left Child elements are aligned to the left of the parent element's allocated layout space.
Member Description

Center Child elements are aligned to the center of the parent element's allocated layout
space.

Right Child elements are aligned to the right of the parent element's allocated layout space.

Stretch Child elements are stretched to fill the parent element's allocated layout space.
(Default) Explicit Width and Height values take precedence.

The following example shows how to apply the HorizontalAlignment property to Button
elements. Each attribute value is shown, to better illustrate the various rendering
behaviors.

C#

Button myButton1 = new Button();


myButton1.HorizontalAlignment = HorizontalAlignment.Left;
myButton1.Content = "Button 1 (Left)";
Button myButton2 = new Button();
myButton2.HorizontalAlignment = HorizontalAlignment.Right;
myButton2.Content = "Button 2 (Right)";
Button myButton3 = new Button();
myButton3.HorizontalAlignment = HorizontalAlignment.Center;
myButton3.Content = "Button 3 (Center)";
Button myButton4 = new Button();
myButton4.HorizontalAlignment = HorizontalAlignment.Stretch;
myButton4.Content = "Button 4 (Stretch)";

The preceding code yields a layout similar to the following image. The positioning
effects of each HorizontalAlignment value are visible in the illustration.

VerticalAlignment Property
The VerticalAlignment property describes the vertical alignment characteristics to apply
to child elements. The following table shows each of the possible values for the
VerticalAlignment property.
Member Description

Top Child elements are aligned to the top of the parent element's allocated layout space.

Center Child elements are aligned to the center of the parent element's allocated layout
space.

Bottom Child elements are aligned to the bottom of the parent element's allocated layout
space.

Stretch Child elements are stretched to fill the parent element's allocated layout space.
(Default) Explicit Width and Height values take precedence.

The following example shows how to apply the VerticalAlignment property to Button
elements. Each attribute value is shown, to better illustrate the various rendering
behaviors. For purposes of this sample, a Grid element with visible gridlines is used as
the parent, to better illustrate the layout behavior of each property value.

C#

TextBlock myTextBlock = new TextBlock();


myTextBlock.FontSize = 18;
myTextBlock.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock.Text = "VerticalAlignment Sample";
Grid.SetRow(myTextBlock, 0);
Button myButton1 = new Button();
myButton1.VerticalAlignment = VerticalAlignment.Top;
myButton1.Content = "Button 1 (Top)";
Grid.SetRow(myButton1, 1);
Button myButton2 = new Button();
myButton2.VerticalAlignment = VerticalAlignment.Bottom;
myButton2.Content = "Button 2 (Bottom)";
Grid.SetRow(myButton2, 2);
Button myButton3 = new Button();
myButton3.VerticalAlignment = VerticalAlignment.Center;
myButton3.Content = "Button 3 (Center)";
Grid.SetRow(myButton3, 3);
Button myButton4 = new Button();
myButton4.VerticalAlignment = VerticalAlignment.Stretch;
myButton4.Content = "Button 4 (Stretch)";
Grid.SetRow(myButton4, 4);

XAML

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
WindowTitle="VerticalAlignment Sample">
<Border Background="LightBlue" BorderBrush="Black" BorderThickness="2"
Padding="15">
<Grid Background="White" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" FontSize="18"
HorizontalAlignment="Center">VerticalAlignment Sample</TextBlock>
<Button Grid.Row="1" Grid.Column="0"
VerticalAlignment="Top">Button 1 (Top)</Button>
<Button Grid.Row="2" Grid.Column="0"
VerticalAlignment="Bottom">Button 2 (Bottom)</Button>
<Button Grid.Row="3" Grid.Column="0"
VerticalAlignment="Center">Button 3 (Center)</Button>
<Button Grid.Row="4" Grid.Column="0"
VerticalAlignment="Stretch">Button 4 (Stretch)</Button>
</Grid>
</Border>
</Page>

The preceding code yields a layout similar to the following image. The positioning
effects of each VerticalAlignment value are visible in the illustration.

Understanding Margin Properties


The Margin property describes the distance between an element and its child or peers.
Margin values can be uniform, by using syntax like Margin="20" . With this syntax, a
uniform Margin of 20 device independent pixels would be applied to the element.
Margin values can also take the form of four distinct values, each value describing a
distinct margin to apply to the left, top, right, and bottom (in that order), like
Margin="0,10,5,25" . Proper use of the Margin property enables very fine control of an

element's rendering position and the rendering position of its neighbor elements and
children.
7 Note

A non-zero margin applies space outside the element's ActualWidth and


ActualHeight.

The following example shows how to apply uniform margins around a group of Button
elements. The Button elements are spaced evenly with a ten-pixel margin buffer in each
direction.

C#

Button myButton7 = new Button();


myButton7.Margin = new Thickness(10);
myButton7.Content = "Button 7";
Button myButton8 = new Button();
myButton8.Margin = new Thickness(10);
myButton8.Content = "Button 8";
Button myButton9 = new Button();
myButton9.Margin = new Thickness(10);
myButton9.Content = "Button 9";

XAML

<Button Margin="10">Button 7</Button>


<Button Margin="10">Button 8</Button>
<Button Margin="10">Button 9</Button>

In many instances, a uniform margin is not appropriate. In these cases, non-uniform


spacing can be applied. The following example shows how to apply non-uniform margin
spacing to child elements. Margins are described in this order: left, top, right, bottom.

C#

Button myButton1 = new Button();


myButton1.Margin = new Thickness(0, 10, 0, 10);
myButton1.Content = "Button 1";
Button myButton2 = new Button();
myButton2.Margin = new Thickness(0, 10, 0, 10);
myButton2.Content = "Button 2";
Button myButton3 = new Button();
myButton3.Margin = new Thickness(0, 10, 0, 10);

XAML

<Button Margin="0,10,0,10">Button 1</Button>


<Button Margin="0,10,0,10">Button 2</Button>
<Button Margin="0,10,0,10">Button 3</Button>

Understanding the Padding Property


Padding is similar to Margin in most respects. The Padding property is exposed on only
on a few classes, primarily as a convenience: Block, Border, Control, and TextBlock are
samples of classes that expose a Padding property. The Padding property enlarges the
effective size of a child element by the specified Thickness value.

The following example shows how to apply Padding to a parent Border element.

C#

myBorder = new Border();


myBorder.Background = Brushes.LightBlue;
myBorder.BorderBrush = Brushes.Black;
myBorder.BorderThickness = new Thickness(2);
myBorder.CornerRadius = new CornerRadius(45);
myBorder.Padding = new Thickness(25);

XAML

<Border Background="LightBlue"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="45"
Padding="25">

Using Alignment, Margins, and Padding in an


Application
HorizontalAlignment, Margin, Padding, and VerticalAlignment provide the positioning
control necessary to create a complex user interface (UI). You can use the effects of each
property to change child-element positioning, enabling flexibility in creating dynamic
applications and user experiences.

The following example demonstrates each of the concepts that are detailed in this topic.
Building on the infrastructure found in the first sample in this topic, this example adds a
Grid element as a child of the Border in the first sample. Padding is applied to the parent
Border element. The Grid is used to partition space between three child StackPanel
elements. Button elements are again used to show the various effects of Margin and
HorizontalAlignment. TextBlock elements are added to each ColumnDefinition to better
define the various properties applied to the Button elements in each column.

C#

mainWindow = new Window();

myBorder = new Border();


myBorder.Background = Brushes.LightBlue;
myBorder.BorderBrush = Brushes.Black;
myBorder.BorderThickness = new Thickness(2);
myBorder.CornerRadius = new CornerRadius(45);
myBorder.Padding = new Thickness(25);

// Define the Grid.


myGrid = new Grid();
myGrid.Background = Brushes.White;
myGrid.ShowGridLines = true;

// Define the Columns.


ColumnDefinition myColDef1 = new ColumnDefinition();
myColDef1.Width = new GridLength(1, GridUnitType.Auto);
ColumnDefinition myColDef2 = new ColumnDefinition();
myColDef2.Width = new GridLength(1, GridUnitType.Star);
ColumnDefinition myColDef3 = new ColumnDefinition();
myColDef3.Width = new GridLength(1, GridUnitType.Auto);

// Add the ColumnDefinitions to the Grid.


myGrid.ColumnDefinitions.Add(myColDef1);
myGrid.ColumnDefinitions.Add(myColDef2);
myGrid.ColumnDefinitions.Add(myColDef3);

// Add the first child StackPanel.


StackPanel myStackPanel = new StackPanel();
myStackPanel.HorizontalAlignment = HorizontalAlignment.Left;
myStackPanel.VerticalAlignment = VerticalAlignment.Top;
Grid.SetColumn(myStackPanel, 0);
Grid.SetRow(myStackPanel, 0);
TextBlock myTextBlock1 = new TextBlock();
myTextBlock1.FontSize = 18;
myTextBlock1.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock1.Margin = new Thickness(0, 0, 0, 15);
myTextBlock1.Text = "StackPanel 1";
Button myButton1 = new Button();
myButton1.Margin = new Thickness(0, 10, 0, 10);
myButton1.Content = "Button 1";
Button myButton2 = new Button();
myButton2.Margin = new Thickness(0, 10, 0, 10);
myButton2.Content = "Button 2";
Button myButton3 = new Button();
myButton3.Margin = new Thickness(0, 10, 0, 10);
TextBlock myTextBlock2 = new TextBlock();
myTextBlock2.Text = @"ColumnDefinition.Width = ""Auto""";
TextBlock myTextBlock3 = new TextBlock();
myTextBlock3.Text = @"StackPanel.HorizontalAlignment = ""Left""";
TextBlock myTextBlock4 = new TextBlock();
myTextBlock4.Text = @"StackPanel.VerticalAlignment = ""Top""";
TextBlock myTextBlock5 = new TextBlock();
myTextBlock5.Text = @"StackPanel.Orientation = ""Vertical""";
TextBlock myTextBlock6 = new TextBlock();
myTextBlock6.Text = @"Button.Margin = ""1,10,0,10""";
myStackPanel.Children.Add(myTextBlock1);
myStackPanel.Children.Add(myButton1);
myStackPanel.Children.Add(myButton2);
myStackPanel.Children.Add(myButton3);
myStackPanel.Children.Add(myTextBlock2);
myStackPanel.Children.Add(myTextBlock3);
myStackPanel.Children.Add(myTextBlock4);
myStackPanel.Children.Add(myTextBlock5);
myStackPanel.Children.Add(myTextBlock6);

// Add the second child StackPanel.


StackPanel myStackPanel2 = new StackPanel();
myStackPanel2.HorizontalAlignment = HorizontalAlignment.Stretch;
myStackPanel2.VerticalAlignment = VerticalAlignment.Top;
myStackPanel2.Orientation = Orientation.Vertical;
Grid.SetColumn(myStackPanel2, 1);
Grid.SetRow(myStackPanel2, 0);
TextBlock myTextBlock7 = new TextBlock();
myTextBlock7.FontSize = 18;
myTextBlock7.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock7.Margin = new Thickness(0, 0, 0, 15);
myTextBlock7.Text = "StackPanel 2";
Button myButton4 = new Button();
myButton4.Margin = new Thickness(10, 0, 10, 0);
myButton4.Content = "Button 4";
Button myButton5 = new Button();
myButton5.Margin = new Thickness(10, 0, 10, 0);
myButton5.Content = "Button 5";
Button myButton6 = new Button();
myButton6.Margin = new Thickness(10, 0, 10, 0);
myButton6.Content = "Button 6";
TextBlock myTextBlock8 = new TextBlock();
myTextBlock8.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock8.Text = @"ColumnDefinition.Width = ""*""";
TextBlock myTextBlock9 = new TextBlock();
myTextBlock9.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock9.Text = @"StackPanel.HorizontalAlignment = ""Stretch""";
TextBlock myTextBlock10 = new TextBlock();
myTextBlock10.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock10.Text = @"StackPanel.VerticalAlignment = ""Top""";
TextBlock myTextBlock11 = new TextBlock();
myTextBlock11.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock11.Text = @"StackPanel.Orientation = ""Horizontal""";
TextBlock myTextBlock12 = new TextBlock();
myTextBlock12.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock12.Text = @"Button.Margin = ""10,0,10,0""";
myStackPanel2.Children.Add(myTextBlock7);
myStackPanel2.Children.Add(myButton4);
myStackPanel2.Children.Add(myButton5);
myStackPanel2.Children.Add(myButton6);
myStackPanel2.Children.Add(myTextBlock8);
myStackPanel2.Children.Add(myTextBlock9);
myStackPanel2.Children.Add(myTextBlock10);
myStackPanel2.Children.Add(myTextBlock11);
myStackPanel2.Children.Add(myTextBlock12);

// Add the final child StackPanel.


StackPanel myStackPanel3 = new StackPanel();
myStackPanel3.HorizontalAlignment = HorizontalAlignment.Left;
myStackPanel3.VerticalAlignment = VerticalAlignment.Top;
Grid.SetColumn(myStackPanel3, 2);
Grid.SetRow(myStackPanel3, 0);
TextBlock myTextBlock13 = new TextBlock();
myTextBlock13.FontSize = 18;
myTextBlock13.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock13.Margin = new Thickness(0, 0, 0, 15);
myTextBlock13.Text = "StackPanel 3";
Button myButton7 = new Button();
myButton7.Margin = new Thickness(10);
myButton7.Content = "Button 7";
Button myButton8 = new Button();
myButton8.Margin = new Thickness(10);
myButton8.Content = "Button 8";
Button myButton9 = new Button();
myButton9.Margin = new Thickness(10);
myButton9.Content = "Button 9";
TextBlock myTextBlock14 = new TextBlock();
myTextBlock14.Text = @"ColumnDefinition.Width = ""Auto""";
TextBlock myTextBlock15 = new TextBlock();
myTextBlock15.Text = @"StackPanel.HorizontalAlignment = ""Left""";
TextBlock myTextBlock16 = new TextBlock();
myTextBlock16.Text = @"StackPanel.VerticalAlignment = ""Top""";
TextBlock myTextBlock17 = new TextBlock();
myTextBlock17.Text = @"StackPanel.Orientation = ""Vertical""";
TextBlock myTextBlock18 = new TextBlock();
myTextBlock18.Text = @"Button.Margin = ""10""";
myStackPanel3.Children.Add(myTextBlock13);
myStackPanel3.Children.Add(myButton7);
myStackPanel3.Children.Add(myButton8);
myStackPanel3.Children.Add(myButton9);
myStackPanel3.Children.Add(myTextBlock14);
myStackPanel3.Children.Add(myTextBlock15);
myStackPanel3.Children.Add(myTextBlock16);
myStackPanel3.Children.Add(myTextBlock17);
myStackPanel3.Children.Add(myTextBlock18);

// Add child content to the parent Grid.


myGrid.Children.Add(myStackPanel);
myGrid.Children.Add(myStackPanel2);
myGrid.Children.Add(myStackPanel3);

// Add the Grid as the lone child of the Border.


myBorder.Child = myGrid;
// Add the Border to the Window as Content and show the Window.
mainWindow.Content = myBorder;
mainWindow.Title = "Margin, Padding, and Alignment Sample";
mainWindow.Show();

XAML

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowTitle="Margins, Padding and Alignment Sample">
<Border Background="LightBlue"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="45"
Padding="25">
<Grid Background="White" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>

<StackPanel Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left"


Name="StackPanel1" VerticalAlignment="Top">
<TextBlock FontSize="18" HorizontalAlignment="Center"
Margin="0,0,0,15">StackPanel1</TextBlock>
<Button Margin="0,10,0,10">Button 1</Button>
<Button Margin="0,10,0,10">Button 2</Button>
<Button Margin="0,10,0,10">Button 3</Button>
<TextBlock>ColumnDefinition.Width="Auto"</TextBlock>
<TextBlock>StackPanel.HorizontalAlignment="Left"</TextBlock>
<TextBlock>StackPanel.VerticalAlignment="Top"</TextBlock>
<TextBlock>StackPanel.Orientation="Vertical"</TextBlock>
<TextBlock>Button.Margin="0,10,0,10"</TextBlock>
</StackPanel>

<StackPanel Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch"


Name="StackPanel2" VerticalAlignment="Top" Orientation="Vertical">
<TextBlock FontSize="18" HorizontalAlignment="Center"
Margin="0,0,0,15">StackPanel2</TextBlock>
<Button Margin="10,0,10,0">Button 4</Button>
<Button Margin="10,0,10,0">Button 5</Button>
<Button Margin="10,0,10,0">Button 6</Button>
<TextBlock HorizontalAlignment="Center">ColumnDefinition.Width="*"
</TextBlock>
<TextBlock
HorizontalAlignment="Center">StackPanel.HorizontalAlignment="Stretch"
</TextBlock>
<TextBlock
HorizontalAlignment="Center">StackPanel.VerticalAlignment="Top"</TextBlock>
<TextBlock
HorizontalAlignment="Center">StackPanel.Orientation="Horizontal"</TextBlock>
<TextBlock HorizontalAlignment="Center">Button.Margin="10,0,10,0"
</TextBlock>
</StackPanel>

<StackPanel Grid.Column="2" Grid.Row="0" HorizontalAlignment="Left"


Name="StackPanel3" VerticalAlignment="Top">
<TextBlock FontSize="18" HorizontalAlignment="Center"
Margin="0,0,0,15">StackPanel3</TextBlock>
<Button Margin="10">Button 7</Button>
<Button Margin="10">Button 8</Button>
<Button Margin="10">Button 9</Button>
<TextBlock>ColumnDefinition.Width="Auto"</TextBlock>
<TextBlock>StackPanel.HorizontalAlignment="Left"</TextBlock>
<TextBlock>StackPanel.VerticalAlignment="Top"</TextBlock>
<TextBlock>StackPanel.Orientation="Vertical"</TextBlock>
<TextBlock>Button.Margin="10"</TextBlock>
</StackPanel>
</Grid>
</Border>
</Page>

When compiled, the preceding application yields a UI that looks like the following
illustration. The effects of the various property values are evident in the spacing between
elements, and significant property values for elements in each column are shown within
TextBlock elements.

What's Next
Positioning properties defined by the FrameworkElement class enable fine control of
element placement within WPF applications. You now have several techniques you can
use to better position elements using WPF.

Additional resources are available that explain WPF layout in greater detail. The Panels
Overview topic contains more detail about the various Panel elements. The topic
Walkthrough: My first WPF desktop application introduces advanced techniques that
use layout elements to position components and bind their actions to data sources.

See also
FrameworkElement
HorizontalAlignment
VerticalAlignment
Margin
Panels Overview
Layout
WPF Layout Gallery Sample
Base Elements How-to Topics
Article • 02/06/2023

The topics in this section describe how to use the four WPF base elements: UIElement,
ContentElement, FrameworkElement, and FrameworkContentElement.

In This Section
Make a UIElement Transparent or Semi-Transparent
Animate the Size of a FrameworkElement
Determine Whether a Freezable Is Frozen
Handle a Loaded Event
Set Margins of Elements and Controls
Make a Freezable Read-Only
Obtain a Writable Copy of a Read-Only Freezable
Flip a UIElement Horizontally or Vertically
Use a ThicknessConverter Object
Handle the ContextMenuOpening Event

Reference
UIElement

ContentElement

FrameworkElement

FrameworkContentElement

Related Sections
Base Elements
How to: Make a UIElement Transparent
or Semi-Transparent
Article • 02/06/2023

This example shows how to make a UIElement transparent or semi-transparent. To make


an element transparent or semi-transparent, you set its Opacity property. A value of 0.0
makes the element completely transparent, while a value of 1.0 makes the element
completely opaque. A value of 0.5 makes the element 50% opaque, and so on. An
element's Opacity is set to 1.0 by default.

Example
The following example sets the Opacity of a button to 0.25 , making it and its contents
(in this case, the button's text) 25% opaque.

XAML

<!-- Both the button and its text are made 25% opaque. -->
<Button Opacity="0.25">A Button</Button>

C#

//
// Both the button and its text are made 25% opaque.
//
Button myTwentyFivePercentOpaqueButton = new Button();
myTwentyFivePercentOpaqueButton.Opacity = new Double();
myTwentyFivePercentOpaqueButton.Opacity = 0.25;
myTwentyFivePercentOpaqueButton.Content = "A Button";

If an element's contents have their own Opacity settings, those values are multiplied
against the containing elements Opacity.

The following example sets a button's Opacity to 0.25 , and the Opacity of an Image
control contained with in the button to 0.5 . As a result, the image appears 12.5%
opaque: 0.25 * 0.5 = 0.125.

XAML

<!-- The image contained within this button has an effective


opacity of 0.125 (0.25 * 0.5 = 0.125). -->
<Button Opacity="0.25">
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Margin="10">A Button</TextBlock>
<Image Source="sampleImages\berries.jpg" Width="50" Height="50"
Opacity="0.5"/>
</StackPanel>
</Button>

C#

//
// The image contained within this button has an
// effective opacity of 0.125 (0.25*0.5 = 0.125);
//
Button myImageButton = new Button();
myImageButton.Opacity = new Double();
myImageButton.Opacity = 0.25;

StackPanel myImageStackPanel = new StackPanel();


myImageStackPanel.Orientation = Orientation.Horizontal;

TextBlock myTextBlock = new TextBlock();


myTextBlock.VerticalAlignment = VerticalAlignment.Center;
myTextBlock.Margin = new Thickness(10);
myTextBlock.Text = "A Button";
myImageStackPanel.Children.Add(myTextBlock);

Image myImage = new Image();


BitmapImage myBitmapImage = new BitmapImage();
myBitmapImage.BeginInit();
myBitmapImage.UriSource = new
Uri("sampleImages/berries.jpg",UriKind.Relative);
myBitmapImage.EndInit();
myImage.Source = myBitmapImage;
ImageBrush myImageBrush = new ImageBrush(myBitmapImage);
myImage.Width = 50;
myImage.Height = 50;
myImage.Opacity = 0.5;
myImageStackPanel.Children.Add(myImage);
myImageButton.Content = myImageStackPanel;

Another way to control the opacity of an element is to set the opacity of the Brush that
paints the element. This approach enables you to selectively alter the opacity of portions
of an element, and provides performance benefits over using the element's Opacity
property. The following example sets the Opacity of a SolidColorBrush used to paint the
button's Background is set to 0.25 . As a result, the brush's background is 25% opaque,
but its contents (the button's text) remain 100% opaque.

XAML
<!-- This button's background is made 25% opaque, but its
text remains 100% opaque. -->
<Button>
<Button.Background>
<SolidColorBrush Color="Gray" Opacity="0.25" />
</Button.Background>
A Button
</Button>

C#

//
// This button's background is made 25% opaque,
// but its text remains 100% opaque.
//
Button myOpaqueTextButton = new Button();
SolidColorBrush mySolidColorBrush = new SolidColorBrush(Colors.Gray);
mySolidColorBrush.Opacity = 0.25;
myOpaqueTextButton.Background = mySolidColorBrush;
myOpaqueTextButton.Content = "A Button";

You may also control the opacity of individual colors within a brush. For more
information about colors and brushes, see Painting with Solid Colors and Gradients
Overview. For an example showing how to animate an element's opacity, see Animate
the Opacity of an Element or Brush.
How to: Animate the Size of a
FrameworkElement
Article • 02/06/2023

To animate the size of a FrameworkElement, you can either animate its Width and
Height properties or use an animated ScaleTransform.

In the following example animates the size of two buttons using these two approaches.
One button is resized by animating its Width property and another is resized by
animating a ScaleTransform applied to its RenderTransform property. Each button
contains some text. Initially, the text appears the same in both buttons, but as the
buttons are resized, the text in the second button becomes distorted.

Example
XAML

<!-- AnimatingSizeExample.xaml
This example shows two ways of animating the size
of a framework element. -->
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Microsoft.Samples.Animation.AnimatingSizeExample"
WindowTitle="Animating Size Example">
<Canvas Width="650" Height="400">

<Button Name="AnimatedWidthButton"
Canvas.Left="20" Canvas.Top="20"
Width="200" Height="150"
BorderBrush="Red" BorderThickness="5">
Click Me
<Button.Triggers>

<!-- Animate the button's Width property. -->


<EventTrigger RoutedEvent="Button.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="AnimatedWidthButton"
Storyboard.TargetProperty="(Button.Width)"
To="500" Duration="0:0:10" AutoReverse="True"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>

<Button
Canvas.Left="20" Canvas.Top="200"
Width="200" Height="150"
BorderBrush="Black" BorderThickness="3">
Click Me
<Button.RenderTransform>
<ScaleTransform x:Name="MyAnimatedScaleTransform"
ScaleX="1" ScaleY="1" />
</Button.RenderTransform>
<Button.Triggers>

<!-- Animate the ScaleX property of a ScaleTransform


applied to the button. -->
<EventTrigger RoutedEvent="Button.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="MyAnimatedScaleTransform"
Storyboard.TargetProperty="(ScaleTransform.ScaleX)"
To="3.0" Duration="0:0:10" AutoReverse="True"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Canvas>
</Page>

When you transform an element, the entire element and its contents are transformed.
When you directly alter the size of an element, as in the case of the first button, the
element's contents are not resized unless their size and position depend on the size of
their parent element.

Animating the size of an element by applying an animated transform to its


RenderTransform property provides better performance than animated its Width and
Height directly, because the RenderTransform property does not trigger a layout pass.

For more information about animating properties, see the Animation Overview. For
more information about transforms, see the Transforms Overview.
How to: Determine Whether a Freezable
Is Frozen
Article • 02/06/2023

This example shows how to determine whether a Freezable object is frozen. If you try to
modify a frozen Freezable object, it throws an InvalidOperationException. To avoid
throwing this exception, use the IsFrozen property of the Freezable object to determine
whether it is frozen.

Example
The following example freezes a SolidColorBrush and then tests it by using the IsFrozen
property to determine whether it is frozen.

C#

Button myButton = new Button();


SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);

if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}

myButton.Background = myBrush;

if (myBrush.IsFrozen) // Evaluates to true.


{
// If the brush is frozen, create a clone and
// modify the clone.
SolidColorBrush myBrushClone = myBrush.Clone();
myBrushClone.Color = Colors.Red;
myButton.Background = myBrushClone;
}
else
{
// If the brush is not frozen,
// it can be modified directly.
myBrush.Color = Colors.Red;
}

For more information about Freezable objects, see the Freezable Objects Overview.
See also
Freezable
IsFrozen
Freezable Objects Overview
How-to Topics
How to: Handle a Loaded Event
Article • 02/06/2023

This example shows how to handle the FrameworkElement.Loaded event, and an


appropriate scenario for handling that event. The handler creates a Button when the
page loads.

Example
The following example uses Extensible Application Markup Language (XAML) together
with a code-behind file.

XAML

<StackPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.FELoaded"
Loaded="OnLoad"
Name="root"
>
</StackPanel>

C#

void OnLoad(object sender, RoutedEventArgs e)


{
Button b1 = new Button();
b1.Content = "New Button";
root.Children.Add(b1);
b1.Height = 25;
b1.Width = 200;
b1.HorizontalAlignment = HorizontalAlignment.Left;
}

See also
FrameworkElement
Object Lifetime Events
Routed Events Overview
How-to Topics
How to: Set Margins of Elements and
Controls
Article • 08/10/2023

This example describes how to set the Margin property, by changing any existing
property value for the margin in code-behind. The Margin property is a property of the
FrameworkElement base element, and is thus inherited by a variety of controls and other
elements.

This example is written in Extensible Application Markup Language (XAML), with a code-
behind file that the XAML refers to. The code-behind is shown in both a C# and a
Microsoft Visual Basic version.

Example
XAML

<Button Click="OnClick" Margin="10" Name="btn1">


Click To See Change!!</Button>

C#

void OnClick(object sender, RoutedEventArgs e)


{
// Get the current value of the property.
Thickness marginThickness = btn1.Margin;
// If the current leftlength value of margin is set to 10 then change it
to a new value.
// Otherwise change it back to 10.
if(marginThickness.Left == 10)
{
btn1.Margin = new Thickness(60);
} else {
btn1.Margin = new Thickness(10);
}
}
How to: Make a Freezable Read-Only
Article • 02/06/2023

This example shows how to make a Freezable read-only by calling its Freeze method.

You cannot freeze a Freezable object if any one of the following conditions is true
about the object:

It has animated or data bound properties.

It has properties that are set by a dynamic resource. For more information about
dynamic resources, see the XAML Resources.

It contains Freezable sub-objects that cannot be frozen.

If these conditions are false for your Freezable object and you do not intend to modify
it, consider freezing it to gain performance benefits.

Example
The following example freezes a SolidColorBrush, which is a type of Freezable object.

C#

Button myButton = new Button();


SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);

if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}

myButton.Background = myBrush;

For more information about Freezable objects, see the Freezable Objects Overview.

See also
Freezable
CanFreeze
Freeze
Freezable Objects Overview
How-to Topics
How to: Obtain a Writable Copy of a
Read-Only Freezable
Article • 02/06/2023

This example shows how to use the Clone method to create a writable copy of a read-
only Freezable.

After a Freezable object is marked as read-only ("frozen"), you cannot modify it.
However, you can use the Clone method to create a modifiable clone of the frozen
object.

Example
The following example creates a modifiable clone of a frozen SolidColorBrush object.

C#

Button myButton = new Button();


SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);

// Freezing a Freezable before it provides


// performance improvements if you don't
// intend on modifying it.
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}

myButton.Background = myBrush;

// If you need to modify a frozen brush,


// the Clone method can be used to
// create a modifiable copy.
SolidColorBrush myBrushClone = myBrush.Clone();

// Changing myBrushClone does not change


// the color of myButton, because its
// background is still set by myBrush.
myBrushClone.Color = Colors.Red;

// Replacing myBrush with myBrushClone


// makes the button change to red.
myButton.Background = myBrushClone;

For more information about Freezable objects, see the Freezable Objects Overview.
See also
Freezable
CloneCurrentValue
Freezable Objects Overview
How-to Topics
How to: Flip a UIElement Horizontally or
Vertically
Article • 02/06/2023

This example shows how to use a ScaleTransform to flip a UIElement horizontally or


vertically. In this example, a Button control (a type of UIElement) is flipped by applying a
ScaleTransform to its RenderTransform property.

Illustration to flip a button


The following illustration shows the button to flip.

The UIElement to flip

The following shows the code that creates the button.

XAML

<Button Content="Flip me!" Padding="5">


</Button>

Illustration to flip a button horizontally


To flip the button horizontally, create a ScaleTransform and set its ScaleX property to -1.
Apply the ScaleTransform to the button's RenderTransform property.

XAML

<Button Content="Flip me!" Padding="5">


<Button.RenderTransform>
<ScaleTransform ScaleX="-1" />
</Button.RenderTransform>
</Button>
The button after applying the ScaleTransform

Illustration to flip a button at its place


As you can see from the previous illustration, the button was flipped, but it was also
moved. That's because the button was flipped from its top left corner. To flip the button
in place, you want to apply the ScaleTransform to its center, not its corner. An easy way
to apply the ScaleTransform to the buttons center is to set the button's
RenderTransformOrigin property to 0.5, 0.5.

XAML

<Button Content="Flip me!" Padding="5"


RenderTransformOrigin="0.5,0.5">
<Button.RenderTransform>
<ScaleTransform ScaleX="-1" />
</Button.RenderTransform>
</Button>

The button with a RenderTransformOrigin of 0.5, 0.5

Illustration to flip a button vertically


To flip the button vertically, set the ScaleTransform object's ScaleY property instead of its
ScaleX property.

XAML
<Button Content="Flip me!" Padding="5"
RenderTransformOrigin="0.5,0.5">
<Button.RenderTransform>
<ScaleTransform ScaleY="-1" />
</Button.RenderTransform>
</Button>

The vertically flipped button

See also
Transforms Overview
How to: Use a ThicknessConverter
Object
Article • 08/18/2022

Example
This example shows how to create an instance of ThicknessConverter and use it to
change the thickness of a border.

The example defines a custom method called changeThickness ; this method first
converts the contents of a ListBoxItem, as defined in a separate Extensible Application
Markup Language (XAML) file, to an instance of Thickness, and later converts the
content into a String. This method passes the ListBoxItem to a ThicknessConverter
object, which converts the Content of a ListBoxItem to an instance of Thickness. This
value is then passed back as the value of the BorderThickness property of the Border.

This example does not run.

C#

private void changeThickness(object sender, SelectionChangedEventArgs args)


{
ListBoxItem li = ((sender as ListBox).SelectedItem as ListBoxItem);
ThicknessConverter myThicknessConverter = new ThicknessConverter();
Thickness th1 =
(Thickness)myThicknessConverter.ConvertFromString(li.Content.ToString());
border1.BorderThickness = th1;
bThickness.Text = "Border.BorderThickness =" + li.Content.ToString();
}

See also
Thickness
ThicknessConverter
Border
How to: Change the Margin Property
How to: Convert a ListBoxItem to a new Data Type
Panels Overview
How to: Handle the
ContextMenuOpening Event
Article • 02/06/2023

The ContextMenuOpening event can be handled in an application to either adjust an


existing context menu prior to display or to suppress the menu that would otherwise be
displayed by setting the Handled property to true in the event data. The typical reason
for setting Handled to true in the event data is to replace the menu entirely with a new
ContextMenu object, which sometimes requires canceling the operation and starting a
new open. If you write handlers for the ContextMenuOpening event, you should be
aware of timing issues between a ContextMenu control and the service that is
responsible for opening and positioning context menus for controls in general. This
topic illustrates some of the code techniques for various context menu opening
scenarios and illustrates a case where the timing issue comes into play.

There are several scenarios for handling the ContextMenuOpening event:

Adjusting the menu items before display.

Replacing the entire menu before display.

Completely suppressing any existing context menu and displaying no context


menu.

Example

Adjusting the Menu Items Before Display


Adjusting the existing menu items is fairly simple and is probably the most common
scenario. You might do this in order to add or subtract context menu options in
response to current state information in your application or particular state information
that is available as a property on the object where the context menu is requested.

The general technique is to get the source of the event, which is the specific control that
was right-clicked, and get the ContextMenu property from it. You typically want to check
the Items collection to see what context menu items already exist in the menu, and then
add or remove appropriate new MenuItem items to or from the collection.

C#
void AddItemToCM(object sender, ContextMenuEventArgs e)
{
//check if Item4 is already there, this will probably run more than once
FrameworkElement fe = e.Source as FrameworkElement;
ContextMenu cm = fe.ContextMenu;
foreach (MenuItem mi in cm.Items)
{
if ((String)mi.Header == "Item4") return;
}
MenuItem mi4 = new MenuItem();
mi4.Header = "Item4";
fe.ContextMenu.Items.Add(mi4);
}

Replacing the Entire Menu Before Display


An alternative scenario is if you want to replace the entire context menu. You could of
course also use a variation of the preceding code, to remove every item of an existing
context menu and add new ones starting with item zero. But the more intuitive
approach for replacing all items in the context menu is to create a new ContextMenu,
populate it with items, and then set the FrameworkElement.ContextMenu property of a
control to be the new ContextMenu.

The following is the simple handler code for replacing a ContextMenu. The code
references a custom BuildMenu method, which is separated out because it is called by
more than one of the example handlers.

C#

void HandlerForCMO(object sender, ContextMenuEventArgs e)


{
FrameworkElement fe = e.Source as FrameworkElement;
fe.ContextMenu = BuildMenu();
}

C#

ContextMenu BuildMenu()
{
ContextMenu theMenu = new ContextMenu();
MenuItem mia = new MenuItem();
mia.Header = "Item1";
MenuItem mib = new MenuItem();
mib.Header = "Item2";
MenuItem mic = new MenuItem();
mic.Header = "Item3";
theMenu.Items.Add(mia);
theMenu.Items.Add(mib);
theMenu.Items.Add(mic);
return theMenu;
}

However, if you use this style of handler for ContextMenuOpening, you can potentially
expose a timing issue if the object where you are setting the ContextMenu does not
have a preexisting context menu. When a user right-clicks a control,
ContextMenuOpening is raised even if the existing ContextMenu is empty or null. But in
this case, whatever new ContextMenu you set on the source element arrives too late to
be displayed. Also, if the user happens to right-click a second time, this time your new
ContextMenu appears, the value is non null, and your handler will properly replace and
display the menu when the handler runs a second time. This suggests two possible
workarounds:

1. Insure that ContextMenuOpening handlers always run against controls that have at
least a placeholder ContextMenu available, which you intend to be replaced by the
handler code. In this case, you can still use the handler shown in the previous
example, but you typically want to assign a placeholder ContextMenu in the initial
markup:

XAML

<StackPanel>
<Rectangle Fill="Yellow" Width="200" Height="100"
ContextMenuOpening="HandlerForCMO">
<Rectangle.ContextMenu>
<ContextMenu>
<MenuItem>Initial menu; this will be replaced ...</MenuItem>
</ContextMenu>
</Rectangle.ContextMenu>
</Rectangle>
<TextBlock>Right-click the rectangle above, context menu gets
replaced</TextBlock>
</StackPanel>

2. Assume that the initial ContextMenu value might be null, based on some
preliminary logic. You could either check ContextMenu for null, or use a flag in
your code to check whether your handler has been run at least once. Because you
assume that the ContextMenu is about to be displayed, your handler then sets
Handled to true in the event data. To the ContextMenuService that is responsible
for context menu display, a true value for Handled in the event data represents a
request to cancel the display for the context menu / control combination that
raised the event.
Now that you have suppressed the potentially suspect context menu, the next step is to
supply a new one, then display it. Setting the new one is basically the same as the
previous handler: you build a new ContextMenu and set the control source's
FrameworkElement.ContextMenu property with it. The additional step is that you must
now force the display of the context menu, because you suppressed the first attempt. To
force the display, you set the Popup.IsOpen property to true within the handler. Be
careful when you do this, because opening the context menu in the handler raises the
ContextMenuOpening event again. If you reenter your handler, it becomes infinitely
recursive. This is why you always need to check for null or use a flag if you open a
context menu from within a ContextMenuOpening event handler.

Suppressing Any Existing Context Menu and


Displaying No Context Menu
The final scenario, writing a handler that suppresses a menu totally, is uncommon. If a
given control is not supposed to display a context menu, there are probably more
appropriate ways to assure this than by suppressing the menu just when a user requests
it. But if you want to use the handler to suppress a context menu and show nothing,
then your handler should simply set Handled to true in the event data. The
ContextMenuService that is responsible for displaying a context menu will check the
event data of the event it raised on the control. If the event was marked Handled
anywhere along the route, then the context menu open action that initiated the event is
suppressed.

C#

void HandlerForCMO2(object sender, ContextMenuEventArgs e)


{
if (!FlagForCustomContextMenu)
{
e.Handled = true; //need to suppress empty menu
FrameworkElement fe = e.Source as FrameworkElement;
fe.ContextMenu = BuildMenu();
FlagForCustomContextMenu = true;
fe.ContextMenu.IsOpen = true;
}
}
}

See also
ContextMenu
FrameworkElement.ContextMenu
Base Elements Overview
ContextMenu Overview
Element Tree and Serialization
Article • 02/06/2023

WPF programming elements often exist in some form of tree relationship to each other.
For instance, an application UI created in XAML can be conceptualized as an object tree.
The element tree can be further divided into two discrete yet sometimes parallel trees:
the logical tree and the visual tree. Serialization in WPF involves saving the state of these
two trees as well as application state and writing it to a file, potentially as XAML.

In This Section
Trees in WPF
Serialization Limitations of XamlWriter.Save
Initialization for Object Elements Not in an Object Tree
How-to Topics

Reference
System.Windows.Markup

LogicalTreeHelper

VisualTreeHelper

Related Sections
WPF Architecture
XAML in WPF
Base Elements
Properties
Events
Input
Resources
Styling and Templating
Threading Model
Trees in WPF
Article • 08/18/2022

In many technologies, elements and components are organized in a tree structure where
developers directly manipulate the object nodes in the tree to affect the rendering or
behavior of an application. Windows Presentation Foundation (WPF) also uses several
tree structure metaphors to define relationships between program elements. For the
most part WPF developers can create an application in code or define portions of the
application in XAML while thinking conceptually about the object tree metaphor, but
will be calling specific API or using specific markup to do so rather than some general
object tree manipulation API such as you might use in XML DOM. WPF exposes two
helper classes that provide a tree metaphor view, LogicalTreeHelper and
VisualTreeHelper. The terms visual tree and logical tree are also used in the WPF
documentation because these same trees are useful for understanding the behavior of
certain key WPF features. This topic defines what the visual tree and logical tree
represent, discusses how such trees relate to an overall object tree concept, and
introduces LogicalTreeHelper and VisualTreeHelpers.

Trees in WPF
The most complete tree structure in WPF is the object tree. If you define an application
page in WPF subsystems and affect choices you make in markup or code.

Even though you do not always manipulate either the logical tree or the visual tree
directly, understanding the concepts of how the trees interact is useful for
understanding WPF as a technology. Thinking of WPF as a tree metaphor of some kind
is also crucial to understanding how property inheritance and event routing work in
WPF.

7 Note

Because the object tree is more of a concept than an actual API, another way to
think of the concept is as an object graph. In practice, there are relationships
between objects at run time where the tree metaphor will break down.
Nevertheless, particularly with XAML-defined UI, the tree metaphor is relevant
enough that most WPF documentation will use the term object tree when
referencing this general concept.
The Logical Tree
In WPF, you add content to UI elements by setting properties of the objects that back
those elements. For example, you add items to a ListBox control by manipulating its
Items property. By doing this, you are placing items into the ItemCollection that is the
Items property value. Similarly, to add objects to a DockPanel, you manipulate its
Children property value. Here, you are adding objects to the UIElementCollection. For a
code example, see How to: Add an Element Dynamically.

In Extensible Application Markup Language (XAML), when you place list items in a
ListBox or controls or other UI elements in a DockPanel, you also use the Items and
Children properties, either explicitly or implicitly, as in the following example.

XAML

<DockPanel
Name="ParentElement"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<!--implicit: <DockPanel.Children>-->
<ListBox DockPanel.Dock="Top">
<!--implicit: <ListBox.Items>-->
<ListBoxItem>
<TextBlock>Dog</TextBlock>
</ListBoxItem>
<ListBoxItem>
<TextBlock>Cat</TextBlock>
</ListBoxItem>
<ListBoxItem>
<TextBlock>Fish</TextBlock>
</ListBoxItem>
<!--implicit: </ListBox.Items>-->
</ListBox>
<Button Height="20" Width="100" DockPanel.Dock="Top">Buy a Pet</Button>
<!--implicit: </DockPanel.Children>-->
</DockPanel>

If you were to process this XAML as XML under a document object model, and if you
had included the tags commented out as implicit (which would have been legal), then
the resulting XML DOM tree would have included elements for <ListBox.Items> and the
other implicit items. But XAML does not process that way when you read the markup
and write to objects, the resulting object graph does not literally include ListBox.Items .
It does however have a ListBox property named Items that contains a ItemCollection,
and that ItemCollection is initialized but empty when the ListBox XAML is processed.
Then, each child object element that exists as content for the ListBox is added to the
ItemCollection by parser calls to ItemCollection.Add . This example of processing XAML
into an object tree is so far seemingly an example where the created object tree is
basically the logical tree.

However, the logical tree is not the entire object graph that exists for your application UI
at run time, even with the XAML implicit syntax items factored out. The main reason for
this is visuals and templates. For example, consider the Button. The logical tree reports
the Button object and also its string Content . But there is more to this button in the run-
time object tree. In particular, the button only appears on screen the way it does
because a specific Button control template was applied. The visuals that come from an
applied template (such as the template-defined Border of dark gray around the visual
button) are not reported in the logical tree, even if you are looking at the logical tree
during run time (such as handling an input event from the visible UI and then reading
the logical tree). To find the template visuals, you would instead need to examine the
visual tree.

For more information about how XAML syntax maps to the created object graph, and
implicit syntax in XAML, see XAML Syntax In Detail or XAML in WPF.

The Purpose of the Logical Tree


The logical tree exists so that content models can readily iterate over their possible child
objects, and so that content models can be extensible. Also, the logical tree provides a
framework for certain notifications, such as when all objects in the logical tree are
loaded. Basically, the logical tree is an approximation of a run time object graph at the
framework level, which excludes visuals, but is adequate for many querying operations
against your own run time application's composition.

In addition, both static and dynamic resource references are resolved by looking
upwards through the logical tree for Resources collections on the initial requesting
object, and then continuing up the logical tree and checking each FrameworkElement
(or FrameworkContentElement) for another Resources value that contains a
ResourceDictionary, possibly containing that key. The logical tree is used for resource
lookup when both the logical tree and the visual tree are present. For more information
on resource dictionaries and lookup, see XAML Resources.

Composition of the Logical Tree


The logical tree is defined at the WPF framework-level, which means that the WPF base
element that is most relevant for logical tree operations is either FrameworkElement or
FrameworkContentElement. However, as you can see if you actually use the
LogicalTreeHelper API, the logical tree sometimes contains nodes that are not either
FrameworkElement or FrameworkContentElement. For instance, the logical tree reports
the Text value of a TextBlock, which is a string.

Overriding the Logical Tree


Advanced control authors can override the logical tree by overriding several APIs that
define how a general object or content model adds or removes objects within the
logical tree. For an example of how to override the logical tree, see Override the Logical
Tree.

Property Value Inheritance


Property value inheritance operates through a hybrid tree. The actual metadata that
contains the Inherits property that enables property inheritance is the WPF framework-
level FrameworkPropertyMetadata class. Therefore, both the parent that holds the
original value and the child object that inherits that value must both be
FrameworkElement or FrameworkContentElement, and they must both be part of some
logical tree. However, for existing WPF properties that support property inheritance,
property value inheritance is able to perpetuate through an intervening object that is
not in the logical tree. Mainly this is relevant for having template elements use any
inherited property values set either on the instance that is templated, or at still higher
levels of page-level composition and therefore higher in the logical tree. In order for
property value inheritance to work consistently across such a boundary, the inheriting
property must be registered as an attached property, and you should follow this pattern
if you intend to define a custom dependency property with property inheritance
behavior. The exact tree used for property inheritance cannot be entirely anticipated by
a helper class utility method, even at run time. For more information, see Property Value
Inheritance.

The Visual Tree


In addition to the concept of the logical tree, there is also the concept of the visual tree
in WPF. The visual tree describes the structure of visual objects, as represented by the
Visual base class. When you write a template for a control, you are defining or
redefining the visual tree that applies for that control. The visual tree is also of interest
to developers who want lower-level control over drawing for performance and
optimization reasons. One exposure of the visual tree as part of conventional WPF
application programming is that event routes for a routed event mostly travel along the
visual tree, not the logical tree. This subtlety of routed event behavior might not be
immediately apparent unless you are a control author. Routing events through the visual
tree enables controls that implement composition at the visual level to handle events or
create event setters.

Trees, Content Elements, and Content Hosts


Content elements (classes that derive from ContentElement) are not part of the visual
tree; they do not inherit from Visual and do not have a visual representation. In order to
appear in a UI at all, a ContentElement must be hosted in a content host that is both a
Visual and a logical tree participant. Usually such an object is a FrameworkElement. You
can conceptualize that the content host is somewhat like a "browser" for the content
and chooses how to display that content within the screen region that the host controls.
When the content is hosted, the content can be made a participant in certain tree
processes that are normally associated with the visual tree. Generally, the
FrameworkElement host class includes implementation code that adds any hosted
ContentElement to the event route through subnodes of the content logical tree, even
though the hosted content is not part of the true visual tree. This is necessary so that a
ContentElement can source a routed event that routes to any element other than itself.

Tree Traversal
The LogicalTreeHelper class provides the GetChildren, GetParent, and FindLogicalNode
methods for logical tree traversal. In most cases, you should not have to traverse the
logical tree of existing controls, because these controls almost always expose their
logical child elements as a dedicated collection property that supports collection access
such as Add , an indexer, and so on. Tree traversal is mainly a scenario that is used by
control authors who choose not to derive from intended control patterns such as
ItemsControl or Panel where collection properties are already defined, and who intend
to provide their own collection property support.

The visual tree also supports a helper class for visual tree traversal, VisualTreeHelper. The
visual tree is not exposed as conveniently through control-specific properties, so the
VisualTreeHelper class is the recommended way to traverse the visual tree if that is
necessary for your programming scenario. For more information, see WPF Graphics
Rendering Overview.

7 Note

Sometimes it is necessary to examine the visual tree of an applied template. You


should be careful when using this technique. Even if you are traversing a visual tree
for a control where you define the template, consumers of your control can always
change the template by setting the Template property on instances, and even the
end user can influence the applied template by changing the system theme.

Routes for Routed Events as a "Tree"


As mentioned before, the route of any given routed event travels along a single and
predetermined path of a tree that is a hybrid of the visual and logical tree
representations. The event route can travel either in the up or down directions within
the tree depending on whether it is a tunneling or bubbling routed event. The event
route concept does not have a directly supporting helper class that could be used to
"walk" the event route independently of raising an event that actually routes. There is a
class that represents the route, EventRoute, but the methods of that class are generally
for internal use only.

Resource Dictionaries and Trees


Resource dictionary lookup for all Resources defined in a page traverses basically the
logical tree. Objects that are not in the logical tree can reference keyed resources, but
the resource lookup sequence begins at the point where that object is connected to the
logical tree. In WPF, only logical tree nodes can have a Resources property that contains
a ResourceDictionary, therefore there is no benefit in traversing the visual tree looking
for keyed resources from a ResourceDictionary.

However, resource lookup can also extend beyond the immediate logical tree. For
application markup, the resource lookup can then continue onward to application-level
resource dictionaries and then to theme support and system values that are referenced
as static properties or keys. Themes themselves can also reference system values outside
of the theme logical tree if the resource references are dynamic. For more information
on resource dictionaries and the lookup logic, see XAML Resources.

See also
Input Overview
WPF Graphics Rendering Overview
Routed Events Overview
Initialization for Object Elements Not in an Object Tree
WPF Architecture
Serialization Limitations of
XamlWriter.Save
Article • 02/06/2023

The API Save can be used to serialize the contents of a Windows Presentation
Foundation (WPF) application as a Extensible Application Markup Language (XAML) file.
However, there are some notable limitations in exactly what is serialized. These
limitations and some general considerations are documented in this topic.

Run-Time, Not Design-Time Representation


The basic philosophy of what is serialized by a call to Save is that the result will be a
representation of the object being serialized, at run-time. Many design-time properties
of the original XAML file may already be optimized or lost by the time that the XAML is
loaded as in-memory objects, and are not preserved when you call Save to serialize. The
serialized result is an effective representation of the constructed logical tree of the
application, but not necessarily of the original XAML that produced it. These issues make
it extremely difficult to use the Save serialization as part of an extensive XAML design
surface.

Serialization is Self-Contained
The serialized output of Save is self-contained; everything that is serialized is contained
inside a XAML single page, with a single root element, and no external references other
than URIs. For instance, if your page referenced resources from application resources,
these will appear as if they were a component of the page being serialized.

Extension References are Dereferenced


Common references to objects made by various markup extension formats, such as
StaticResource or Binding , will be dereferenced by the serialization process. These

were already dereferenced at the time that in-memory objects were created by the
application runtime, and the Save logic does not revisit the original XAML to restore
such references to the serialized output. This potentially freezes any databound or
resource obtained value to be the value last used by the run-time representation, with
only limited or indirect ability to distinguish such a value from any other value set
locally. Images are also serialized as object references to images as they exist in the
project, rather than as original source references, losing whatever filename or URI was
originally referenced. Even resources declared within the same page are seen serialized
into the point where they were referenced, rather than being preserved as a key of a
resource collection.

Event Handling is Not Preserved


When event handlers that are added through XAML are serialized, they are not
preserved. XAML without code-behind (and also without the related x:Code mechanism)
has no way of serializing runtime procedural logic. Because serialization is self-contained
and limited to the logical tree, there is no facility for storing the event handlers. As a
result, event handler attributes, both the attribute itself and the string value that names
the handler, are removed from the output XAML.

Realistic Scenarios for Use of XAMLWriter.Save


While the limitations listed here are fairly substantial, there are still several appropriate
scenarios for using Save for serialization.

Vector or graphical output: The output of the rendered area can be used to
reproduce the same vector or graphics when reloaded.

Rich text and flow documents: Text and all element formatting and element
containment within it is preserved in the output. This can be useful for mechanisms
that approximate a clipboard functionality.

Preserving business object data: If you have stored data in custom elements, such
as XML data, so long as your business objects follow basic XAML rules such as
providing custom constructors and conversion for by-reference property values,
these business objects can be perpetuated through serialization.
Initialization for Object Elements Not in
an Object Tree
Article • 02/06/2023

Some aspects of Windows Presentation Foundation (WPF) initialization are deferred to


processes that typically rely on that element being connected to either the logical tree
or visual tree. This topic describes the steps that may be necessary in order to initialize
an element that is not connected to either tree.

Elements and the Logical Tree


When you create an instance of a Windows Presentation Foundation (WPF) class in
code, you should be aware that several aspects of object initialization for a Windows
Presentation Foundation (WPF) class are deliberately not a part of the code that is
executed when calling the class constructor. Particularly for a control class, most of the
visual representation of that control is not defined by the constructor. Instead, the visual
representation is defined by the control's template. The template potentially comes
from a variety of sources, but most often the template is obtained from theme styles.
Templates are effectively late-binding; the necessary template is not attached to the
control in question until the control is ready for layout. And the control is not ready for
layout until it is attached to a logical tree that connects to a rendering surface at the
root. It is that root-level element that initiates the rendering of all of its child elements
as defined in the logical tree.

The visual tree also participates in this process. Elements that are part of the visual tree
through the templates are also not fully instantiated until connected.

The consequences of this behavior are that certain operations that rely on the
completed visual characteristics of an element require additional steps. An example is if
you are attempting to get the visual characteristics of a class that was constructed but
not yet attached to a tree. For instance, if you want to call Render on a
RenderTargetBitmap and the visual you are passing is an element not connected to a
tree, that element is not visually complete until additional initialization steps are
completed.

Using BeginInit and EndInit to Initialize the Element


Various classes in WPF implement the ISupportInitialize interface. You use the BeginInit
and EndInit methods of the interface to denote a region in your code that contains
initialization steps (such as setting property values that affect rendering). After EndInit is
called in the sequence, the layout system can process the element and start looking for
an implicit style.

If the element you are setting properties on is a FrameworkElement or


FrameworkContentElement derived class, then you can call the class versions of
BeginInit and EndInit rather than casting to ISupportInitialize.

Sample Code
The following example is sample code for a console application that uses rendering APIs
and XamlReader.Load(Stream) of a loose XAML file to illustrate the proper placement of
BeginInit and EndInit around other API calls that adjust properties that affect rendering.

The example illustrates the main function only. The functions Rasterize and Save (not
shown) are utility functions that take care of image processing and IO.

C#

[STAThread]
static void Main(string[] args)
{
UIElement e;
string file = Directory.GetCurrentDirectory() + "\\starting.xaml";
using (Stream stream = File.Open(file, FileMode.Open))
{
// loading files from current directory, project settings take care
of copying the file
ParserContext pc = new ParserContext();
pc.BaseUri = new Uri(file, UriKind.Absolute);
e = (UIElement)XamlReader.Load(stream, pc);
}

Size paperSize = new Size(8.5 * 96, 11 * 96);


e.Measure(paperSize);
e.Arrange(new Rect(paperSize));
e.UpdateLayout();

/*
* Render effect at normal dpi, indicator is the original RED
rectangle
*/
RenderTargetBitmap image1 = Rasterize(e, paperSize.Width,
paperSize.Height, 96, 96);
Save(image1, "render1.png");

Button b = new Button();


b.BeginInit();
b.Background = Brushes.Blue;
b.Width = b.Height = 200;
b.EndInit();
b.Measure(paperSize);
b.Arrange(new Rect(paperSize));
b.UpdateLayout();

// now render the altered version, with the element built up and
initialized

RenderTargetBitmap image2 = Rasterize(b, paperSize.Width,


paperSize.Height, 96, 96);
Save(image2, "render2.png");
}

See also
Trees in WPF
WPF Graphics Rendering Overview
XAML in WPF
Element Tree and Serialization How-to
Topics
Article • 02/06/2023

The topics in this section describe how to use the WPF element tree.

In This Section
Find an Element by Its Name
Override the Logical Tree

Reference
LogicalTreeHelper

VisualTreeHelper

System.Windows.Markup

Related Sections
How to: Find an Element by Its Name
Article • 02/06/2023

This example describes how to use the FindName method to find an element by its
Name value.

Example
In this example, the method to find a particular element by its name is written as the
event handler of a button. stackPanel is the Name of the root FrameworkElement being
searched, and the example method then visually indicates the found element by casting
it as TextBlock and changing one of the TextBlock visible UI properties.

C#

void Find(object sender, RoutedEventArgs e)


{
object wantedNode = stackPanel.FindName("dog");
if (wantedNode is TextBlock)
{
// Following executed if Text element was found.
TextBlock wantedChild = wantedNode as TextBlock;
wantedChild.Foreground = Brushes.Blue;
}
}
How to: Override the Logical Tree
Article • 02/06/2023

Although it is not necessary in most cases, advanced control authors have the option to
override the logical tree.

Example
This example describes how to subclass StackPanel to override the logical tree, in this
case to enforce a behavior that the panel may only have and will only render a single
child element. This isn't necessarily a practically desirable behavior, but is shown here as
a means of illustrating the scenario for overriding an element's normal logical tree.

C#

public class SingletonPanel : StackPanel


{
//private UIElementCollection _children;
private FrameworkElement _child;

public SingletonPanel()
{
}

public FrameworkElement SingleChild


{

get { return _child; }


set
{
if (value == null)
{
RemoveLogicalChild(_child);
}
else
{
if (_child == null)
{
_child = value;
}
else
{
// raise an exception?
MessageBox.Show("Needs to be a single element");
}
}
}
}
public void SetSingleChild(object child)
{
this.AddLogicalChild(child);
}

public new void AddLogicalChild(object child)


{
_child = (FrameworkElement)child;
if (this.Children.Count == 1)
{
this.RemoveLogicalChild(this.Children[0]);
this.Children.Add((UIElement)child);
}
else
{
this.Children.Add((UIElement)child);
}
}

public new void RemoveLogicalChild(object child)


{
_child = null;
this.Children.Clear();
}
protected override IEnumerator LogicalChildren
{
get
{
// cheat, make a list with one member and return the enumerator
ArrayList _list = new ArrayList();
_list.Add(_child);
return (IEnumerator)_list.GetEnumerator();
}
}
}

For more information on the logical tree, see Trees in WPF.


Properties (WPF)
Article • 02/06/2023

Windows Presentation Foundation (WPF) provides a set of services that can be used to
extend the functionality of a common language runtime (CLR) property. Collectively,
these services are typically referred to as the WPF property system. A property that is
backed by the WPF property system is known as a dependency property.

In This Section
Dependency Properties Overview
Attached Properties Overview
Custom Dependency Properties
Dependency Property Metadata
Dependency Property Callbacks and Validation
Framework Property Metadata
Dependency Property Value Precedence
Read-Only Dependency Properties
Property Value Inheritance
Dependency Property Security
Safe Constructor Patterns for DependencyObjects
Collection-Type Dependency Properties
XAML Loading and Dependency Properties
How-to Topics

Reference
DependencyProperty

PropertyMetadata

FrameworkPropertyMetadata

DependencyObject

Related Sections
WPF Architecture
XAML in WPF
Base Elements
Element Tree and Serialization
Events
Input
Resources
WPF Content Model
Threading Model
Dependency properties overview
Article • 02/06/2023

Windows Presentation Foundation (WPF) provides a set of services that can be used to
extend the functionality of a type's property. Collectively, these services are typically
referred to as the WPF property system. A property that is backed by the WPF property
system is known as a dependency property. This overview describes the WPF property
system and the capabilities of a dependency property. This includes how to use existing
dependency properties in XAML and in code. This overview also introduces specialized
aspects of dependency properties, such as dependency property metadata, and how to
create your own dependency property in a custom class.

Prerequisites
This topic assumes that you have some basic knowledge of the .NET type system and
object-oriented programming. In order to follow the examples in this topic, you should
also understand XAML and know how to write WPF applications. For more information,
see Walkthrough: My first WPF desktop application.

Dependency properties and CLR properties


In WPF, properties are typically exposed as standard .NET properties. At a basic level,
you could interact with these properties directly and never know that they are
implemented as a dependency property. However, you should become familiar with
some or all of the features of the WPF property system, so that you can take advantage
of these features.

The purpose of dependency properties is to provide a way to compute the value of a


property based on the value of other inputs. These other inputs might include system
properties such as themes and user preference, just-in-time property determination
mechanisms such as data binding and animations/storyboards, multiple-use templates
such as resources and styles, or values known through parent-child relationships with
other elements in the element tree. In addition, a dependency property can be
implemented to provide self-contained validation, default values, callbacks that monitor
changes to other properties, and a system that can coerce property values based on
potentially runtime information. Derived classes can also change some specific
characteristics of an existing property by overriding dependency property metadata,
rather than overriding the actual implementation of existing properties or creating new
properties.
In the SDK reference, you can identify which property is a dependency property by the
presence of the Dependency Property Information section on the managed reference
page for that property. The Dependency Property Information section includes a link to
the DependencyProperty identifier field for that dependency property, and also includes
a list of the metadata options that are set for that property, per-class override
information, and other details.

Dependency properties back CLR properties


Dependency properties and the WPF property system extend property functionality by
providing a type that backs a property, as an alternative implementation to the standard
pattern of backing the property with a private field. The name of this type is
DependencyProperty. The other important type that defines the WPF property system is
DependencyObject. DependencyObject defines the base class that can register and own
a dependency property.

The following lists the terminology that is used with dependency properties:

Dependency property: A property that is backed by a DependencyProperty.

Dependency property identifier: A DependencyProperty instance, which is


obtained as a return value when registering a dependency property, and then
stored as a static member of a class. This identifier is used as a parameter for many
of the APIs that interact with the WPF property system.

CLR "wrapper": The actual get and set implementations for the property. These
implementations incorporate the dependency property identifier by using it in the
GetValue and SetValue calls, thus providing the backing for the property using the
WPF property system.

The following example defines the IsSpinning dependency property, and shows the
relationship of the DependencyProperty identifier to the property that it backs.

C#

public static readonly DependencyProperty IsSpinningProperty =


DependencyProperty.Register(
"IsSpinning", typeof(Boolean),
typeof(MyCode)
);
public bool IsSpinning
{
get { return (bool)GetValue(IsSpinningProperty); }
set { SetValue(IsSpinningProperty, value); }
}
The naming convention of the property and its backing DependencyProperty field is
important. The name of the field is always the name of the property, with the suffix
Property appended. For more information about this convention and the reasons for it,
see Custom Dependency Properties.

Setting property values


You can set properties either in code or in XAML.

Setting property values in XAML


The following XAML example specifies the background color of a button as red. This
example illustrates a case where the simple string value for a XAML attribute is type-
converted by the WPF XAML parser into a WPF type (a Color, by way of a
SolidColorBrush) in the generated code.

XAML

<Button Background="Red" Content="Button!"/>

XAML supports a variety of syntax forms for setting properties. Which syntax to use for a
particular property will depend on the value type that a property uses, as well as other
factors such as the presence of a type converter. For more information on XAML syntax
for property setting, see XAML in WPF and XAML Syntax In Detail.

As an example of non-attribute syntax, the following XAML example shows another


button background. This time rather than setting a simple solid color, the background is
set to an image, with an element representing that image and the source of that image
specified as an attribute of the nested element. This is an example of property element
syntax.

XAML

<Button Content="Button!">
<Button.Background>
<ImageBrush ImageSource="wavy.jpg"/>
</Button.Background>
</Button>

Setting properties in code


Setting dependency property values in code is typically just a call to the set
implementation exposed by the CLR "wrapper".

C#

Button myButton = new Button();


myButton.Width = 200.0;

Getting a property value is also essentially a call to the get "wrapper" implementation:

C#

double whatWidth;
whatWidth = myButton.Width;

You can also call the property system APIs GetValue and SetValue directly. This is not
typically necessary if you are using existing properties (the wrappers are more
convenient, and provide better exposure of the property for developer tools), but calling
the APIs directly is appropriate for certain scenarios.

Properties can be also set in XAML and then accessed later in code, through code-
behind. For details, see Code-Behind and XAML in WPF.

Property functionality provided by a


dependency property
A dependency property provides functionality that extends the functionality of a
property as opposed to a property that is backed by a field. Often, such functionality
represents or supports one of the following specific features:

Resources

Data binding

Styles

Animations

Metadata overrides

Property value inheritance

WPF Designer integration


Resources
A dependency property value can be set by referencing a resource. Resources are
typically specified as the Resources property value of a page root element, or of the
application (these locations enable the most convenient access to the resource). The
following example shows how to define a SolidColorBrush resource.

XAML

<DockPanel.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
</DockPanel.Resources>

Once the resource is defined, you can reference the resource and use it to provide a
property value:

XAML

<Button Background="{DynamicResource MyBrush}" Content="I am gold" />

This particular resource is referenced as a DynamicResource Markup Extension (in WPF


XAML, you can use either a static or dynamic resource reference). To use a dynamic
resource reference, you must be setting to a dependency property, so it is specifically
the dynamic resource reference usage that is enabled by the WPF property system. For
more information, see XAML Resources.

7 Note

Resources are treated as a local value, which means that if you set another local
value, you will eliminate the resource reference. For more information, see
Dependency Property Value Precedence.

Data binding
A dependency property can reference a value through data binding. Data binding works
through a specific markup extension syntax in XAML, or the Binding object in code. With
data binding, the final property value determination is deferred until run time, at which
time the value is obtained from a data source.

The following example sets the Content property for a Button, using a binding declared
in XAML. The binding uses an inherited data context and an XmlDataProvider data
source (not shown). The binding itself specifies the desired source property by XPath
within the data source.

XAML

<Button Content="{Binding XPath=Team/@TeamName}"/>

7 Note

Bindings are treated as a local value, which means that if you set another local
value, you will eliminate the binding. For details, see Dependency Property Value
Precedence.

Dependency properties, or the DependencyObject class, do not natively support


INotifyPropertyChanged for purposes of producing notifications of changes in
DependencyObject source property value for data binding operations. For more
information on how to create properties for use in data binding that can report changes
to a data binding target, see Data Binding Overview.

Styles
Styles and templates are two of the chief motivating scenarios for using dependency
properties. Styles are particularly useful for setting properties that define application
user interface (UI). Styles are typically defined as resources in XAML. Styles interact with
the property system because they typically contain "setters" for particular properties, as
well as "triggers" that change a property value based on the real-time value for another
property.

The following example creates a simple style (which would be defined inside a
Resources dictionary, not shown), then applies that style directly to the Style property
for a Button. The setter within the style sets the Background property for a styled Button
to green.

XAML

<Style x:Key="GreenButtonStyle">
<Setter Property="Control.Background" Value="Green"/>
</Style>

XAML

<Button Style="{StaticResource GreenButtonStyle}">I am green!</Button>


For more information, see Styling and Templating.

Animations
Dependency properties can be animated. When an animation is applied and is running,
the animated value operates at a higher precedence than any value (such as a local
value) that the property otherwise has.

The following example animates the Background on a Button property (technically, the
Background is animated by using property element syntax to specify a blank
SolidColorBrush as the Background, then the Color property of that SolidColorBrush is
the property that is directly animated).

XAML

<Button>I am animated
<Button.Background>
<SolidColorBrush x:Name="AnimBrush"/>
</Button.Background>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Loaded">
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetName="AnimBrush"
Storyboard.TargetProperty="(SolidColorBrush.Color)"
From="Red" To="Green" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>

For more information on animating properties, see Animation Overview and Storyboards
Overview.

Metadata overrides
You can change certain behaviors of a dependency property by overriding the metadata
for that property when you derive from the class that originally registers the
dependency property. Overriding metadata relies on the DependencyProperty identifier.
Overriding metadata does not require reimplementing the property. The metadata
change is handled natively by the property system; each class potentially holds
individual metadata for all properties that are inherited from base classes, on a per-type
basis.

The following example overrides metadata for a dependency property DefaultStyleKey.


Overriding this particular dependency property metadata is part of an implementation
pattern that creates controls that can use default styles from themes.

C#

public class SpinnerControl : ItemsControl


{
static SpinnerControl()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(SpinnerControl),
new FrameworkPropertyMetadata(typeof(SpinnerControl))
);
}
}

For more information about overriding or obtaining property metadata, see


Dependency Property Metadata.

Property value inheritance


An element can inherit the value of a dependency property from its parent in the object
tree.

7 Note

Property value inheritance behavior is not globally enabled for all dependency
properties, because the calculation time for inheritance does have some
performance impact. Property value inheritance is typically only enabled for
properties where a particular scenario suggests that property value inheritance is
appropriate. You can determine whether a dependency property inherits by looking
at the Dependency Property Information section for that dependency property in
the SDK reference.

The following example shows a binding, and sets the DataContext property that
specifies the source of the binding, which was not shown in the earlier binding example.
Any subsequent bindings in child objects do not need to specify the source, they can
use the inherited value from DataContext in the parent StackPanel object. (Alternatively,
a child object could instead choose to directly specify its own DataContext or a Source
in the Binding, and to deliberately not use the inherited value for data context of its
bindings.)

XAML

<StackPanel Canvas.Top="50" DataContext="{Binding Source={StaticResource


XmlTeamsSource}}">
<Button Content="{Binding XPath=Team/@TeamName}"/>
</StackPanel>

For more information, see Property Value Inheritance.

WPF designer integration


A custom control with properties that are implemented as dependency properties will
receive appropriate WPF Designer for Visual Studio support. One example is the ability
to edit direct and attached dependency properties with the Properties window. For
more information, see Control Authoring Overview.

Dependency property value precedence


When you get the value of a dependency property, you are potentially obtaining a value
that was set on that property through any one of the other property-based inputs that
participate in the WPF property system. Dependency property value precedence exists
so that a variety of scenarios for how properties obtain their values can interact in a
predictable way.

Consider the following example. The example includes a style that applies to all buttons
and their Background properties, but then also specifies one button with a locally set
Background value.

7 Note

The SDK documentation uses the terms "local value" or "locally set value"
occasionally when discussing dependency properties. A locally set value is a
property value that is set directly on an object instance in code, or as an attribute
on an element in XAML.

In principle, for the first button, the property is set twice, but only one value applies: the
value with the highest precedence. A locally set value has the highest precedence
(except for a running animation, but no animation applies in this example) and thus the
locally set value is used instead of the style setter value for the background on the first
button. The second button has no local value (and no other value with higher
precedence than a style setter) and thus the background in that button comes from the
style setter.

XAML

<StackPanel>
<StackPanel.Resources>
<Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red"/>
</Style>
</StackPanel.Resources>
<Button Background="Green">I am NOT red!</Button>
<Button>I am styled red</Button>
</StackPanel>

Why does dependency property precedence exist?


Typically, you would not want styles to always apply and to obscure even a locally set
value of an individual element (otherwise, it would be difficult to use either styles or
elements in general). Therefore, the values that come from styles operate at a lower
precedent than a locally set value. For a more thorough listing of dependency properties
and where a dependency property effective value might come from, see Dependency
Property Value Precedence.

7 Note

There are a number of properties defined on WPF elements that are not
dependency properties. By and large, properties were implemented as dependency
properties only when there were needs to support at least one of the scenarios
enabled by the property system: data binding, styling, animation, default value
support, inheritance, attached properties, or invalidation.

Learning more about dependency properties


An attached property is a type of property that supports a specialized syntax in
XAML. An attached property often does not have a 1:1 correspondence with a
common language runtime (CLR) property, and is not necessarily a dependency
property. The typical purpose of an attached property is to allow child elements to
report property values to a parent element, even if the parent element and child
element do not both possess that property as part of the class members listings.
One primary scenario is to enable child elements to inform the parent how they
should be presented in UI; for an example, see Dock or Left. For details, see
Attached Properties Overview.

Component developers or application developers may wish to create their own


dependency property, in order to enable capabilities such as data binding or styles
support, or for invalidation and value coercion support. For details, see Custom
Dependency Properties.

Consider dependency properties to be public properties, accessible or at least


discoverable by any caller that has access to an instance. For more information, see
Dependency Property Security.

See also
Custom Dependency Properties
Read-Only Dependency Properties
XAML in WPF
WPF Architecture
Attached Properties Overview
Article • 03/17/2022

An attached property is a concept defined by XAML. An attached property is intended to


be used as a type of global property that is settable on any dependency object. In
Windows Presentation Foundation (WPF), attached properties are typically defined as a
specialized form of dependency property that does not have the conventional property
"wrapper".

Prerequisites
This article assumes that you understand dependency properties from the perspective of
a consumer of existing dependency properties on Windows Presentation Foundation
(WPF) classes, and have read the Dependency Properties Overview. To follow the
examples in this article, you should also understand XAML and know how to write WPF
applications.

Why Use Attached Properties


One purpose of an attached property is to allow different child elements to specify
unique values for a property that's defined in a parent element. A specific application of
this scenario is having child elements inform the parent element of how they are to be
presented in the user interface (UI). One example is the DockPanel.Dock property. The
DockPanel.Dock property is created as an attached property because it is designed to be
set on elements that are contained within a DockPanel rather than on DockPanel itself.
The DockPanel class defines the static DependencyProperty field named DockProperty,
and then provides the GetDock and SetDock methods as public accessors for the
attached property.

Attached Properties in XAML


In XAML, you set attached properties by using the syntax
AttachedPropertyProvider.PropertyName

The following is an example of how you can set DockPanel.Dock in XAML:

XAML

<DockPanel>
<TextBox DockPanel.Dock="Top">Enter text</TextBox>
</DockPanel>

The usage is somewhat similar to a static property; you always reference the type
DockPanel that owns and registers the attached property, rather than referring to any
instance specified by name.

Also, because an attached property in XAML is an attribute that you set in markup, only
the set operation has any relevance. You cannot directly get a property in XAML,
although there are some indirect mechanisms for comparing values, such as triggers in
styles (for details, see Styling and Templating).

Attached Property Implementation in WPF


In Windows Presentation Foundation (WPF), most of the UI-related attached properties
on WPF types are implemented as dependency properties. Attached properties are a
XAML concept, whereas dependency properties are a WPF concept. Because WPF
attached properties are dependency properties, they support dependency property
concepts such as property metadata, and default values from that property metadata.

How Attached Properties Are Used by the


Owning Type
Although attached properties are settable on any object, that does not automatically
mean that setting the property will produce a tangible result, or that the value will ever
be used by another object. Generally, attached properties are intended so that objects
coming from a wide variety of possible class hierarchies or logical relationships can each
report common information to the type that defines the attached property. The type
that defines the attached property typically follows one of these models:

The type that defines the attached property is designed so that it can be the
parent element of the elements that will set values for the attached property. The
type then iterates its child objects through internal logic against some object tree
structure, obtains the values, and acts on those values in some manner.

The type that defines the attached property will be used as the child element for a
variety of possible parent elements and content models.

The type that defines the attached property represents a service. Other types set
values for the attached property. Then, when the element that set the property is
evaluated in the context of the service, the attached property values are obtained
through internal logic of the service class.
An Example of a Parent-Defined Attached Property
The most typical scenario where WPF defines an attached property is when a parent
element supports a child element collection, and also implements a behavior where the
specifics of the behavior are reported individually for each child element.

DockPanel defines the DockPanel.Dock attached property, and DockPanel has class-level
code as part of its rendering logic (specifically, MeasureOverride and ArrangeOverride).
A DockPanel instance will always check to see whether any of its immediate child
elements have set a value for DockPanel.Dock. If so, those values become input for the
rendering logic applied to that particular child element. Nested DockPanel instances
each treat their own immediate child element collections, but that behavior is
implementation-specific to how DockPanel processes DockPanel.Dock values. It is
theoretically possible to have attached properties that influence elements beyond the
immediate parent. If the DockPanel.Dock attached property is set on an element that
has no DockPanel parent element to act upon it, no error or exception is raised. This
simply means that a global property value was set, but it has no current DockPanel
parent that could consume the information.

Attached Properties in Code


Attached properties in WPF do not have the typical CLR "wrapper" methods for easy
get/set access. This is because the attached property is not necessarily part of the CLR
namespace for instances where the property is set. However, a XAML processor must be
able to set those values when XAML is parsed. To support an effective attached property
usage, the owner type of the attached property must implement dedicated accessor
methods in the form GetPropertyName and SetPropertyName. These dedicated
accessor methods are also useful to get or set the attached property in code. From a
code perspective, an attached property is similar to a backing field that has method
accessors instead of property accessors, and that backing field can exist on any object
rather than needing to be specifically defined.

The following example shows how you can set an attached property in code. In this
example, myCheckBox is an instance of the CheckBox class.

C#

DockPanel myDockPanel = new DockPanel();


CheckBox myCheckBox = new CheckBox();
myCheckBox.Content = "Hello";
myDockPanel.Children.Add(myCheckBox);
DockPanel.SetDock(myCheckBox, Dock.Top);
Similar to the XAML case, if myCheckBox had not already been added as a child element
of myDockPanel by the fourth line of code, the fifth line of code would not raise an
exception, but the property value would not interact with a DockPanel parent and thus
would do nothing. Only a DockPanel.Dock value set on a child element combined with
the presence of a DockPanel parent element will cause an effective behavior in the
rendered application. (In this case, you could set the attached property, then attach to
the tree. Or you could attach to the tree then set the attached property. Either action
order provides the same result.)

Attached Property Metadata


When registering the property, FrameworkPropertyMetadata is set to specify
characteristics of the property, such as whether the property affects rendering,
measurement, and so on. Metadata for an attached property is generally no different
than on a dependency property. If you specify a default value in an override to attached
property metadata, that value becomes the default value of the implicit attached
property on instances of the overriding class. Specifically, your default value is reported
if some process queries for the value of an attached property through the Get method
accessor for that property, specifying an instance of the class where you specified the
metadata, and the value for that attached property was otherwise not set.

If you want to enable property value inheritance on a property, you should use attached
properties rather than non-attached dependency properties. For details, see Property
Value Inheritance.

Custom Attached Properties

When to Create an Attached Property


You might create an attached property when there is a reason to have a property setting
mechanism available for classes other than the defining class. The most common
scenario for this is layout. Examples of existing layout properties are DockPanel.Dock,
Panel.ZIndex, and Canvas.Top. The scenario enabled here is that elements that exist as
child elements to layout-controlling elements are able to express layout requirements to
their layout parent elements individually, each setting a property value that the parent
defined as an attached property.

Another scenario for using an attached property is when your class represents a service,
and you want classes to be able to integrate the service more transparently.
Yet another scenario is to receive Visual Studio WPF Designer support, such as
Properties window editing. For more information, see Control Authoring Overview.

As mentioned before, you should register as an attached property if you want to use
property value inheritance.

How to Create an Attached Property


If your class is defining the attached property strictly for use on other types, then the
class does not have to derive from DependencyObject. But you do need to derive from
DependencyObject if you follow the overall WPF model of having your attached
property also be a dependency property.

Define your attached property as a dependency property by declaring a public static


readonly field of type DependencyProperty. You define this field by using the return

value of the RegisterAttached method. The field name must match the attached
property name, appended with the string Property , to follow the established WPF
pattern of naming the identifying fields versus the properties that they represent. The
attached property provider must also provide static GetPropertyName and
SetPropertyName methods as accessors for the attached property; failing to do this
results in the property system being unable to use your attached property.

7 Note

If you omit the attached property's get accessor, data binding on the property will
not work in design tools, such as Visual Studio and Blend for Visual Studio.

The Get Accessor

The signature for the GetPropertyName accessor must be:

public static object GetPropertyName(object target)

The target object can be specified as a more specific type in your implementation.
For example, the DockPanel.GetDock method types the parameter as UIElement,
because the attached property is only intended to be set on UIElement instances.

The return value can be specified as a more specific type in your implementation.
For example, the GetDock method types it as Dock, because the value can only be
set to that enumeration.
The Set Accessor
The signature for the SetPropertyName accessor must be:

public static void SetPropertyName(object target, object value)

The target object can be specified as a more specific type in your implementation.
For example, the SetDock method types it as UIElement, because the attached
property is only intended to be set on UIElement instances.

The value object can be specified as a more specific type in your implementation.
For example, the SetDock method types it as Dock, because the value can only be
set to that enumeration. Remember that the value for this method is the input
coming from the XAML loader when it encounters your attached property in an
attached property usage in markup. That input is the value specified as a XAML
attribute value in markup. Therefore there must be type conversion, value
serializer, or markup extension support for the type you use, such that the
appropriate type can be created from the attribute value (which is ultimately just a
string).

The following example shows the dependency property registration (using the
RegisterAttached method), as well as the GetPropertyName and SetPropertyName
accessors. In the example, the attached property name is IsBubbleSource . Therefore, the
accessors must be named GetIsBubbleSource and SetIsBubbleSource .

C#

public static readonly DependencyProperty IsBubbleSourceProperty =


DependencyProperty.RegisterAttached(
"IsBubbleSource",
typeof(Boolean),
typeof(AquariumObject),
new FrameworkPropertyMetadata(false,
FrameworkPropertyMetadataOptions.AffectsRender)
);
public static void SetIsBubbleSource(UIElement element, Boolean value)
{
element.SetValue(IsBubbleSourceProperty, value);
}
public static Boolean GetIsBubbleSource(UIElement element)
{
return (Boolean)element.GetValue(IsBubbleSourceProperty);
}

Attached Property Attributes


WPF defines several .NET attributes that are intended to provide information about
attached properties to reflection processes, and to typical users of reflection and
property information such as designers. Because attached properties have a type of
unlimited scope, designers need a way to avoid overwhelming users with a global list of
all the attached properties that are defined in a particular technology implementation
that uses XAML. The .NET attributes that WPF defines for attached properties can be
used to scope the situations where a given attached property should be shown in a
properties window. You might consider applying these attributes for your own custom
attached properties also. The purpose and syntax of the .NET attributes is described on
the appropriate reference pages:

AttachedPropertyBrowsableAttribute

AttachedPropertyBrowsableForChildrenAttribute

AttachedPropertyBrowsableForTypeAttribute

AttachedPropertyBrowsableWhenAttributePresentAttribute

Learning More About Attached Properties


For more information on creating an attached property, see Register an Attached
Property.

For more advanced usage scenarios for dependency properties and attached
properties, see Custom Dependency Properties.

You can also register a property as an attached property, and as a dependency


property, but then still expose "wrapper" implementations. In this case, the
property can be set either on that element, or on any element through the XAML
attached property syntax. An example of a property with an appropriate scenario
for both standard and attached usages is FrameworkElement.FlowDirection.

See also
DependencyProperty
Dependency Properties Overview
Custom Dependency Properties
XAML in WPF
Register an Attached Property
Custom Dependency Properties
Article • 03/17/2022

This topic describes the reasons that Windows Presentation Foundation (WPF)
application developers and component authors might want to create custom
dependency property, and describes the implementation steps as well as some
implementation options that can improve performance, usability, or versatility of the
property.

Prerequisites
This topic assumes that you understand dependency properties from the perspective of
a consumer of existing dependency properties on WPF classes, and have read the
Dependency Properties Overview topic. In order to follow the examples in this topic, you
should also understand WPF applications.

What Is a Dependency Property?


You can enable what would otherwise be a common language runtime (CLR) property to
support styling, data binding, inheritance, animations, and default values by
implementing it as a dependency property. Dependency properties are properties that
are registered with the WPF property system by calling the Register method (or
RegisterReadOnly), and that are backed by a DependencyProperty identifier field.
Dependency properties can be used only by DependencyObject types, but
DependencyObject is quite high in the WPF class hierarchy, so the majority of classes
available in WPF can support dependency properties. For more information about
dependency properties and some of the terminology and conventions used for
describing them in this SDK, see Dependency Properties Overview.

Examples of Dependency Properties


Examples of dependency properties that are implemented on WPF classes include the
Background property, the Width property, and the Text property, among many others.
Each dependency property exposed by a class has a corresponding public static field of
type DependencyProperty exposed on that same class. This is the identifier for the
dependency property. The identifier is named using a convention: the name of the
dependency property with the string Property appended to it. For example, the
corresponding DependencyProperty identifier field for the Background property is
BackgroundProperty. The identifier stores the information about the dependency
property as it was registered, and the identifier is then used later for other operations
involving the dependency property, such as calling SetValue.

As mentioned in the Dependency Properties Overview, all dependency properties in


WPF (except most attached properties) are also CLR properties because of the "wrapper"
implementation. Therefore, from code, you can get or set dependency properties by
calling CLR accessors that define the wrappers in the same manner that you would use
other CLR properties. As a consumer of established dependency properties, you do not
typically use the DependencyObject methods GetValue and SetValue, which are the
connection point to the underlying property system. Rather, the existing implementation
of the CLR properties will have already called GetValue and SetValue within the get and
set wrapper implementations of the property, using the identifier field appropriately. If
you are implementing a custom dependency property yourself, then you will be defining
the wrapper in a similar way.

When Should You Implement a Dependency


Property?
When you implement a property on a class, so long as your class derives from
DependencyObject, you have the option to back your property with a
DependencyProperty identifier and thus to make it a dependency property. Having your
property be a dependency property is not always necessary or appropriate, and will
depend on your scenario needs. Sometimes, the typical technique of backing your
property with a private field is adequate. However, you should implement your property
as a dependency property whenever you want your property to support one or more of
the following WPF capabilities:

You want your property to be settable in a style. For more information, see Styling
and Templating.

You want your property to support data binding. For more information about data
binding dependency properties, see Bind the Properties of Two Controls.

You want your property to be settable with a dynamic resource reference. For more
information, see XAML Resources.

You want to inherit a property value automatically from a parent element in the
element tree. In this case, register with the RegisterAttached method, even if you
also create a property wrapper for CLR access. For more information, see Property
Value Inheritance.
You want your property to be animatable. For more information, see Animation
Overview.

You want the property system to report when the previous value of the property
has been changed by actions taken by the property system, the environment, or
the user, or by reading and using styles. By using property metadata, your property
can specify a callback method that will be invoked each time the property system
determines that your property value was definitively changed. A related concept is
property value coercion. For more information, see Dependency Property Callbacks
and Validation.

You want to use established metadata conventions that are also used by WPF
processes, such as reporting whether changing a property value should require the
layout system to recompose the visuals for an element. Or you want to be able to
use metadata overrides so that derived classes can change metadata-based
characteristics such as the default value.

You want properties of a custom control to receive Visual Studio WPF Designer
support, such as Properties window editing. For more information, see Control
Authoring Overview.

When you examine these scenarios, you should also consider whether you can achieve
your scenario by overriding the metadata of an existing dependency property, rather
than implementing a completely new property. Whether a metadata override is practical
depends on your scenario and how closely that scenario resembles the implementation
in existing WPF dependency properties and classes. For more information about
overriding metadata on existing properties, see Dependency Property Metadata.

Checklist for Defining a Dependency Property


Defining a dependency property consists of four distinct concepts. These concepts are
not necessarily strict procedural steps, because some of these end up being combined
as single lines of code in the implementation:

(Optional) Create property metadata for the dependency property.

Register the property name with the property system, specifying an owner type
and the type of the property value. Also specify the property metadata, if used.

Define a DependencyProperty identifier as a public static readonly field on the


owner type.
Define a CLR "wrapper" property whose name matches the name of the
dependency property. Implement the CLR "wrapper" property's get and set
accessors to connect with the dependency property that backs it.

Registering the Property with the Property System


In order for your property to be a dependency property, you must register that property
into a table maintained by the property system, and give it a unique identifier that is
used as the qualifier for later property system operations. These operations might be
internal operations, or your own code calling property system APIs. To register the
property, you call the Register method within the body of your class (inside the class,
but outside of any member definitions). The identifier field is also provided by the
Register method call, as the return value. The reason that the Register call is done
outside of other member definitions is because you use this return value to assign and
create a public static readonly field of type DependencyProperty as part of your
class. This field becomes the identifier for your dependency property.

C#

public static readonly DependencyProperty AquariumGraphicProperty =


DependencyProperty.Register(
"AquariumGraphic",
typeof(Uri),
typeof(AquariumObject),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnUriChanged)
)
);

Dependency Property Name Conventions


There are established naming conventions regarding dependency properties that you
must follow in all but exceptional circumstances.

The dependency property itself will have a basic name, "AquariumGraphic" as in this
example, which is given as the first parameter of Register. That name must be unique
within each registering type. Dependency properties inherited through base types are
considered to be already part of the registering type; names of inherited properties
cannot be registered again. However, there is a technique for adding a class as owner of
a dependency property even when that dependency property is not inherited; for
details, see Dependency Property Metadata.
When you create the identifier field, name this field by the name of the property as you
registered it, plus the suffix Property . This field is your identifier for the dependency
property, and it will be used later as an input for the SetValue and GetValue calls you will
make in the wrappers, by any other code access to the property by your own code, by
any external code access you allow, by the property system, and potentially by XAML
processors.

7 Note

Defining the dependency property in the class body is the typical implementation,
but it is also possible to define a dependency property in the class static
constructor. This approach might make sense if you need more than one line of
code to initialize the dependency property.

Implementing the "Wrapper"


Your wrapper implementation should call GetValue in the get implementation, and
SetValue in the set implementation (the original registration call and field are shown
here too for clarity).

In all but exceptional circumstances, your wrapper implementations should perform only
the GetValue and SetValue actions, respectively. The reason for this is discussed in the
topic XAML Loading and Dependency Properties.

All existing public dependency properties that are provided on the WPF classes use this
simple wrapper implementation model; most of the complexity of how dependency
properties work is either inherently a behavior of the property system, or is
implemented through other concepts such as coercion or property change callbacks
through property metadata.

C#

public static readonly DependencyProperty AquariumGraphicProperty =


DependencyProperty.Register(
"AquariumGraphic",
typeof(Uri),
typeof(AquariumObject),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnUriChanged)
)
);
public Uri AquariumGraphic
{
get { return (Uri)GetValue(AquariumGraphicProperty); }
set { SetValue(AquariumGraphicProperty, value); }
}

Again, by convention, the name of the wrapper property must be the same as the name
chosen and given as first parameter of the Register call that registered the property. If
your property does not follow the convention, this does not necessarily disable all
possible uses, but you will encounter several notable issues:

Certain aspects of styles and templates will not work.

Most tools and designers must rely on the naming conventions to properly
serialize XAML, or to provide designer environment assistance at a per-property
level.

The current implementation of the WPF XAML loader bypasses the wrappers
entirely, and relies on the naming convention when processing attribute values. For
more information, see XAML Loading and Dependency Properties.

Property Metadata for a New Dependency Property


When you register a dependency property, the registration through the property system
creates a metadata object that stores property characteristics. Many of these
characteristics have defaults that are set if the property is registered with the simple
signatures of Register. Other signatures of Register allow you to specify the metadata
that you want as you register the property. The most common metadata given for
dependency properties is to give them a default value that is applied on new instances
that use the property.

If you are creating a dependency property that exists on a derived class of


FrameworkElement, you can use the more specialized metadata class
FrameworkPropertyMetadata rather than the base PropertyMetadata class. The
constructor for the FrameworkPropertyMetadata class has several signatures where you
can specify various metadata characteristics in combination. If you want to specify the
default value only, use the signature that takes a single parameter of type Object. Pass
that object parameter as a type-specific default value for your property (the default
value provided must be the type you provided as the propertyType parameter in the
Register call).

For FrameworkPropertyMetadata, you can also specify metadata option flags for your
property. These flags are converted into discrete properties on the property metadata
after registration and are used to communicate certain conditionals to other processes
such as the layout engine.

Setting Appropriate Metadata Flags

If your property (or changes in its value) affects the user interface (UI), and in
particular affects how the layout system should size or render your element in a
page, set one or more of the following flags: AffectsMeasure, AffectsArrange,
AffectsRender.

AffectsMeasure indicates that a change to this property requires a change to UI


rendering where the containing object might require more or less space within
the parent. For example, a "Width" property should have this flag set.

AffectsArrange indicates that a change to this property requires a change to UI


rendering that typically does not require a change in the dedicated space, but
does indicate that the positioning within the space has changed. For example,
an "Alignment" property should have this flag set.

AffectsRender indicates that some other change has occurred that will not affect
layout and measure, but does require another render. An example would be a
property that changes a color of an existing element, such as "Background".

These flags are often used as a protocol in metadata for your own override
implementations of property system or layout callbacks. For instance, you might
have an OnPropertyChanged callback that will call InvalidateArrange if any
property of the instance reports a value change and has AffectsArrange as true
in its metadata.

Some properties may affect the rendering characteristics of the containing parent
element, in ways above and beyond the changes in required size mentioned
above. An example is the MinOrphanLines property used in the flow document
model, where changes to that property can change the overall rendering of the
flow document that contains the paragraph. Use AffectsParentArrange or
AffectsParentMeasure to identify similar cases in your own properties.

By default, dependency properties support data binding. You can deliberately


disable data binding, for cases where there is no realistic scenario for data binding,
or where performance in data binding for a large object is recognized as a
problem.

By default, data binding Mode for dependency properties defaults to OneWay. You
can always change the binding to be TwoWay per binding instance; for details, see
Specify the Direction of the Binding. But as the dependency property author, you
can choose to make the property use TwoWay binding mode by default. An
example of an existing dependency property is MenuItem.IsSubmenuOpen; the
scenario for this property is that the IsSubmenuOpen setting logic and the
compositing of MenuItem interact with the default theme style. The
IsSubmenuOpen property logic uses data binding natively to maintain the state of
the property in accordance to other state properties and method calls. Another
example property that binds TwoWay by default is TextBox.Text.

You can also enable property inheritance in a custom dependency property by


setting the Inherits flag. Property inheritance is useful for a scenario where parent
elements and child elements have a property in common, and it makes sense for
the child elements to have that particular property value set to the same value as
the parent set it. An example inheritable property is DataContext, which is used for
binding operations to enable the important master-detail scenario for data
presentation. By making DataContext inheritable, any child elements inherit that
data context also. Because of property value inheritance, you can specify a data
context at the page or application root, and do not need to respecify it for
bindings in all possible child elements. DataContext is also a good example to
illustrate that inheritance overrides the default value, but it can always be set
locally on any particular child element; for details, see Use the Master-Detail
Pattern with Hierarchical Data. Property value inheritance does have a possible
performance cost, and thus should be used sparingly; for details, see Property
Value Inheritance.

Set the Journal flag to indicate if your dependency property should be detected or
used by navigation journaling services. An example is the SelectedIndex property;
any item selected in a selection control should be persisted when the journaling
history is navigated.

Read-Only Dependency Properties


You can define a dependency property that is read-only. However, the scenarios for why
you might define your property as read-only are somewhat different, as is the procedure
for registering them with the property system and exposing the identifier. For more
information, see Read-Only Dependency Properties.

Collection-Type Dependency Properties


Collection-type dependency properties have some additional implementation issues to
consider. For details, see Collection-Type Dependency Properties.
Dependency Property Security Considerations
Dependency properties should be declared as public properties. Dependency property
identifier fields should be declared as public static fields. Even if you attempt to declare
other access levels (such as protected), a dependency property can always be accessed
through the identifier in combination with the property system APIs. Even a protected
identifier field is potentially accessible because of metadata reporting or value
determination APIs that are part of the property system, such as LocalValueEnumerator.
For more information, see Dependency Property Security.

Dependency Properties and Class Constructors


There is a general principle in managed code programming (often enforced by code
analysis tools such as FxCop) that class constructors should not call virtual methods. This
is because constructors can be called as base initialization of a derived class constructor,
and entering the virtual method through the constructor might occur at an incomplete
initialization state of the object instance being constructed. When you derive from any
class that already derives from DependencyObject, you should be aware that the
property system itself calls and exposes virtual methods internally. These virtual
methods are part of the WPF property system services. Overriding the methods enables
derived classes to participate in value determination. To avoid potential issues with
runtime initialization, you should not set dependency property values within
constructors of classes, unless you follow a very specific constructor pattern. For details,
see Safe Constructor Patterns for DependencyObjects.

See also
Dependency Properties Overview
Dependency Property Metadata
Control Authoring Overview
Collection-Type Dependency Properties
Dependency Property Security
XAML Loading and Dependency Properties
Safe Constructor Patterns for DependencyObjects
Dependency Property Metadata
Article • 02/06/2023

The Windows Presentation Foundation (WPF) property system includes a metadata


reporting system that goes beyond what can be reported about a property through
reflection or general common language runtime (CLR) characteristics. Metadata for a
dependency property can also be assigned uniquely by the class that defines a
dependency property, can be changed when the dependency property is added to a
different class, and can be specifically overridden by all derived classes that inherit the
dependency property from the defining base class.

Prerequisites
This topic assumes that you understand dependency properties from the perspective of
a consumer of existing dependency properties on WPF applications.

How Dependency Property Metadata is Used


Dependency property metadata exists as an object that can be queried to examine the
characteristics of a dependency property. This metadata is also accessed frequently by
the property system as it processes any given dependency property. The metadata
object for a dependency property can contain the following types of information:

Default value for the dependency property, if no other value can be determined for
the dependency property by local value, style, inheritance, etc. For a thorough
discussion of how default values participate in the precedence used by the
property system when assigning values for dependency properties, see
Dependency Property Value Precedence.

References to callback implementations that affect coercion or change-notification


behaviors on a per-owner-type basis. Note that these callbacks are often defined
with a nonpublic access level, so obtaining the actual references from metadata is
generally not possible unless the references are within your permitted access
scope. For more information on dependency property callbacks, see Dependency
Property Callbacks and Validation.

If the dependency property in question is considered to be a WPF framework-level


property, the metadata might contain WPF framework-level dependency property
characteristics, which report information and state for services such as the WPF
framework-level layout engine and property inheritance logic. For more
information on this aspect of dependency property metadata, see Framework
Property Metadata.

Metadata APIs
The type that reports most of the metadata information used by the property system is
the PropertyMetadata class. Metadata instances are optionally specified when
dependency properties are registered with the property system, and can be specified
again for additional types that either add themselves as owners or override metadata
they inherit from the base class dependency property definition. (For cases where a
property registration does not specify metadata, a default PropertyMetadata is created
with default values for that class.)The registered metadata is returned as
PropertyMetadata when you call the various GetMetadata overloads that get metadata
from a dependency property on a DependencyObject instance.

The PropertyMetadata class is then derived from to provide more specific metadata for
architectural divisions such as the WPF framework-level classes. UIPropertyMetadata
adds animation reporting, and FrameworkPropertyMetadata provides the WPF
framework-level properties mentioned in the previous section. When dependency
properties are registered, they can be registered with these PropertyMetadata derived
classes. When the metadata is examined, the base PropertyMetadata type can
potentially be cast to the derived classes so that you can examine the more specific
properties.

7 Note

The property characteristics that can be specified in FrameworkPropertyMetadata


are sometimes referred to in this documentation as "flags". When you create new
metadata instances for use in dependency property registrations or metadata
overrides, you specify these values using the flagwise enumeration
FrameworkPropertyMetadataOptions and then you supply possibly concatenated
values of the enumeration to the FrameworkPropertyMetadata constructor.
However, once constructed, these option characteristics are exposed within a
FrameworkPropertyMetadata as a series of Boolean properties rather than the
constructing enumeration value. The Boolean properties enable you to check each
conditional, rather than requiring you to apply a mask to a flagwise enumeration
value to get the information you are interested in. The constructor uses the
concatenated FrameworkPropertyMetadataOptions in order to keep the length of
the constructor signature reasonable, whereas the actual constructed metadata
exposes the discrete properties to make querying the metadata more intuitive.
When to Override Metadata, When to Derive a
Class
The WPF property system has established capabilities for changing some characteristics
of dependency properties without requiring them to be entirely re-implemented. This is
accomplished by constructing a different instance of property metadata for the
dependency property as it exists on a particular type. Note that most existing
dependency properties are not virtual properties, so strictly speaking "re-implementing"
them on inherited classes could only be accomplished by shadowing the existing
member.

If the scenario you are trying to enable for a dependency property on a type cannot be
accomplished by modifying characteristics of existing dependency properties, it might
then be necessary to create a derived class, and then to declare a custom dependency
property on your derived class. A custom dependency property behaves identically to
dependency properties defined by the WPF APIs. For more details about custom
dependency properties, see Custom Dependency Properties.

One notable characteristic of a dependency property that you cannot override is its
value type. If you are inheriting a dependency property that has the approximate
behavior you require, but you require a different type for it, you will have to implement
a custom dependency property and perhaps link the properties through type conversion
or other implementation on your custom class. Also, you cannot replace an existing
ValidateValueCallback, because this callback exists in the registration field itself and not
within its metadata.

Scenarios for Changing Existing Metadata


If you are working with metadata of an existing dependency property, one common
scenario for changing dependency property metadata is to change the default value.
Changing or adding property system callbacks is a more advanced scenario. You might
want to do this if your implementation of a derived class has different interrelationships
between dependency properties. One of the conditionals of having a programming
model that supports both code and declarative usage is that properties must enable
being set in any order. Thus any dependent properties need to be set just-in-time
without context and cannot rely on knowing a setting order such as might be found in a
constructor. For more information on this aspect of the property system, see
Dependency Property Callbacks and Validation. Note that validation callbacks are not
part of the metadata; they are part of the dependency property identifier. Therefore,
validation callbacks cannot be changed by overriding the metadata.
In some cases you might also want to alter the WPF framework-level property metadata
options on existing dependency properties. These options communicate certain known
conditionals about WPF framework-level properties to other WPF framework-level
processes such as the layout system. Setting the options is generally done only when
registering a new dependency property, but it is also possible to change the WPF
framework-level property metadata as part of a OverrideMetadata or AddOwner call.
For the specific values to use and more information, see Framework Property Metadata.
For more information that is pertinent to how these options should be set for a newly
registered dependency property, see Custom Dependency Properties.

Overriding Metadata
The purpose of overriding metadata is primarily so that you have the opportunity to
change the various metadata-derived behaviors that are applied to the dependency
property as it exists on your type. The reasons for this are explained in more detail in the
Metadata section. For more information including some code examples, see Override
Metadata for a Dependency Property.

Property metadata can be supplied for a dependency property during the registration
call (Register). However, in many cases, you might want to provide type-specific
metadata for your class when it inherits that dependency property. You can do this by
calling the OverrideMetadata method. For an example from the WPF APIs, the
FrameworkElement class is the type that first registers the Focusable dependency
property. But the Control class overrides metadata for the dependency property to
provide its own initial default value, changing it from false to true , and otherwise re-
uses the original Focusable implementation.

When you override metadata, the different metadata characteristics are either merged
or replaced.

PropertyChangedCallback is merged. If you add a new PropertyChangedCallback,


that callback is stored in the metadata. If you do not specify a
PropertyChangedCallback in the override, the value of PropertyChangedCallback is
promoted as a reference from the nearest ancestor that specified it in metadata.

The actual property system behavior for PropertyChangedCallback is that


implementations for all metadata owners in the hierarchy are retained and added
to a table, with order of execution by the property system being that the most
derived class's callbacks are invoked first.

DefaultValue is replaced. If you do not specify a DefaultValue in the override, the


value of DefaultValue comes from the nearest ancestor that specified it in
metadata.

CoerceValueCallback implementations are replaced. If you add a new


CoerceValueCallback, that callback is stored in the metadata. If you do not specify
a CoerceValueCallback in the override, the value of CoerceValueCallback is
promoted as a reference from the nearest ancestor that specified it in metadata.

The property system behavior is that only the CoerceValueCallback in the


immediate metadata is invoked. No references to other CoerceValueCallback
implementations in the hierarchy are retained.

This behavior is implemented by Merge, and can be overridden on derived metadata


classes.

Overriding Attached Property Metadata


In WPF, attached properties are implemented as dependency properties. This means
that they also have property metadata, which individual classes can override. The
scoping considerations for an attached property in WPF are generally that any
DependencyObject can have an attached property set on them. Therefore, any
DependencyObject derived class can override the metadata for any attached property,
as it might be set on an instance of the class. You can override default values, callbacks,
or WPF framework-level characteristic-reporting properties. If the attached property is
set on an instance of your class, those override property metadata characteristics apply.
For instance, you can override the default value, such that your override value is
reported as the value of the attached property on instances of your class, whenever the
property is not otherwise set.

7 Note

The Inherits property is not relevant for attached properties.

Adding a Class as an Owner of an Existing Dependency


Property
A class can add itself as an owner of a dependency property that has already been
registered, by using the AddOwner method. This enables the class to use a dependency
property that was originally registered for a different type. The adding class is typically
not a derived class of the type that first registered that dependency property as owner.
Effectively, this allows your class and its derived classes to "inherit" a dependency
property implementation without the original owner class and the adding class being in
the same true class hierarchy. In addition, the adding class (and all derived classes as
well) can then provide type-specific metadata for the original dependency property.

As well as adding itself as owner through the property system utility methods, the
adding class should declare additional public members on itself in order to make the
dependency property] a full participant in the property system with exposure to both
code and markup. A class that adds an existing dependency property has the same
responsibilities as far as exposing the object model for that dependency property as
does a class that defines a new custom dependency property. The first such member to
expose is a dependency property identifier field. This field should be a public static
readonly field of type DependencyProperty, which is assigned to the return value of the

AddOwner call. The second member to define is the common language runtime (CLR)
"wrapper" property. The wrapper makes it much more convenient to manipulate your
dependency property in code (you avoid calls to SetValue each time, and can make that
call only once in the wrapper itself). The wrapper is implemented identically to how it
would be implemented if you were registering a custom dependency property. For more
information about implementing a dependency property, see Custom Dependency
Properties and Add an Owner Type for a Dependency Property.

AddOwner and Attached Properties

You can call AddOwner for a dependency property that is defined as an attached
property by the owner class. Generally the reason for doing this is to expose the
previously attached property as a non-attached dependency property. You then will
expose the AddOwner return value as a public static readonly field for use as the
dependency property identifier, and will define appropriate "wrapper" properties so that
the property appears in the members table and supports a non-attached property usage
in your class.

See also
PropertyMetadata
DependencyObject
DependencyProperty
GetMetadata
Dependency Properties Overview
Framework Property Metadata
Dependency Property Callbacks and
Validation
Article • 02/06/2023

This topic describes how to create dependency properties using alternative custom
implementations for property-related features such as validation determination,
callbacks that are invoked whenever the property's effective value is changed, and
overriding possible outside influences on value determination. This topic also discusses
scenarios where expanding on the default property system behaviors by using these
techniques is appropriate.

Prerequisites
This topic assumes that you understand the basic scenarios of implementing a
dependency property, and how metadata is applied to a custom dependency property.
See Custom Dependency Properties and Dependency Property Metadata for context.

Validation Callbacks
Validation callbacks can be assigned to a dependency property when you first register it.
The validation callback is not part of property metadata; it is a direct input of the
Register method. Therefore, once a validation callback is created for a dependency
property, it cannot be overridden by a new implementation.

C#

public static readonly DependencyProperty CurrentReadingProperty =


DependencyProperty.Register(
"CurrentReading",
typeof(double),
typeof(Gauge),
new FrameworkPropertyMetadata(
Double.NaN,
FrameworkPropertyMetadataOptions.AffectsMeasure,
new PropertyChangedCallback(OnCurrentReadingChanged),
new CoerceValueCallback(CoerceCurrentReading)
),
new ValidateValueCallback(IsValidReading)
);
public double CurrentReading
{
get { return (double)GetValue(CurrentReadingProperty); }
set { SetValue(CurrentReadingProperty, value); }
}

The callbacks are implemented such that they are provided an object value. They return
true if the provided value is valid for the property; otherwise, they return false . It is
assumed that the property is of the correct type per the type registered with the
property system, so checking type within the callbacks is not ordinarily done. The
callbacks are used by the property system in a variety of different operations. This
includes the initial type initialization by default value, programmatic change by invoking
SetValue, or attempts to override metadata with new default value provided. If the
validation callback is invoked by any of these operations, and returns false , then an
exception will be raised. Application writers must be prepared to handle these
exceptions. A common use of validation callbacks is validating enumeration values, or
constraining values of integers or doubles when the property sets measurements that
must be zero or greater.

Validation callbacks specifically are intended to be class validators, not instance


validators. The parameters of the callback do not communicate a specific
DependencyObject on which the properties to validate are set. Therefore the validation
callbacks are not useful for enforcing the possible "dependencies" that might influence a
property value, where the instance-specific value of a property is dependent on factors
such as instance-specific values of other properties, or run-time state.

The following is example code for a very simple validation callback scenario: validating
that a property that is typed as the Double primitive is not PositiveInfinity or
NegativeInfinity.

C#

public static bool IsValidReading(object value)


{
Double v = (Double)value;
return (!v.Equals(Double.NegativeInfinity) &&
!v.Equals(Double.PositiveInfinity));
}

Coerce Value Callbacks and Property Changed


Events
Coerce value callbacks do pass the specific DependencyObject instance for properties,
as do PropertyChangedCallback implementations that are invoked by the property
system whenever the value of a dependency property changes. Using these two
callbacks in combination, you can create a series of properties on elements where
changes in one property will force a coercion or reevaluation of another property.

A typical scenario for using a linkage of dependency properties is when you have a user
interface driven property where the element holds one property each for the minimum
and maximum value, and a third property for the actual or current value. Here, if the
maximum was adjusted in such a way that the current value exceeded the new
maximum, you would want to coerce the current value to be no greater than the new
maximum, and a similar relationship for minimum to current.

The following is very brief example code for just one of the three dependency properties
that illustrate this relationship. The example shows how the CurrentReading property of
a Min/Max/Current set of related *Reading properties is registered. It uses the validation
as shown in the previous section.

C#

public static readonly DependencyProperty CurrentReadingProperty =


DependencyProperty.Register(
"CurrentReading",
typeof(double),
typeof(Gauge),
new FrameworkPropertyMetadata(
Double.NaN,
FrameworkPropertyMetadataOptions.AffectsMeasure,
new PropertyChangedCallback(OnCurrentReadingChanged),
new CoerceValueCallback(CoerceCurrentReading)
),
new ValidateValueCallback(IsValidReading)
);
public double CurrentReading
{
get { return (double)GetValue(CurrentReadingProperty); }
set { SetValue(CurrentReadingProperty, value); }
}

The property changed callback for Current is used to forward the change to other
dependent properties, by explicitly invoking the coerce value callbacks that are
registered for those other properties:

C#

private static void OnCurrentReadingChanged(DependencyObject d,


DependencyPropertyChangedEventArgs e)
{
d.CoerceValue(MinReadingProperty);
d.CoerceValue(MaxReadingProperty);
}
The coerce value callback checks the values of properties that the current property is
potentially dependent upon, and coerces the current value if necessary:

C#

private static object CoerceCurrentReading(DependencyObject d, object value)


{
Gauge g = (Gauge)d;
double current = (double)value;
if (current < g.MinReading) current = g.MinReading;
if (current > g.MaxReading) current = g.MaxReading;
return current;
}

7 Note

Default values of properties are not coerced. A property value equal to the default
value might occur if a property value still has its initial default, or through clearing
other values with ClearValue.

The coerce value and property changed callbacks are part of property metadata.
Therefore, you can change the callbacks for a particular dependency property as it exists
on a type that you derive from the type that owns the dependency property, by
overriding the metadata for that property on your type.

Advanced Coercion and Callback Scenarios

Constraints and Desired Values


The CoerceValueCallback callbacks will be used by the property system to coerce a value
in accordance to the logic you declare, but a coerced value of a locally set property will
still retain a "desired value" internally. If the constraints are based on other property
values that may change dynamically during the application lifetime, the coercion
constraints are changed dynamically also, and the constrained property can change its
value to get as close to the desired value as possible given the new constraints. The
value will become the desired value if all constraints are lifted. You can potentially
introduce some fairly complicated dependency scenarios if you have multiple properties
that are dependent on one another in a circular manner. For instance, in the
Min/Max/Current scenario, you could choose to have Minimum and Maximum be user
settable. If so, you might need to coerce that Maximum is always greater than Minimum
and vice versa. But if that coercion is active, and Maximum coerces to Minimum, it
leaves Current in an unsettable state, because it is dependent on both and is
constrained to the range between the values, which is zero. Then, if Maximum or
Minimum are adjusted, Current will seem to "follow" one of the values, because the
desired value of Current is still stored and is attempting to reach the desired value as
the constraints are loosened.

There is nothing technically wrong with complex dependencies, but they can be a slight
performance detriment if they require large numbers of reevaluations, and can also be
confusing to users if they affect the UI directly. Be careful with property changed and
coerce value callbacks and make sure that the coercion being attempted can be treated
as unambiguously as possible, and does not "overconstrain".

Using CoerceValue to Cancel Value Changes


The property system will treat any CoerceValueCallback that returns the value
UnsetValue as a special case. This special case means that the property change that
resulted in the CoerceValueCallback being called should be rejected by the property
system, and that the property system should instead report whatever previous value the
property had. This mechanism can be useful to check that changes to a property that
were initiated asynchronously are still valid for the current object state, and suppress the
changes if not. Another possible scenario is that you can selectively suppress a value
depending on which component of property value determination is responsible for the
value being reported. To do this, you can use the DependencyProperty passed in the
callback and the property identifier as input for GetValueSource, and then process the
ValueSource.

See also
Dependency Properties Overview
Dependency Property Metadata
Custom Dependency Properties
Framework Property Metadata
Article • 02/06/2023

Framework property metadata options are reported for the properties of object
elements considered to be at the WPF framework level in the WPF presentation APIs
and executables. Framework property metadata is queried by these systems to
determine feature-specific characteristics of particular element properties.

Prerequisites
This topic assumes that you understand dependency properties from the perspective of
a consumer of existing dependency properties on Windows Presentation Foundation
(WPF) classes, and have read the Dependency Properties Overview. You should also have
read Dependency Property Metadata.

What Is Communicated by Framework Property


Metadata
Framework property metadata can be divided into the following categories:

Reporting layout properties that affect an element (AffectsArrange,


AffectsMeasure, AffectsRender). You might set these flags in metadata if the
property affects those respective aspects, and you are also implementing the
MeasureOverride / ArrangeOverride methods in your class to supply specific
rendering behavior and information to the layout system. Typically, such an
implementation would check for property invalidations in dependency properties
where any of these layout properties were true in the property metadata, and only
those invalidations would necessitate requesting a new layout pass.

Reporting layout properties that affect the parent element of an element


(AffectsParentArrange, AffectsParentMeasure). Some examples where these flags
are set by default are FixedPage.Left and Paragraph.KeepWithNext.

Inherits. By default, dependency properties do not inherit values.


OverridesInheritanceBehavior allows the pathway of inheritance to also travel into
a visual tree, which is necessary for some control compositing scenarios.

7 Note
The term "inherits" in the context of property values means something
specific for dependency properties; it means that child elements can inherit
the actual dependency property value from parent elements because of a
WPF framework-level capability of the WPF property system. It has nothing to
do directly with managed code type and members inheritance through
derived types. For details, see Property Value Inheritance.

Reporting data binding characteristics (IsNotDataBindable,


BindsTwoWayByDefault). By default, dependency properties in the framework
support data binding, with a one-way binding behavior. You might disable data
binding if there were no scenario for it whatsoever (because they are intended to
be flexible and extensible, there aren't many examples of such properties in the
default WPF APIs). You might set binding to have a two-way default for properties
that tie together a control's behaviors amongst its component pieces
(IsSubmenuOpen is an example) or where two-way binding is the common and
expected scenario for users (Text is an example). Changing the data binding–
related metadata only influences the default; on a per-binding basis that default
can always be changed. For details on the binding modes and binding in general,
see Data Binding Overview.

Reporting whether properties should be journaled by applications or services that


support journaling (Journal). For general elements, journaling is not enabled by
default, but it is selectively enabled for certain user input controls. This property is
intended to be read by journaling services including the WPF implementation of
journaling, and is typically set on user controls such as user selections within lists
that should be persisted across navigation steps. For information about the journal,
see Navigation Overview.

Reading FrameworkPropertyMetadata
Each of the properties linked above are the specific properties that the
FrameworkPropertyMetadata adds to its immediate base class UIPropertyMetadata.
Each of these properties will be false by default. A metadata request for a property
where knowing the value of these properties is important should attempt to cast the
returned metadata to FrameworkPropertyMetadata, and then check the values of the
individual properties as needed.

Specifying Metadata
When you create a new metadata instance for purposes of applying metadata to a new
dependency property registration, you have the choice of which metadata class to use:
the base PropertyMetadata or some derived class such as FrameworkPropertyMetadata.
In general, you should use FrameworkPropertyMetadata, particularly if your property
has any interaction with property system and WPF functions such as layout and data
binding. Another option for more sophisticated scenarios is to derive from
FrameworkPropertyMetadata to create your own metadata reporting class with extra
information carried in its members. Or you might use PropertyMetadata or
UIPropertyMetadata to communicate the degree of support for features of your
implementation.

For existing properties (AddOwner or OverrideMetadata call), you should always


override with the metadata type used by the original registration.

If you are creating a FrameworkPropertyMetadata instance, there are two ways to


populate that metadata with values for the specific properties that communicate the
framework property characteristics:

1. Use the FrameworkPropertyMetadata constructor signature that allows a flags


parameter. This parameter should be filled with all desired combined values of the
FrameworkPropertyMetadataOptions enumeration flags.

2. Use one of the signatures without a flags parameter, and then set each reporting
Boolean property on FrameworkPropertyMetadata to true for each desired
characteristic change. If you do this, you must set these properties before any
elements with this dependency property are constructed; the Boolean properties
are read-write in order to allow this behavior of avoiding the flags parameter and
still populate the metadata, but the metadata must become effectively sealed
before property use. Thus, attempting to set the properties after metadata is
requested will be an invalid operation.

Framework Property Metadata Merge Behavior


When you override framework property metadata, the different metadata characteristics
are either merged or replaced.

PropertyChangedCallback is merged. If you add a new PropertyChangedCallback,


that callback is stored in the metadata. If you do not specify a
PropertyChangedCallback in the override, the value of PropertyChangedCallback is
promoted as a reference from the nearest ancestor that specified it in metadata.
The actual property system behavior for PropertyChangedCallback is that
implementations for all metadata owners in the hierarchy are retained and added
to a table, with order of execution by the property system being that the callbacks
of the most deeply derived class are invoked first. Inherited callbacks run only
once, counting as being owned by the class that placed them in metadata.

DefaultValue is replaced. If you do not specify a PropertyChangedCallback in the


override, the value of DefaultValue comes from the nearest ancestor that specified
it in metadata.

CoerceValueCallback implementations are replaced. If you add a new


CoerceValueCallback, that callback is stored in the metadata. If you do not specify
a CoerceValueCallback in the override, the value of CoerceValueCallback is
promoted as a reference from the nearest ancestor that specified it in metadata.

The property system behavior is that only the CoerceValueCallback in the


immediate metadata is invoked. No references to other CoerceValueCallback
implementations in the hierarchy are retained.

The flags of FrameworkPropertyMetadataOptions enumeration are combined as a


bitwise OR operation. If you specify FrameworkPropertyMetadataOptions, the
original options are not overwritten. To change an option, set the corresponding
property on FrameworkPropertyMetadata. For example, if the original
FrameworkPropertyMetadata object sets the
FrameworkPropertyMetadataOptions.NotDataBindable flag, you can change that
by setting FrameworkPropertyMetadata.IsNotDataBindable to false .

This behavior is implemented by Merge, and can be overridden on derived metadata


classes.

See also
GetMetadata
Dependency Property Metadata
Dependency Properties Overview
Custom Dependency Properties
Dependency Property Value Precedence
Article • 02/06/2023

This topic explains how the workings of the Windows Presentation Foundation (WPF)
property system can affect the value of a dependency property, and describes the
precedence by which aspects of the property system apply to the effective value of a
property.

Prerequisites
This topic assumes that you understand dependency properties from the perspective of
a consumer of existing dependency properties on WPF classes, and have read
Dependency Properties Overview. To follow the examples in this topic, you should also
understand WPF applications.

The WPF Property System


The WPF property system offers a powerful way to have the value of dependency
properties be determined by a variety of factors, enabling features such as real-time
property validation, late binding, and notifying related properties of changes to values
for other properties. The exact order and logic that is used to determine dependency
property values is reasonably complex. Knowing this order will help you avoid
unnecessary property setting, and might also clear up confusion over exactly why some
attempt to influence or anticipate a dependency property value did not end up resulting
in the value you expected.

Dependency Properties Might Be "Set" in


Multiple Places
The following is example XAML where the same property (Background) has three
different "set" operations that might influence the value.

XAML

<StackPanel>
<StackPanel.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type
Button}">
<Border Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</StackPanel.Resources>

<Button Template="{StaticResource ButtonTemplate}" Background="Red">


<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Blue"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Yellow" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
Which color do you expect?
</Button>
</StackPanel>

Here, which color do you expect will apply—red, green, or blue?

With the exception of animated values and coercion, local property sets are set at the
highest precedence. If you set a value locally you can expect that the value will be
honored, even above any styles or control templates. Here in the example, Background
is set to Red locally. Therefore, the style defined in this scope, even though it is an
implicit style that would otherwise apply to all elements of that type in that scope, is not
the highest precedence for giving the Background property its value. If you removed the
local value of Red from that Button instance, then the style would have precedence and
the button would obtain the Background value from the style. Within the style, triggers
take precedence, so the button will be blue if the mouse is over it, and green otherwise.

Dependency Property Setting Precedence List


The following is the definitive order that the property system uses when assigning the
run-time values of dependency properties. Highest precedence is listed first. This list
expands on some of the generalizations made in the Dependency Properties Overview.

1. Property system coercion. For details on coercion, see Coercion, Animation, and
Base Value later in this topic.

2. Active animations, or animations with a Hold behavior. In order to have any


practical effect, an animation of a property must be able to have precedence over
the base (unanimated) value, even if that value was set locally. For details, see
Coercion, Animation, and Base Value later in this topic.

3. Local value. A local value might be set through the convenience of the "wrapper"
property, which also equates to setting as an attribute or property element in
XAML, or by a call to the SetValue API using a property of a specific instance. If you
set a local value by using a binding or a resource, these each act in the precedence
as if a direct value was set.

4. TemplatedParent template properties. An element has a TemplatedParent if it was


created as part of a template (a ControlTemplate or DataTemplate). For details on
when this applies, see TemplatedParent later in this topic. Within the template, the
following precedence applies:

a. Triggers from the TemplatedParent template.

b. Property sets (typically through XAML attributes) in the TemplatedParent


template.

5. Implicit style. Applies only to the Style property. The Style property is filled by
any style resource with a key that matches the type of that element. That style
resource must exist either in the page or the application; lookup for an implicit
style resource does not proceed into the themes.

6. Style triggers. The triggers within styles from page or application (these styles
might be either explicit or implicit styles, but not from the default styles, which
have lower precedence).

7. Template triggers. Any trigger from a template within a style, or a directly applied
template.

8. Style setters. Values from a Setter within styles from page or application.

9. Default (theme) style. For details on when this applies, and how theme styles
relate to the templates within theme styles, see Default (Theme) Styles later in this
topic. Within a default style, the following order of precedence applies:

a. Active triggers in the theme style.

b. Setters in the theme style.

10. Inheritance. A few dependency properties inherit their values from parent element
to child elements, such that they need not be set specifically on each element
throughout an application. For details see Property Value Inheritance.
11. Default value from dependency property metadata. Any given dependency
property may have a default value as established by the property system
registration of that particular property. Also, derived classes that inherit a
dependency property have the option to override that metadata (including the
default value) on a per-type basis. See Dependency Property Metadata for more
information. Because inheritance is checked before default value, for an inherited
property, a parent element default value takes precedence over a child element.
Consequently, if an inheritable property is not set anywhere, the default value as
specified on the root or parent is used instead of the child element default value.

TemplatedParent
TemplatedParent as a precedence item does not apply to any property of an element
that you declare directly in standard application markup. The TemplatedParent concept
exists only for child items within a visual tree that come into existence through the
application of the template. When the property system searches the TemplatedParent
template for a value, it is searching the template that created that element. The property
values from the TemplatedParent template generally act as if they were set as a local
value on the child element, but this lesser precedence versus the local value exists
because the templates are potentially shared. For details, see TemplatedParent.

The Style Property


The order of lookup described earlier applies to all possible dependency properties
except one: the Style property. The Style property is unique in that it cannot itself be
styled, so the precedence items 5 through 8 do not apply. Also, either animating or
coercing Style is not recommended (and animating Style would require a custom
animation class). This leaves three ways that the Style property might be set:

Explicit style. The Style property is set directly. In most scenarios, the style is not
defined inline, but instead is referenced as a resource, by explicit key. In this case
the Style property itself acts as if it were a local value, precedence item 3.

Implicit style. The Style property is not set directly. However, the Style exists at
some level in the resource lookup sequence (page, application) and is keyed using
a resource key that matches the type the style is to be applied to. In this case, the
Style property itself acts by a precedence identified in the sequence as item 5. This
condition can be detected by using DependencyPropertyHelper against the Style
property and looking for ImplicitStyleReference in the results.
Default style, also known as theme style. The Style property is not set directly, and
in fact will read as null up until run time. In this case, the style comes from the
run-time theme evaluation that is part of the WPF presentation engine.

For implicit styles not in themes, the type must match exactly - a MyButton Button -
derived class will not implicitly use a style for Button .

Default (Theme) Styles


Every control that ships with WPF has a default style. That default style potentially varies
by theme, which is why this default style is sometimes referred to as a theme style.

The most important information that is found within a default style for a control is its
control template, which exists in the theme style as a setter for its Template property. If
there were no template from default styles, a control without a custom template as part
of a custom style would have no visual appearance at all. The template from the default
style gives the visual appearance of each control a basic structure, and also defines the
connections between properties defined in the visual tree of the template and the
corresponding control class. Each control exposes a set of properties that can influence
the visual appearance of the control without completely replacing the template. For
example, consider the default visual appearance of a Thumb control, which is a
component of a ScrollBar.

A Thumb has certain customizable properties. The default template of a Thumb creates
a basic structure / visual tree with several nested Border components to create a bevel
look. If a property that is part of the template is intended to be exposed for
customization by the Thumb class, then that property must be exposed by a
TemplateBinding, within the template. In the case of Thumb, various properties of these
borders share a template binding to properties such as Background or BorderThickness.
But certain other properties or visual arrangements are hard-coded into the control
template or are bound to values that come directly from the theme, and cannot be
changed short of replacing the entire template. Generally, if a property comes from a
templated parent and is not exposed by a template binding, it cannot be adjusted by
styles because there is no easy way to target it. But that property could still be
influenced by property value inheritance in the applied template, or by default value.

The theme styles use a type as the key in their definitions. However, when themes are
applied to a given element instance, themes lookup for this type is performed by
checking the DefaultStyleKey property on a control. This is in contrast to using the literal
Type, as implicit styles do. The value of DefaultStyleKey would inherit to derived classes
even if the implementer did not change it (the intended way of changing the property is
not to override it at the property level, but to instead change its default value in
property metadata). This indirection enables base classes to define the theme styles for
derived elements that do not otherwise have a style (or more importantly, do not have a
template within that style and would thus have no default visual appearance at all).
Thus, you can derive MyButton from Button and will still get the Button default template.
If you were the control author of MyButton and you wanted a different behavior, you
could override the dependency property metadata for DefaultStyleKey on MyButton to
return a different key, and then define the relevant theme styles including template for
MyButton that you must package with your MyButton control. For more details on
themes, styles, and control authoring, see Control Authoring Overview.

Dynamic Resource References and Binding


Dynamic resource references and binding operations respect the precedence of the
location at which they are set. For example, a dynamic resource applied to a local value
acts per precedence item 3, a binding for a property setter within a theme style applies
at precedence item 9, and so on. Because dynamic resource references and binding
must both be able to obtain values from the run time state of the application, this
entails that the actual process of determining the property value precedence for any
given property extends into the run time as well.

Dynamic resource references are not strictly speaking part of the property system, but
they do have a lookup order of their own which interacts with the sequence listed
above. That precedence is documented more thoroughly in the XAML Resources. The
basic summation of that precedence is: element to page root, application, theme,
system.

Dynamic resources and bindings have the precedence of where they were set, but the
value is deferred. One consequence of this is that if you set a dynamic resource or
binding to a local value, any change to the local value replaces the dynamic resource or
binding entirely. Even if you call the ClearValue method to clear the locally set value, the
dynamic resource or binding will not be restored. In fact, if you call ClearValue on a
property that has a dynamic resource or binding in place (with no literal local value),
they are cleared by the ClearValue call too.

SetCurrentValue
The SetCurrentValue method is another way to set a property, but it is not in the order
of precedence. Instead, SetCurrentValue enables you to change the value of a property
without overwriting the source of a previous value. You can use SetCurrentValue any
time that you want to set a value without giving that value the precedence of a local
value. For example, if a property is set by a trigger and then assigned another value via
SetCurrentValue, the property system still respects the trigger and the property will
change if the trigger’s action occurs. SetCurrentValue enables you to change the
property’s value without giving it a source with a higher precedence. Likewise, you can
use SetCurrentValue to change the value of a property without overwriting a binding.

Coercion, Animations, and Base Value


Coercion and animation both act on a value that is termed as the "base value"
throughout this SDK. The base value is thus whatever value is determined through
evaluating upwards in the items until item 2 is reached.

For an animation, the base value can have an effect on the animated value, if that
animation does not specify both "From" and "To" for certain behaviors, or if the
animation deliberately reverts to the base value when completed. To see this in practice,
run the From, To, and By Animation Target Values Sample . Try setting the local values
of the rectangle height in the example, such that the initial local value differs from any
"From" in the animation. You will note that the animations start right away using the
"From" values and replace the base value once started. The animation might specify to
return to the value found before animation once it is completed by specifying the Stop
FillBehavior. Afterwards, normal precedence is used for the base value determination.

Multiple animations might be applied to a single property, with each of these


animations possibly having been defined from different points in the value precedence.
However, these animations will potentially composite their values, rather than just
applying the animation from the higher precedence. This depends on exactly how the
animations are defined, and the type of the value that is being animated. For more
information about animating properties, see Animation Overview.

Coercion applies at the highest level of all. Even an already running animation is subject
to value coercion. Certain existing dependency properties in WPF have built-in coercion.
For a custom dependency property, you define the coercion behavior for a custom
dependency property by writing a CoerceValueCallback and passing the callback as part
of metadata when you create the property. You can also override coercion behavior of
existing properties by overriding the metadata on that property in a derived class.
Coercion interacts with the base value in such a way that the constraints on coercion are
applied as those constraints exist at the time, but the base value is still retained.
Therefore, if constraints in coercion are later lifted, the coercion will return the closest
value possible to that base value, and potentially the coercion influence on a property
will cease as soon as all constraints are lifted. For more information about coercion
behavior, see Dependency Property Callbacks and Validation.

Trigger Behaviors
Controls often define trigger behaviors as part of their default style in themes. Setting
local properties on controls might prevent the triggers from being able to respond to
user-driven events either visually or behaviorally. The most common use of a property
trigger is for control or state properties such as IsSelected. For example, by default when
a Button is disabled (trigger for IsEnabled is false ) then the Foreground value in the
theme style is what causes the control to appear "grayed out". But if you have set a local
Foreground value, that normal gray-out color will be overruled in precedence by your
local property set, even in this property-triggered scenario. Be cautious of setting values
for properties that have theme-level trigger behaviors and make sure you are not
unduly interfering with the intended user experience for that control.

ClearValue and Value Precedence


The ClearValue method provides an expedient means to clear any locally applied value
from a dependency property that is set on an element. However, calling ClearValue is
not a guarantee that the default as established in metadata during property registration
is the new effective value. All of the other participants in value precedence are still
active. Only the locally set value has been removed from the precedence sequence. For
example, if you call ClearValue on a property where that property is also set by a theme
style, then the theme value is applied as the new value rather than the metadata-based
default. If you want to take all property value participants out of the process and set the
value to the registered metadata default, you can obtain that default value definitively
by querying the dependency property metadata, and then you can use the default value
to locally set the property with a call to SetValue.

See also
DependencyObject
DependencyProperty
Dependency Properties Overview
Custom Dependency Properties
Dependency Property Callbacks and Validation
Read-Only Dependency Properties
Article • 02/06/2023

This topic describes read-only dependency properties, including existing read-only


dependency properties and the scenarios and techniques for creating a custom read-
only dependency property.

Prerequisites
This topic assumes that you understand the basic scenarios of implementing a
dependency property, and how metadata is applied to a custom dependency property.
See Custom Dependency Properties and Dependency Property Metadata for context.

Existing Read-Only Dependency Properties


Some of the dependency properties defined in the Windows Presentation Foundation
(WPF) framework are read-only. The typical reason for specifying a read-only
dependency property is that these are properties that should be used for state
determination, but where that state is influenced by a multitude of factors, but just
setting the property to that state isn't desirable from a user interface design perspective.
For example, the property IsMouseOver is really just surfacing state as determined from
the mouse input. Any attempt to set this value programmatically by circumventing the
true mouse input would be unpredictable and would cause inconsistency.

By virtue of not being settable, read-only dependency properties aren't appropriate for
many of the scenarios for which dependency properties normally offer a solution
(namely: data binding, directly stylable to a value, validation, animation, inheritance).
Despite not being settable, read-only dependency properties still have some of the
additional capabilities supported by dependency properties in the property system. The
most important remaining capability is that the read-only dependency property can still
be used as a property trigger in a style. You can't enable triggers with a normal common
language runtime (CLR) property; it needs to be a dependency property. The
aforementioned IsMouseOver property is a perfect example of a scenario where it might
be quite useful to define a style for a control, where some visible property such as a
background, foreground, or similar properties of composited elements within the
control will change when the user places a mouse over some defined region of your
control. Changes in a read-only dependency property can also be detected and
reported by the property system's inherent invalidation processes, and this in fact
supports the property trigger functionality internally.
Creating Custom Read-Only Dependency
Properties
Make sure to read the section above regarding why read-only dependency properties
won't work for many typical dependency-property scenarios. But if you have an
appropriate scenario, you may wish to create your own read-only dependency property.

Much of the process of creating a read-only dependency property is the same as is


described in the Custom Dependency Properties and Implement a Dependency Property
topics. There are three important differences:

When registering your property, call the RegisterReadOnly method instead of the
normal Register method for property registration.

When implementing the CLR "wrapper" property, make sure that the wrapper too
doesn't have a set implementation, so that there is no inconsistency in read-only
state for the public wrapper you expose.

The object returned by the read-only registration is DependencyPropertyKey rather


than DependencyProperty. You should still store this field as a member but
typically you would not make it a public member of the type.

Whatever private field or value you have backing your read-only dependency property
can of course be fully writable using whatever logic you decide. However, the most
straightforward way to set the property either initially or as part of runtime logic is to
use the property system's APIs, rather than circumventing the property system and
setting the private backing field directly. In particular, there is a signature of SetValue
that accepts a parameter of type DependencyPropertyKey. How and where you set this
value programmatically within your application logic will affect how you may wish to set
access on the DependencyPropertyKey created when you first registered the
dependency property. If you handle this logic all within the class you could make it
private, or if you require it to be set from other portions of the assembly you might set it
internal. One approach is to call SetValue within a class event handler of a relevant event
that informs a class instance that the stored property value needs to be changed.
Another approach is to tie dependency properties together by using paired
PropertyChangedCallback and CoerceValueCallback callbacks as part of those
properties' metadata during registration.

Because the DependencyPropertyKey is private, and is not propagated by the property


system outside of your code, a read-only dependency property does have better setting
security than a read-write dependency property. For a read-write dependency property,
the identifying field is explicitly or implicitly public and thus the property is widely
settable. For more specifics, see Dependency Property Security.

See also
Dependency Properties Overview
Custom Dependency Properties
Styling and Templating
Property Value Inheritance
Article • 02/06/2023

Property value inheritance is a feature of the Windows Presentation Foundation (WPF)


property system. Property value inheritance enables child elements in a tree of elements
to obtain the value of a particular property from parent elements, inheriting that value
as it was set anywhere in the nearest parent element. The parent element might also
have obtained its value through property value inheritance, so the system potentially
recurses all the way to the page root. Property value inheritance is not the default
property system behavior; a property must be established with a particular metadata
setting in order to cause that property to initiate property value inheritance on child
elements.

Property Value Inheritance Is Containment


Inheritance
"Inheritance" as a term here is not quite the same concept as inheritance in the context
of types and general object-oriented programming, where derived classes inherit
member definitions from their base classes. That meaning of inheritance is also active in
WPF: properties defined in various base classes are exposed as attributes for derived
XAML classes when used as elements, and exposed as members for code. Property value
inheritance is particularly about how property values can inherit from one element to
another on the basis of the parent-child relationships within a tree of elements. That
tree of elements is most directly visible when nesting elements inside other elements as
you define applications in XAML markup. Trees of objects can also be created
programmatically by adding objects to designated collections of other objects, and
property value inheritance works the same way in the finished tree at run time.

Practical Applications of Property Value


Inheritance
The WPF APIs include several properties that have property inheritance enabled.
Typically, the scenario for these is that they involve a property where it is appropriate
that the property be set only once per page, but where that property is also a member
of one of the base element classes and thus would also exist on most of the child
elements. For example, the FlowDirection property controls which direction flowed
content should be presented and arranged on the page. Typically, you want the text
flow concept to be handled consistently throughout all child elements. If flow direction
were for some reason reset in some level of the element tree by user or environment
action, it should typically be reset throughout. When the FlowDirection property is made
to inherit, the value need only be set or reset once at the level in the element tree that
encompasses the presentation needs of each page in the application. Even the initial
default value will inherit in this way. The property value inheritance model still enables
individual elements to reset the value for the rare cases where having a mix of flow
directions is intentional.

Making a Custom Property Inheritable


By changing a custom property's metadata, you can also make your own custom
properties inheritable. Note, however, that designating a property as inheritable does
have some performance considerations. In cases where that property does not have an
established local value, or a value obtained through styles, templates, or data binding,
an inheritable property provides its assigned property values to all child elements in the
logical tree.

To make a property participate in value inheritance, create a custom attached property,


as described in Register an Attached Property. Register the property with metadata
(FrameworkPropertyMetadata) and specify the "Inherits" option in the options settings
within that metadata. Also make sure that the property has an established default value,
because that value will now inherit. Although you registered the property as attached,
you might also want to create a property "wrapper" for get/set access on the owner
type, just as you would for an "nonattached" dependency property. After doing so, the
inheritable property can either be set by using the direct property wrapper on the owner
type or derived types, or it can be set by using the attached property syntax on any
DependencyObject.

Attached properties are conceptually similar to global properties; you can check for the
value on any DependencyObject and get a valid result. The typical scenario for attached
properties is to set property values on child elements, and that scenario is more
effective if the property in question is an attached property that is always implicitly
present as an attached property on each element (DependencyObject) in the tree.

7 Note

Although property value inheritance might appear to work for nonattached


dependency properties, the inheritance behavior for a nonattached property
through certain element boundaries in the run-time tree is undefined. Always use
RegisterAttached to register properties where you specify Inherits in the metadata.
Inheriting Property Values Across Tree
Boundaries
Property inheritance works by traversing a tree of elements. This tree is often parallel to
the logical tree. However, whenever you include a WPF core-level object in the markup
that defines an element tree, such as a Brush, you have created a discontinuous logical
tree. A true logical tree does not conceptually extend through the Brush, because the
logical tree is a WPF framework-level concept. You can see this reflected in the results
when using the methods of LogicalTreeHelper. However, property value inheritance can
bridge this gap in the logical tree and can still pass inherited values through, so long as
the inheritable property was registered as an attached property and no deliberate
inheritance-blocking boundary (such as a Frame) is encountered.

See also
Dependency Property Metadata
Attached Properties Overview
Dependency Property Value Precedence
Dependency Property Security
Article • 02/06/2023

Dependency properties should generally be considered to be public properties. The


nature of the Windows Presentation Foundation (WPF) property system prevents the
ability to make security guarantees about a dependency property value.

Access and Security of Wrappers and


Dependency Properties
Typically, dependency properties are implemented along with "wrapper" common
language runtime (CLR) properties that simplify getting or setting the property from an
instance. But the wrappers are really just convenience methods that implement the
underlying GetValue and SetValue static calls that are used when interacting with
dependency properties. Thinking of it in another way, the properties are exposed as
common language runtime (CLR) properties that happen to be backed by a dependency
property rather than by a private field. Security mechanisms applied to the wrappers do
not parallel the property system behavior and access of the underlying dependency
property. Placing a security demand on the wrapper will only prevent the usage of the
convenience method but will not prevent calls to GetValue or SetValue. Similarly, placing
protected or private access level on the wrappers does not provide any effective
security.

If you are writing your own dependency properties, you should declare the wrappers
and the DependencyProperty identifier field as public members, so that callers do not
get misleading information about the true access level of that property (because of its
store being implemented as a dependency property).

For a custom dependency property, you can register your property as a read-only
dependency property, and this does provide an effective means of preventing a
property being set by anyone that does not hold a reference to the
DependencyPropertyKey for that property. For more information, see Read-Only
Dependency Properties.

7 Note

Declaring a DependencyProperty identifier field private is not forbidden, and it can


conceivably be used to help reduce the immediately exposed namespace of a
custom class, but such a property should not be considered "private" in the same
sense as the common language runtime (CLR) language definitions define that
access level, for reasons described in the next section.

Property System Exposure of Dependency


Properties
It is not generally useful, and it is potentially misleading, to declare a
DependencyProperty as any access level other than public. That access level setting only
prevents someone from being able to get a reference to the instance from the declaring
class. But there are several aspects of the property system that will return a
DependencyProperty as the means of identifying a particular property as it exists on an
instance of a class or a derived class instance, and this identifier is still usable in a
SetValue call even if the original static identifier is declared as nonpublic. Also,
OnPropertyChanged virtual methods receive information of any existing dependency
property that changed value. In addition, the GetLocalValueEnumerator method returns
identifiers for any property on instances with a locally set value.

Validation and Security


Applying a demand to a ValidateValueCallback and expecting the validation failure on a
demand failure to prevent a property from being set is not an adequate security
mechanism. Set-value invalidation enforced through ValidateValueCallback could also be
suppressed by malicious callers, if those callers are operating within the application
domain.

See also
Custom Dependency Properties
Safe Constructor Patterns for
DependencyObjects
Article • 02/06/2023

Generally, class constructors should not call callbacks such as virtual methods or
delegates, because constructors can be called as base initialization of constructors for a
derived class. Entering the virtual might be done at an incomplete initialization state of
any given object. However, the property system itself calls and exposes callbacks
internally, as part of the dependency property system. As simple an operation as setting
a dependency property value with SetValue call potentially includes a callback
somewhere in the determination. For this reason, you should be careful when setting
dependency property values within the body of a constructor, which can become
problematic if your type is used as a base class. There is a particular pattern for
implementing DependencyObject constructors that avoids specific problems with
dependency property states and the inherent callbacks, which is documented here.

Property System Virtual Methods


The following virtual methods or callbacks are potentially called during the
computations of the SetValue call that sets a dependency property value:
ValidateValueCallback, PropertyChangedCallback, CoerceValueCallback,
OnPropertyChanged. Each of these virtual methods or callbacks serves a particular
purpose in expanding the versatility of the Windows Presentation Foundation (WPF)
property system and dependency properties. For more information on how to use these
virtuals to customize property value determination, see Dependency Property Callbacks
and Validation.

FXCop Rule Enforcement vs. Property System Virtuals


If you use the Microsoft tool FXCop as part of your build process, and you either derive
from certain WPF framework classes calling the base constructor, or implement your
own dependency properties on derived classes, you might encounter a particular FXCop
rule violation. The name string for this violation is:

DoNotCallOverridableMethodsInConstructors

This is a rule that is part of the default public rule set for FXCop. What this rule might be
reporting is a trace through the dependency property system that eventually calls a
dependency property system virtual method. This rule violation might continue to
appear even after following the recommended constructor patterns documented in this
topic, so you might need to disable or suppress that rule in your FXCop rule set
configuration.

Most Issues Come From Deriving Classes, Not Using


Existing Classes
The issues reported by this rule occur when a class that you implement with virtual
methods in its construction sequence is then derived from. If you seal your class, or
otherwise know or enforce that your class will not be derived from, the considerations
explained here and the issues that motivated the FXCop rule do not apply to you.
However, if you are authoring classes in such a way that they are intended to be used as
base classes, for instance if you are creating templates, or an expandable control library
set, you should follow the patterns recommended here for constructors.

Default Constructors Must Initialize All Values Requested


By Callbacks
Any instance members that are used by your class overrides or callbacks (the callbacks
from the list in the Property System Virtuals section) must be initialized in your class
parameterless constructor, even if some of those values are filled by "real" values
through parameters of the nonparameterless constructors.

The following example code (and subsequent examples) is a pseudo-C# example that
violates this rule and explains the problem:

C#

public class MyClass : DependencyObject


{
public MyClass() {}
public MyClass(object toSetWobble)
: this()
{
Wobble = toSetWobble; //this is backed by a DependencyProperty
_myList = new ArrayList(); // this line should be in the default
ctor
}
public static readonly DependencyProperty WobbleProperty =
DependencyProperty.Register("Wobble", typeof(object),
typeof(MyClass));
public object Wobble
{
get { return GetValue(WobbleProperty); }
set { SetValue(WobbleProperty, value); }
}
protected override void
OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
int count = _myList.Count; // null-reference exception
}
private ArrayList _myList;
}

When application code calls new MyClass(objectvalue) , this calls the parameterless
constructor and base class constructors. Then it sets Property1 = object1 , which calls
the virtual method OnPropertyChanged on the owning MyClass DependencyObject. The
override refers to _myList , which has not been initialized yet.

One way to avoid these issues is to make sure that callbacks use only other dependency
properties, and that each such dependency property has an established default value as
part of its registered metadata.

Safe Constructor Patterns


To avoid the risks of incomplete initialization if your class is used as a base class, follow
these patterns:

Parameterless constructors calling base initialization


Implement these constructors calling the base default:

C#

public MyClass : SomeBaseClass {


public MyClass() : base() {
// ALL class initialization, including initial defaults for
// possible values that other ctors specify or that callbacks need.
}
}

Non-default (convenience) constructors, not matching any base


signatures

If these constructors use the parameters to set dependency properties in the


initialization, first call your own class parameterless constructor for initialization, and
then use the parameters to set dependency properties. These could either be
dependency properties defined by your class, or dependency properties inherited from
base classes, but in either case use the following pattern:

C#

public MyClass : SomeBaseClass {


public MyClass(object toSetProperty1) : this() {
// Class initialization NOT done by default.
// Then, set properties to values as passed in ctor parameters.
Property1 = toSetProperty1;
}
}

Non-default (convenience) constructors, which do match base


signatures
Instead of calling the base constructor with the same parameterization, again call your
own class' parameterless constructor. Do not call the base initializer; instead you should
call this() . Then reproduce the original constructor behavior by using the passed
parameters as values for setting the relevant properties. Use the original base
constructor documentation for guidance in determining the properties that the
particular parameters are intended to set:

C#

public MyClass : SomeBaseClass {


public MyClass(object toSetProperty1) : this() {
// Class initialization NOT done by default.
// Then, set properties to values as passed in ctor parameters.
Property1 = toSetProperty1;
}
}

Must match all signatures

For cases where the base type has multiple signatures, you must deliberately match all
possible signatures with a constructor implementation of your own that uses the
recommended pattern of calling the class parameterless constructor before setting
further properties.

Setting dependency properties with SetValue


These same patterns apply if you are setting a property that does not have a wrapper
for property setting convenience, and set values with SetValue. Your calls to SetValue
that pass through constructor parameters should also call the class' parameterless
constructor for initialization.

See also
Custom Dependency Properties
Dependency Properties Overview
Dependency Property Security
Collection-Type Dependency Properties
Article • 02/06/2023

This topic provides guidance and suggested patterns for how to implement a
dependency property where the type of the property is a collection type.

Implementing a Collection-Type Dependency


Property
For a dependency property in general, the implementation pattern that you follow is
that you define a CLR property wrapper, where that property is backed by a
DependencyProperty identifier rather than a field or other construct. You follow this
same pattern when you implement a collection-type property. However, a collection-
type property introduces some complexity to the pattern whenever the type that is
contained within the collection is itself a DependencyObject or Freezable derived class.

Initializing the Collection Beyond the Default


Value
When you create a dependency property, you do not specify the property default value
as the initial field value. Instead, you specify the default value through the dependency
property metadata. If your property is a reference type, the default value specified in
dependency property metadata is not a default value per instance; instead it is a default
value that applies to all instances of the type. Therefore you must be careful to not use
the singular static collection defined by the collection property metadata as the working
default value for newly created instances of your type. Instead, you must make sure that
you deliberately set the collection value to a unique (instance) collection as part of your
class constructor logic. Otherwise you will have created an unintentional singleton class.

Consider the following example. The following section of the example shows the
definition for a class Aquarium , which contains a flaw with the default value. The class
defines the collection type dependency property AquariumObjects , which uses the
generic List<T> type with a FrameworkElement type constraint. In the Register(String,
Type, Type, PropertyMetadata) call for the dependency property, the metadata
establishes the default value to be a new generic List<T>.

2 Warning
The following code does not behave correctly.

C#

public class Fish : FrameworkElement { }


public class Aquarium : DependencyObject {
private static readonly DependencyPropertyKey
AquariumContentsPropertyKey =
DependencyProperty.RegisterReadOnly(
"AquariumContents",
typeof(List<FrameworkElement>),
typeof(Aquarium),
new FrameworkPropertyMetadata(new List<FrameworkElement>())
);
public static readonly DependencyProperty AquariumContentsProperty =
AquariumContentsPropertyKey.DependencyProperty;

public List<FrameworkElement> AquariumContents


{
get { return
(List<FrameworkElement>)GetValue(AquariumContentsProperty); }
}

// ...
}

However, if you just left the code as shown, that single list default value is shared for all
instances of Aquarium . If you ran the following test code, which is intended to show how
you would instantiate two separate Aquarium instances and add a single different Fish
to each of them, you would see a surprising result:

C#

Aquarium myAq1 = new Aquarium();


Aquarium myAq2 = new Aquarium();
Fish f1 = new Fish();
Fish f2 = new Fish();
myAq1.AquariumContents.Add(f1);
myAq2.AquariumContents.Add(f2);
MessageBox.Show("aq1 contains " + myAq1.AquariumContents.Count.ToString() +
" things");
MessageBox.Show("aq2 contains " + myAq2.AquariumContents.Count.ToString() +
" things");

Instead of each collection having a count of one, each collection has a count of two! This
is because each Aquarium added its Fish to the default value collection, which resulted
from a single constructor call in the metadata and is therefore shared between all
instances. This situation is almost never what you want.
To correct this problem, you must reset the collection dependency property value to a
unique instance, as part of the class constructor call. Because the property is a read-only
dependency property, you use the SetValue(DependencyPropertyKey, Object) method to
set it, using the DependencyPropertyKey that is only accessible within the class.

C#

public Aquarium() : base()


{
SetValue(AquariumContentsPropertyKey, new List<FrameworkElement>());
}

Now, if you ran that same test code again, you could see more expected results, where
each Aquarium supported its own unique collection.

There would be a slight variation on this pattern if you chose to have your collection
property be read-write. In that case, you could call the public set accessor from the
constructor to do the initialization, which would still be calling the nonkey signature of
SetValue(DependencyProperty, Object) within your set wrapper, using a public
DependencyProperty identifier.

Reporting Binding Value Changes from


Collection Properties
A collection property that is itself a dependency property does not automatically report
changes to its subproperties. If you are creating bindings into a collection, this can
prevent the binding from reporting changes, thus invalidating some data binding
scenarios. However, if you use the collection type FreezableCollection<T> as your
collection type, then subproperty changes to contained elements in the collection are
properly reported, and binding works as expected.

To enable subproperty binding in a dependency object collection, create the collection


property as type FreezableCollection<T>, with a type constraint for that collection to
any DependencyObject derived class.

See also
FreezableCollection<T>
XAML and Custom Classes for WPF
Data Binding Overview
Dependency Properties Overview
Custom Dependency Properties
Dependency Property Metadata
XAML Loading and Dependency
Properties
Article • 02/06/2023

The current WPF implementation of its WPF XAML processor uses property system
methods for dependency properties when loading binary XAML and processing
attributes that are dependency properties. This effectively bypasses the property
wrappers. When you implement custom dependency properties, you must account for
this behavior and should avoid placing any other code in your property wrapper other
than the property system methods GetValue and SetValue.

Prerequisites
This topic assumes that you understand dependency properties both as consumer and
author and have read Dependency Properties Overview and Custom Dependency
Properties. You should also have read XAML in WPF and XAML Syntax In Detail.

The WPF XAML Loader Implementation, and


Performance
For implementation reasons, it is computationally less expensive to identify a property
as a dependency property and access the property system SetValue method to set it,
rather than using the property wrapper and its setter. This is because a XAML processor
must infer the entire object model of the backing code based only on knowing the type
and member relationships that are indicated by the structure of the markup and various
strings.

The type is looked up through a combination of xmlns and assembly attributes, but
identifying the members, determining which could support being set as an attribute,
and resolving what types the property values support would otherwise require extensive
reflection using PropertyInfo. Because dependency properties on a given type are
accessible as a storage table through the property system, the WPF implementation of
its XAML processor uses this table and infers that any given property ABC can be more
efficiently set by calling SetValue on the containing DependencyObject derived type,
using the dependency property identifier ABCProperty.
Implications for Custom Dependency
Properties
Because the current WPF implementation of the XAML processor behavior for property
setting bypasses the wrappers entirely, you should not put any additional logic into the
set definitions of the wrapper for your custom dependency property. If you put such
logic in the set definition, then the logic will not be executed when the property is set in
XAML rather than in code.

Similarly, other aspects of the XAML processor that obtain property values from XAML
processing also use GetValue rather than using the wrapper. Therefore, you should also
avoid any additional implementation in the get definition beyond the GetValue call.

The following example is a recommended dependency property definition with


wrappers, where the property identifier is stored as a public static readonly field, and
the get and set definitions contain no code beyond the necessary property system
methods that define the dependency property backing.

C#

public static readonly DependencyProperty AquariumGraphicProperty =


DependencyProperty.Register(
"AquariumGraphic",
typeof(Uri),
typeof(AquariumObject),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnUriChanged)
)
);
public Uri AquariumGraphic
{
get { return (Uri)GetValue(AquariumGraphicProperty); }
set { SetValue(AquariumGraphicProperty, value); }
}

See also
Dependency Properties Overview
XAML in WPF
Dependency Property Metadata
Collection-Type Dependency Properties
Dependency Property Security
Safe Constructor Patterns for DependencyObjects
Properties How-to Topics
Article • 02/06/2023

In This Section
Implement a Dependency Property
Add an Owner Type for a Dependency Property
Register an Attached Property
Override Metadata for a Dependency Property

Reference
DependencyProperty

PropertyMetadata

FrameworkPropertyMetadata

DependencyObject

Related Sections
Properties
How to: Implement a Dependency
Property
Article • 02/06/2023

This example shows how to back a common language runtime (CLR) property with a
DependencyProperty field, thus defining a dependency property. When you define your
own properties and want them to support many aspects of Windows Presentation
Foundation (WPF) functionality, including styles, data binding, inheritance, animation,
and default values, you should implement them as a dependency property.

Example
The following example first registers a dependency property by calling the Register
method. The name of the identifier field that you use to store the name and
characteristics of the dependency property must be the Name you chose for the
dependency property as part of the Register call, appended by the literal string
Property . For instance, if you register a dependency property with a Name of Location ,
then the identifier field that you define for the dependency property must be named
LocationProperty .

In this example, the name of the dependency property and its CLR accessor is State ; the
identifier field is StateProperty ; the type of the property is Boolean; and the type that
registers the dependency property is MyStateControl .

If you fail to follow this naming pattern, designers might not report your property
correctly, and certain aspects of property system style application might not behave as
expected.

You can also specify default metadata for a dependency property. This example registers
the default value of the State dependency property to be false .

C#

public class MyStateControl : ButtonBase


{
public MyStateControl() : base() { }
public Boolean State
{
get { return (Boolean)this.GetValue(StateProperty); }
set { this.SetValue(StateProperty, value); }
}
public static readonly DependencyProperty StateProperty =
DependencyProperty.Register(
"State", typeof(Boolean), typeof(MyStateControl),new
PropertyMetadata(false));
}

For more information about how and why to implement a dependency property, as
opposed to just backing a CLR property with a private field, see Dependency Properties
Overview.

See also
Dependency Properties Overview
How-to Topics
How to: Add an Owner Type for a
Dependency Property
Article • 02/06/2023

This example shows how to add a class as an owner of a dependency property


registered for a different type. By doing this, the WPF XAML reader and property system
are both able to recognize the class as an additional owner of the property. Adding as
owner optionally allows the adding class to provide type-specific metadata.

In the following example, StateProperty is a property registered by the MyStateControl


class. The class UnrelatedStateControl adds itself as an owner of the StateProperty
using the AddOwner method, specifically using the signature that allows for new
metadata for the dependency property as it exists on the adding type. Notice that you
should provide common language runtime (CLR) accessors for the property similar to
the example shown in the Implement a Dependency Property example, as well as re-
expose the dependency property identifier on the class being added as owner.

Without wrappers, the dependency property would still work from the perspective of
programmatic access using GetValue or SetValue. But you typically want to parallel this
property-system behavior with the CLR property wrappers. The wrappers make it easier
to set the dependency property programmatically, and make it possible to set the
properties as XAML attributes.

To find out how to override default metadata, see Override Metadata for a Dependency
Property.

Example
C#

public class MyStateControl : ButtonBase


{
public MyStateControl() : base() { }
public Boolean State
{
get { return (Boolean)this.GetValue(StateProperty); }
set { this.SetValue(StateProperty, value); }
}
public static readonly DependencyProperty StateProperty =
DependencyProperty.Register(
"State", typeof(Boolean), typeof(MyStateControl),new
PropertyMetadata(false));
}
C#

public class UnrelatedStateControl : Control


{
public UnrelatedStateControl() { }
public static readonly DependencyProperty StateProperty =
MyStateControl.StateProperty.AddOwner(typeof(UnrelatedStateControl), new
PropertyMetadata(true));
public Boolean State
{
get { return (Boolean)this.GetValue(StateProperty); }
set { this.SetValue(StateProperty, value); }
}
}

See also
Custom Dependency Properties
Dependency Properties Overview
How to: Register an Attached Property
Article • 08/10/2023

This example shows how to register an attached property and provide public accessors
so that you can use the property in both XAML and code. Attached properties are a
syntax concept defined by XAML. Most attached properties for WPF types are also
implemented as dependency properties. You can use dependency properties on any
DependencyObject types.

Example
The following example shows how to register an attached property as a dependency
property, by using the RegisterAttached method. The provider class has the option of
providing default metadata for the property that is applicable when the property is used
on another class, unless that class overrides the metadata. In this example, the default
value of the IsBubbleSource property is set to false .

The provider class for an attached property (even if it is not registered as a dependency
property) must provide static get and set accessors that follow the naming convention
Set [AttachedPropertyName] and Get [AttachedPropertyName]. These accessors are

required so that the acting XAML reader can recognize the property as an attribute in
XAML and resolve the appropriate types.

C#

public static readonly DependencyProperty IsBubbleSourceProperty =


DependencyProperty.RegisterAttached(
"IsBubbleSource",
typeof(Boolean),
typeof(AquariumObject),
new FrameworkPropertyMetadata(false,
FrameworkPropertyMetadataOptions.AffectsRender)
);
public static void SetIsBubbleSource(UIElement element, Boolean value)
{
element.SetValue(IsBubbleSourceProperty, value);
}
public static Boolean GetIsBubbleSource(UIElement element)
{
return (Boolean)element.GetValue(IsBubbleSourceProperty);
}

See also
DependencyProperty
Dependency Properties Overview
Custom Dependency Properties
How-to Topics
How to: Override Metadata for a
Dependency Property
Article • 06/02/2023

This example shows how to override default dependency property metadata that comes
from an inherited class, by calling the OverrideMetadata method and providing type-
specific metadata.

Example
By defining its PropertyMetadata, a class can define the dependency property's
behaviors, such as its default value and property system callbacks. Many dependency
property classes already have default metadata established as part of their registration
process. This includes the dependency properties that are part of the WPF API. A class
that inherits the dependency property through its class inheritance can override the
original metadata so that the characteristics of the property that can be altered through
metadata will match any subclass-specific requirements.

Overriding metadata on a dependency property must be done prior to that property


being placed in use by the property system (this equates to the time that specific
instances of objects that register the property are instantiated). Calls to
OverrideMetadata must be performed within the static constructors of the type that
provides itself as the forType parameter of OverrideMetadata. If you attempt to change
metadata once instances of the owner type exist, this will not raise exceptions, but will
result in inconsistent behaviors in the property system. Also, metadata can only be
overridden once per type. Subsequent attempts to override metadata on the same type
will raise an exception.

In the following example, the custom class MyAdvancedStateControl overrides the


metadata provided for StateProperty by MyStateControl with new property metadata.
For instance, the default value of the StateProperty is now true when the property is
queried on a newly constructed MyAdvancedStateControl instance.

C#

public class MyStateControl : ButtonBase


{
public MyStateControl() : base() { }
public Boolean State
{
get { return (Boolean)this.GetValue(StateProperty); }
set { this.SetValue(StateProperty, value); }
}
public static readonly DependencyProperty StateProperty =
DependencyProperty.Register(
"State", typeof(Boolean), typeof(MyStateControl),new
PropertyMetadata(false));
}

C#

public class MyAdvancedStateControl : MyStateControl


{
public MyAdvancedStateControl() : base() { }
static MyAdvancedStateControl()
{

MyStateControl.StateProperty.OverrideMetadata(typeof(MyAdvancedStateControl)
, new PropertyMetadata(true));
}
}

See also
DependencyProperty
Dependency Properties Overview
Custom Dependency Properties
How-to Topics
Events (WPF)
Article • 02/06/2023

Windows Presentation Foundation (WPF) introduces routed events that can invoke
handlers that exist on various listeners in the element tree of an application.

In This Section
Routed Events Overview
Attached Events Overview
Object Lifetime Events
Marking Routed Events as Handled, and Class Handling
Preview Events
Property Change Events
Visual Basic and WPF Event Handling
Weak Event Patterns
How-to Topics

Reference
RoutedEvent

EventManager

RoutingStrategy

Related Sections
WPF Architecture
XAML in WPF
Base Elements
Element Tree and Serialization
Properties
Input
Resources
Styling and Templating
WPF Content Model
Threading Model
Routed Events Overview
Article • 03/17/2022

This topic describes the concept of routed events in Windows Presentation Foundation
(WPF). The topic defines routed events terminology, describes how routed events are
routed through a tree of elements, summarizes how you handle routed events, and
introduces how to create your own custom routed events.

Prerequisites
This topic assumes that you have basic knowledge of the common language runtime
(CLR) and object-oriented programming, as well as the concept of how the relationships
between WPF elements can be conceptualized as a tree. In order to follow the examples
in this topic, you should also understand WPF applications or pages. For more
information, see Walkthrough: My first WPF desktop application and XAML in WPF.

What Is a Routed Event?


You can think about routed events either from a functional or implementation
perspective. Both definitions are presented here, because some people find one or the
other definition more useful.

Functional definition: A routed event is a type of event that can invoke handlers on
multiple listeners in an element tree, rather than just on the object that raised the event.

Implementation definition: A routed event is a CLR event that is backed by an instance


of the RoutedEvent class and is processed by the Windows Presentation Foundation
(WPF) event system.

A typical WPF application contains many elements. Whether created in code or declared
in XAML, these elements exist in an element tree relationship to each other. The event
route can travel in one of two directions depending on the event definition, but
generally the route travels from the source element and then "bubbles" upward through
the element tree until it reaches the element tree root (typically a page or a window).
This bubbling concept might be familiar to you if you have worked with the DHTML
object model previously.

Consider the following simple element tree:

XAML
<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
<StackPanel Background="LightGray" Orientation="Horizontal"
Button.Click="CommonClickHandler">
<Button Name="YesButton" Width="Auto" >Yes</Button>
<Button Name="NoButton" Width="Auto" >No</Button>
<Button Name="CancelButton" Width="Auto" >Cancel</Button>
</StackPanel>
</Border>

This element tree produces something like the following:

In this simplified element tree, the source of a Click event is one of the Button elements,
and whichever Button was clicked is the first element that has the opportunity to handle
the event. But if no handler attached to the Button acts on the event, then the event will
bubble upwards to the Button parent in the element tree, which is the StackPanel.
Potentially, the event bubbles to Border, and then beyond to the page root of the
element tree (not shown).

In other words, the event route for this Click event is:

Button-->StackPanel-->Border-->...

Top-level Scenarios for Routed Events


The following is a brief summary of the scenarios that motivated the routed event
concept, and why a typical CLR event was not adequate for these scenarios:

Control composition and encapsulation: Various controls in WPF have a rich content
model. For example, you can place an image inside of a Button, which effectively
extends the visual tree of the button. However, the added image must not break the hit-
testing behavior that causes a button to respond to a Click of its content, even if the
user clicks on pixels that are technically part of the image.

Singular handler attachment points: In Windows Forms, you would have to attach the
same handler multiple times to process events that could be raised from multiple
elements. Routed events enable you to attach that handler only once, as was shown in
the previous example, and use handler logic to determine where the event came from if
necessary. For instance, this might be the handler for the previously shown XAML:

C#
private void CommonClickHandler(object sender, RoutedEventArgs e)
{
FrameworkElement feSource = e.Source as FrameworkElement;
switch (feSource.Name)
{
case "YesButton":
// do something here ...
break;
case "NoButton":
// do something ...
break;
case "CancelButton":
// do something ...
break;
}
e.Handled=true;
}

Class handling: Routed events permit a static handler that is defined by the class. This
class handler has the opportunity to handle an event before any attached instance
handlers can.

Referencing an event without reflection: Certain code and markup techniques require a
way to identify a specific event. A routed event creates a RoutedEvent field as an
identifier, which provides a robust event identification technique that does not require
static or run-time reflection.

How Routed Events Are Implemented


A routed event is a CLR event that is backed by an instance of the RoutedEvent class and
registered with the WPF event system. The RoutedEvent instance obtained from
registration is typically retained as a public static readonly field member of the class
that registers and thus "owns" the routed event. The connection to the identically
named CLR event (which is sometimes termed the "wrapper" event) is accomplished by
overriding the add and remove implementations for the CLR event. Ordinarily, the add
and remove are left as an implicit default that uses the appropriate language-specific
event syntax for adding and removing handlers of that event. The routed event backing
and connection mechanism is conceptually similar to how a dependency property is a
CLR property that is backed by the DependencyProperty class and registered with the
WPF property system.

The following example shows the declaration for a custom Tap routed event, including
the registration and exposure of the RoutedEvent identifier field and the add and
remove implementations for the Tap CLR event.
C#

public static readonly RoutedEvent TapEvent =


EventManager.RegisterRoutedEvent(
"Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler),
typeof(MyButtonSimple));

// Provide CLR accessors for the event


public event RoutedEventHandler Tap
{
add { AddHandler(TapEvent, value); }
remove { RemoveHandler(TapEvent, value); }
}

Routed Event Handlers and XAML


To add a handler for an event using XAML, you declare the event name as an attribute
on the element that is an event listener. The value of the attribute is the name of your
implemented handler method, which must exist in the partial class of the code-behind
file.

XAML

<Button Click="b1SetColor">button</Button>

The XAML syntax for adding standard CLR event handlers is the same for adding routed
event handlers, because you are really adding handlers to the CLR event wrapper, which
has a routed event implementation underneath. For more information about adding
event handlers in XAML, see XAML in WPF.

Routing Strategies
Routed events use one of three routing strategies:

Bubbling: Event handlers on the event source are invoked. The routed event then
routes to successive parent elements until reaching the element tree root. Most
routed events use the bubbling routing strategy. Bubbling routed events are
generally used to report input or state changes from distinct controls or other UI
elements.

Direct: Only the source element itself is given the opportunity to invoke handlers
in response. This is analogous to the "routing" that Windows Forms uses for
events. However, unlike a standard CLR event, direct routed events support class
handling (class handling is explained in an upcoming section) and can be used by
EventSetter and EventTrigger.

Tunneling: Initially, event handlers at the element tree root are invoked. The routed
event then travels a route through successive child elements along the route,
towards the node element that is the routed event source (the element that raised
the routed event). Tunneling routed events are often used or handled as part of
the compositing for a control, such that events from composite parts can be
deliberately suppressed or replaced by events that are specific to the complete
control. Input events provided in WPF often come implemented as a
tunneling/bubbling pair. Tunneling events are also sometimes referred to as
Preview events, because of a naming convention that is used for the pairs.

Why Use Routed Events?


As an application developer, you do not always need to know or care that the event you
are handling is implemented as a routed event. Routed events have special behavior,
but that behavior is largely invisible if you are handling an event on the element where it
is raised.

Where routed events become powerful is if you use any of the suggested scenarios:
defining common handlers at a common root, compositing your own control, or
defining your own custom control class.

Routed event listeners and routed event sources do not need to share a common event
in their hierarchy. Any UIElement or ContentElement can be an event listener for any
routed event. Therefore, you can use the full set of routed events available throughout
the working API set as a conceptual "interface" whereby disparate elements in the
application can exchange event information. This "interface" concept for routed events
is particularly applicable for input events.

Routed events can also be used to communicate through the element tree, because the
event data for the event is perpetuated to each element in the route. One element could
change something in the event data, and that change would be available to the next
element in the route.

Other than the routing aspect, there are two other reasons that any given WPF event
might be implemented as a routed event instead of a standard CLR event. If you are
implementing your own events, you might also consider these principles:

Certain WPF styling and templating features such as EventSetter and EventTrigger
require the referenced event to be a routed event. This is the event identifier
scenario mentioned earlier.

Routed events support a class handling mechanism whereby the class can specify
static methods that have the opportunity to handle routed events before any
registered instance handlers can access them. This is very useful in control design,
because your class can enforce event-driven class behaviors that cannot be
accidentally suppressed by handling an event on an instance.

Each of the above considerations is discussed in a separate section of this topic.

Adding and Implementing an Event Handler for


a Routed Event
To add an event handler in XAML, you simply add the event name to an element as an
attribute and set the attribute value as the name of the event handler that implements
an appropriate delegate, as in the following example.

XAML

<Button Click="b1SetColor">button</Button>

b1SetColor is the name of the implemented handler that contains the code that handles
the Click event. b1SetColor must have the same signature as the RoutedEventHandler
delegate, which is the event handler delegate for the Click event. The first parameter of
all routed event handler delegates specifies the element to which the event handler is
added, and the second parameter specifies the data for the event.

C#

void b1SetColor(object sender, RoutedEventArgs args)


{
//logic to handle the Click event
}

RoutedEventHandler is the basic routed event handler delegate. For routed events that
are specialized for certain controls or scenarios, the delegates to use for the routed
event handlers also might become more specialized, so that they can transmit
specialized event data. For instance, in a common input scenario, you might handle a
DragEnter routed event. Your handler should implement the DragEventHandler
delegate. By using the most specific delegate, you can process the DragEventArgs in the
handler and read the Data property, which contains the clipboard payload of the drag
operation.
For a complete example of how to add an event handler to an element using XAML, see
Handle a Routed Event.

Adding a handler for a routed event in an application that is created in code is


straightforward. Routed event handlers can always be added through a helper method
AddHandler (which is the same method that the existing backing calls for add .)
However, existing WPF routed events generally have backing implementations of add
and remove logic that allow the handlers for routed events to be added by a language-
specific event syntax, which is more intuitive syntax than the helper method. The
following is an example usage of the helper method:

C#

void MakeButton()
{
Button b2 = new Button();
b2.AddHandler(Button.ClickEvent, new RoutedEventHandler(Onb2Click));
}
void Onb2Click(object sender, RoutedEventArgs e)
{
//logic to handle the Click event
}

The next example shows the C# operator syntax (Visual Basic has slightly different
operator syntax because of its handling of dereferencing):

C#

void MakeButton2()
{
Button b2 = new Button();
b2.Click += new RoutedEventHandler(Onb2Click2);
}
void Onb2Click2(object sender, RoutedEventArgs e)
{
//logic to handle the Click event
}

For an example of how to add an event handler in code, see Add an Event Handler
Using Code.

If you are using Visual Basic, you can also use the Handles keyword to add handlers as
part of the handler declarations. For more information, see Visual Basic and WPF Event
Handling.
The Concept of Handled
All routed events share a common event data base class, RoutedEventArgs.
RoutedEventArgs defines the Handled property, which takes a Boolean value. The
purpose of the Handled property is to enable any event handler along the route to mark
the routed event as handled, by setting the value of Handled to true . After being
processed by the handler at one element along the route, the shared event data is again
reported to each listener along the route.

The value of Handled affects how a routed event is reported or processed as it travels
further along the route. If Handled is true in the event data for a routed event, then
handlers that listen for that routed event on other elements are generally no longer
invoked for that particular event instance. This is true both for handlers attached in
XAML and for handlers added by language-specific event handler attachment syntaxes
such as += or Handles . For most common handler scenarios, marking an event as
handled by setting Handled to true will "stop" routing for either a tunneling route or a
bubbling route, and also for any event that is handled at a point in the route by a class
handler.

However, there is a "handledEventsToo" mechanism whereby listeners can still run


handlers in response to routed events where Handled is true in the event data. In other
words, the event route is not truly stopped by marking the event data as handled. You
can only use the handledEventsToo mechanism in code, or in an EventSetter:

In code, instead of using a language-specific event syntax that works for general
CLR events, call the WPF method AddHandler(RoutedEvent, Delegate, Boolean) to
add your handler. Specify the value of handledEventsToo as true .

In an EventSetter, set the HandledEventsToo attribute to be true .

In addition to the behavior that Handled state produces in routed events, the concept of
Handled has implications for how you should design your application and write the
event handler code. You can conceptualize Handled as being a simple protocol that is
exposed by routed events. Exactly how you use this protocol is up to you, but the
conceptual design for how the value of Handled is intended to be used is as follows:

If a routed event is marked as handled, then it does not need to be handled again
by other elements along that route.

If a routed event is not marked as handled, then other listeners that were earlier
along the route have chosen either not to register a handler, or the handlers that
were registered chose not to manipulate the event data and set Handled to true .
(Or, it is of course possible that the current listener is the first point in the route.)
Handlers on the current listener now have three possible courses of action:

Take no action at all; the event remains unhandled, and the event routes to the
next listener.

Execute code in response to the event, but make the determination that the
action taken was not substantial enough to warrant marking the event as
handled. The event routes to the next listener.

Execute code in response to the event. Mark the event as handled in the event
data passed to the handler, because the action taken was deemed substantial
enough to warrant marking as handled. The event still routes to the next
listener, but with Handled= true in its event data, so only handledEventsToo
listeners have the opportunity to invoke further handlers.

This conceptual design is reinforced by the routing behavior mentioned earlier: it is


more difficult (although still possible in code or styles) to attach handlers for routed
events that are invoked even if a previous handler along the route has already set
Handled to true .

For more information about Handled, class handling of routed events, and
recommendations about when it is appropriate to mark a routed event as Handled, see
Marking Routed Events as Handled, and Class Handling.

In applications, it is quite common to just handle a bubbling routed event on the object
that raised it, and not be concerned with the event's routing characteristics at all.
However, it is still a good practice to mark the routed event as handled in the event
data, to prevent unanticipated side effects just in case an element that is further up the
element tree also has a handler attached for that same routed event.

Class Handlers
If you are defining a class that derives in some way from DependencyObject, you can
also define and attach a class handler for a routed event that is a declared or inherited
event member of your class. Class handlers are invoked before any instance listener
handlers that are attached to an instance of that class, whenever a routed event reaches
an element instance in its route.

Some WPF controls have inherent class handling for certain routed events. This might
give the outward appearance that the routed event is not ever raised, but in reality it is
being class handled, and the routed event can potentially still be handled by your
instance handlers if you use certain techniques. Also, many base classes and controls
expose virtual methods that can be used to override class handling behavior. For more
information both on how to work around undesired class handling and on defining your
own class handling in a custom class, see Marking Routed Events as Handled, and Class
Handling.

Attached Events in WPF


The XAML language also defines a special type of event called an attached event. An
attached event enables you to add a handler for a particular event to an arbitrary
element. The element handling the event need not define or inherit the attached event,
and neither the object potentially raising the event nor the destination handling
instance must define or otherwise "own" that event as a class member.

The WPF input system uses attached events extensively. However, nearly all of these
attached events are forwarded through base elements. The input events then appear as
equivalent non-attached routed events that are members of the base element class. For
instance, the underlying attached event Mouse.MouseDown can more easily be handled
on any given UIElement by using MouseDown on that UIElement rather than dealing
with attached event syntax either in XAML or code.

For more information about attached events in WPF, see Attached Events Overview.

Qualified Event Names in XAML


Another syntax usage that resembles typename.eventname attached event syntax but is
not strictly speaking an attached event usage is when you attach handlers for routed
events that are raised by child elements. You attach the handlers to a common parent,
to take advantage of event routing, even though the common parent might not have
the relevant routed event as a member. Consider this example again:

XAML

<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">


<StackPanel Background="LightGray" Orientation="Horizontal"
Button.Click="CommonClickHandler">
<Button Name="YesButton" Width="Auto" >Yes</Button>
<Button Name="NoButton" Width="Auto" >No</Button>
<Button Name="CancelButton" Width="Auto" >Cancel</Button>
</StackPanel>
</Border>

Here, the parent element listener where the handler is added is a StackPanel. However, it
is adding a handler for a routed event that was declared and will be raised by the Button
class (ButtonBase actually, but available to Button through inheritance). Button "owns"
the event, but the routed event system permits handlers for any routed event to be
attached to any UIElement or ContentElement instance listener that could otherwise
attach listeners for a common language runtime (CLR) event. The default xmlns
namespace for these qualified event attribute names is typically the default WPF xmlns
namespace, but you can also specify prefixed namespaces for custom routed events. For
more information about xmlns, see XAML Namespaces and Namespace Mapping for
WPF XAML.

WPF Input Events


One frequent application of routed events within the WPF platform is for input events.
In WPF, tunneling routed events names are prefixed with the word "Preview" by
convention. Input events often come in pairs, with one being the bubbling event and
the other being the tunneling event. For example, the KeyDown event and the
PreviewKeyDown event have the same signature, with the former being the bubbling
input event and the latter being the tunneling input event. Occasionally, input events
only have a bubbling version, or perhaps only a direct routed version. In the
documentation, routed event topics cross-reference similar routed events with
alternative routing strategies if such routed events exist, and sections in the managed
reference pages clarify the routing strategy of each routed event.

WPF input events that come in pairs are implemented so that a single user action from
input, such as a mouse button press, will raise both routed events of the pair in
sequence. First, the tunneling event is raised and travels its route. Then the bubbling
event is raised and travels its route. The two events literally share the same event data
instance, because the RaiseEvent method call in the implementing class that raises the
bubbling event listens for the event data from the tunneling event and reuses it in the
new raised event. Listeners with handlers for the tunneling event have the first
opportunity to mark the routed event handled (class handlers first, then instance
handlers). If an element along the tunneling route marked the routed event as handled,
the already-handled event data is sent on for the bubbling event, and typical handlers
attached for the equivalent bubbling input events will not be invoked. To outward
appearances it will be as if the handled bubbling event has not even been raised. This
handling behavior is useful for control compositing, where you might want all hit-test
based input events or focus-based input events to be reported by your final control,
rather than its composite parts. The final control element is closer to the root in the
compositing, and therefore has the opportunity to class handle the tunneling event first
and perhaps to "replace" that routed event with a more control-specific event, as part of
the code that backs the control class.
As an illustration of how input event processing works, consider the following input
event example. In the following tree illustration, leaf element #2 is the source of both a
PreviewMouseDown and then a MouseDown event:

The order of event processing is as follows:

1. PreviewMouseDown (tunnel) on root element.

2. PreviewMouseDown (tunnel) on intermediate element #1.

3. PreviewMouseDown (tunnel) on source element #2.

4. MouseDown (bubble) on source element #2.

5. MouseDown (bubble) on intermediate element #1.

6. MouseDown (bubble) on root element.

A routed event handler delegate provides references to two objects: the object that
raised the event and the object where the handler was invoked. The object where the
handler was invoked is the object reported by the sender parameter. The object where
the event was first raised is reported by the Source property in the event data. A routed
event can still be raised and handled by the same object, in which case sender and
Source are identical (this is the case with Steps 3 and 4 in the event processing example
list).

Because of tunneling and bubbling, parent elements receive input events where the
Source is one of their child elements. When it is important to know what the source
element is, you can identify the source element by accessing the Source property.

Usually, once the input event is marked Handled, further handlers are not invoked.
Typically, you should mark input events as handled as soon as a handler is invoked that
addresses your application-specific logical handling of the meaning of the input event.

The exception to this general statement about Handled state is that input event
handlers that are registered to deliberately ignore Handled state of the event data
would still be invoked along either route. For more information, see Preview Events or
Marking Routed Events as Handled, and Class Handling.

The shared event data model between tunneling and bubbling events, and the
sequential raising of first tunneling then bubbling events, is not a concept that is
generally true for all routed events. That behavior is specifically implemented by how
WPF input devices choose to raise and connect the input event pairs. Implementing
your own input events is an advanced scenario, but you might choose to follow that
model for your own input events also.

Certain classes choose to class-handle certain input events, usually with the intent of
redefining what a particular user-driven input event means within that control and
raising a new event. For more information, see Marking Routed Events as Handled, and
Class Handling.

For more information on input and how input and events interact in typical application
scenarios, see Input Overview.

EventSetters and EventTriggers


In styles, you can include some pre-declared XAML event handling syntax in the markup
by using an EventSetter. When the style is applied, the referenced handler is added to
the styled instance. You can declare an EventSetter only for a routed event. The
following is an example. Note that the b1SetColor method referenced here is in a code-
behind file.

XAML

<StackPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.EventOvw2"
Name="dpanel2"
Initialized="PrimeHandledToo"
>
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<EventSetter Event="Click" Handler="b1SetColor"/>
</Style>
</StackPanel.Resources>
<Button>Click me</Button>
<Button Name="ThisButton" Click="HandleThis">
Raise event, handle it, use handled=true handler to get it anyway.
</Button>
</StackPanel>

The advantage gained here is that the style is likely to contain a great deal of other
information that could apply to any button in your application, and having the
EventSetter be part of that style promotes code reuse even at the markup level. Also, an
EventSetter abstracts method names for handlers one step further away from the
general application and page markup.

Another specialized syntax that combines the routed event and animation features of
WPF is an EventTrigger. As with EventSetter, only routed events may be used for an
EventTrigger. Typically, an EventTrigger is declared as part of a style, but an EventTrigger
can also be declared on page-level elements as part of the Triggers collection, or in a
ControlTemplate. An EventTrigger enables you to specify a Storyboard that runs
whenever a routed event reaches an element in its route that declares an EventTrigger
for that event. The advantage of an EventTrigger over just handling the event and
causing it to start an existing storyboard is that an EventTrigger provides better control
over the storyboard and its run-time behavior. For more information, see Use Event
Triggers to Control a Storyboard After It Starts.

More About Routed Events


This topic mainly discusses routed events from the perspective of describing the basic
concepts and offering guidance on how and when to respond to the routed events that
are already present in the various base elements and controls. However, you can create
your own routed event on your custom class along with all the necessary support, such
as specialized event data classes and delegates. The routed event owner can be any
class, but routed events must be raised by and handled by UIElement or
ContentElement derived classes in order to be useful. For more information about
custom events, see Create a Custom Routed Event.

See also
EventManager
RoutedEvent
RoutedEventArgs
Marking Routed Events as Handled, and Class Handling
Input Overview
Commanding Overview
Custom Dependency Properties
Trees in WPF
Weak Event Patterns
Attached Events Overview
Article • 02/06/2023

Extensible Application Markup Language (XAML) defines a language component and


type of event called an attached event. The concept of an attached event enables you to
add a handler for a particular event to an arbitrary element rather than to an element
that actually defines or inherits the event. In this case, neither the object potentially
raising the event nor the destination handling instance defines or otherwise "owns" the
event.

Prerequisites
This topic assumes that you have read Routed Events Overview and XAML in WPF.

Attached Event Syntax


Attached events have a XAML syntax and a coding pattern that must be used by the
backing code in order to support the attached event usage.

In XAML syntax, the attached event is specified not just by its event name, but by its
owning type plus the event name, separated by a dot (.). Because the event name is
qualified with the name of its owning type, the attached event syntax allows any
attached event to be attached to any element that can be instantiated.

For example, the following is the XAML syntax for attaching a handler for a custom
NeedsCleaning attached event:

XAML

<aqua:Aquarium Name="theAquarium" Height="600" Width="800"


aqua:AquariumFilter.NeedsCleaning="WashMe"/>

Note the aqua: prefix; the prefix is necessary in this case because the attached event is a
custom event that comes from a custom mapped xmlns.

How WPF Implements Attached Events


In WPF, attached events are backed by a RoutedEvent field and are routed through the
tree after they are raised. Typically, the source of the attached event (the object that
raises the event) is a system or service source, and the object that runs the code that
raises the event is therefore not a direct part of the element tree.

Scenarios for Attached Events


In WPF, attached events are present in certain feature areas where there is service-level
abstraction, such as for the events enabled by the static Mouse class or the Validation
class. Classes that interact with or use the service can either use the event in the
attached event syntax, or they can choose to surface the attached event as a routed
event that is part of how the class integrates the capabilities of the service.

Although WPF defines a number of attached events, the scenarios where you will either
use or handle the attached event directly are very limited. Generally, the attached event
serves an architecture purpose, but is then forwarded to a non-attached (backed with a
CLR event "wrapper") routed event.

For instance, the underlying attached event Mouse.MouseDown can more easily be
handled on any given UIElement by using MouseDown on that UIElement rather than
dealing with attached event syntax either in XAML or code. The attached event serves a
purpose in the architecture because it allows for future expansion of input devices. The
hypothetical device would only need to raise Mouse.MouseDown in order to simulate
mouse input, and would not need to derive from Mouse to do so. However, this
scenario involves code handling of the events, and XAML handling of the attached event
is not relevant to this scenario.

Handling an Attached Event in WPF


The process for handling an attached event, and the handler code that you will write, is
basically the same as for a routed event.

In general, a WPF attached event is not very different from a WPF routed event. The
differences are how the event is sourced and how it is exposed by a class as a member
(which also affects the XAML handler syntax).

However, as noted earlier, the existing WPF attached events are not particularly
intended for handling in WPF. More often, the purpose of the event is to enable a
composited element to report a state to a parent element in compositing, in which case
the event is usually raised in code and also relies on class handling in the relevant parent
class. For instance, items within a Selector are expected to raise the attached Selected
event, which is then class handled by the Selector class and then potentially converted
by the Selector class into a different routed event, SelectionChanged. For more
information on routed events and class handling, see Marking Routed Events as
Handled, and Class Handling.

Defining Your Own Attached Events as Routed


Events
If you are deriving from common WPF base classes, you can implement your own
attached events by including certain pattern methods in your class and by using utility
methods that are already present on the base classes.

The pattern is as follows:

A method AddEventNameHandler with two parameters. The first parameter is the


instance to which the event handler is added. The second parameter is the event
handler to add. The method must be public and static , with no return value.

A method RemoveEventNameHandler with two parameters. The first parameter is


the instance from which the event handler is removed. The second parameter is
the event handler to remove. The method must be public and static , with no
return value.

The AddEventNameHandler accessor method facilitates XAML processing when


attached event handler attributes are declared on an element. The
AddEventNameHandler and RemoveEventNameHandler methods also enable code
access to the event handler store for the attached event.

This general pattern is not yet precise enough for practical implementation in a
framework, because any given XAML reader implementation might have different
schemes for identifying underlying events in the supporting language and architecture.
This is one of the reasons that WPF implements attached events as routed events; the
identifier to use for an event (RoutedEvent) is already defined by the WPF event system.
Also, routing an event is a natural implementation extension on the XAML language-
level concept of an attached event.

The AddEventNameHandler implementation for a WPF attached event consists of


calling the AddHandler with the routed event and handler as arguments.

This implementation strategy and the routed event system in general restrict handling
for attached events to either UIElement derived classes or ContentElement derived
classes, because only those classes have AddHandler implementations.
For example, the following code defines the NeedsCleaning attached event on the owner
class Aquarium , using the WPF attached event strategy of declaring the attached event
as a routed event.

C#

public static readonly RoutedEvent NeedsCleaningEvent =


EventManager.RegisterRoutedEvent("NeedsCleaning", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(AquariumFilter));
public static void AddNeedsCleaningHandler(DependencyObject d,
RoutedEventHandler handler)
{
UIElement uie = d as UIElement;
if (uie != null)
{
uie.AddHandler(AquariumFilter.NeedsCleaningEvent, handler);
}
}
public static void RemoveNeedsCleaningHandler(DependencyObject d,
RoutedEventHandler handler)
{
UIElement uie = d as UIElement;
if (uie != null)
{
uie.RemoveHandler(AquariumFilter.NeedsCleaningEvent, handler);
}
}

Note that the method used to establish the attached event identifier field,
RegisterRoutedEvent, is actually the same method that is used to register a non-
attached routed event. Attached events and routed events all are registered to a
centralized internal store. This event store implementation enables the "events as an
interface" conceptual consideration that is discussed in Routed Events Overview.

Raising a WPF Attached Event


You do not typically need to raise existing WPF-defined attached events from your code.
These events follow the general "service" conceptual model, and service classes such as
InputManager are responsible for raising the events.

However, if you are defining a custom attached event based on the WPF model of
basing attached events on RoutedEvent, you can use RaiseEvent to raise an attached
event from any UIElement or ContentElement. Raising a routed event (attached or not)
requires that you declare a particular element in the element tree as the event source;
that source is reported as the RaiseEvent caller. Determining which element is reported
as the source in the tree is your service's responsibility
See also
Routed Events Overview
XAML Syntax In Detail
XAML and Custom Classes for WPF
Object Lifetime Events
Article • 02/06/2023

This topic describes the specific WPF events that signify stages in an object lifetime of
creation, use, and destruction.

Prerequisites
This topic assumes that you understand dependency properties from the perspective of
a consumer of existing dependency properties on WPF applications.

Object Lifetime Events


All objects in Microsoft .NET Framework managed code go through a similar set of
stages of life, creation, use, and destruction. Many objects also have a finalization stage
of life that occurs as part of the destruction phase. WPF objects, more specifically the
visual objects that WPF identifies as elements, also have a set of common stages of
object life. The WPF programming and application models expose these stages as a
series of events. There are four main types of objects in WPF with respect to lifetime
events; elements in general, window elements, navigation hosts, and application objects.
Windows and navigation hosts are also within the larger grouping of visual objects
(elements). This topic describes the lifetime events that are common to all elements and
then introduces the more specific ones that apply to application definitions, windows or
navigation hosts.

Common Lifetime Events for Elements


Any WPF framework-level element (those objects deriving from either
FrameworkElement or FrameworkContentElement) has three common lifetime events:
Initialized, Loaded, and Unloaded.

Initialized
Initialized is raised first, and roughly corresponds to the initialization of the object by the
call to its constructor. Because the event happens in response to initialization, you are
guaranteed that all properties of the object are set. (An exception is expression usages
such as dynamic resources or binding; these will be unevaluated expressions.) As a
consequence of the requirement that all properties are set, the sequence of Initialized
being raised by nested elements that are defined in markup appears to occur in order of
deepest elements in the element tree first, then parent elements toward the root. This
order is because the parent-child relationships and containment are properties, and
therefore the parent cannot report initialization until the child elements that fill the
property are also completely initialized.

When you are writing handlers in response to the Initialized event, you must consider
that there is no guarantee that all other elements in the element tree (either logical tree
or visual tree) around where the handler is attached have been created, particularly
parent elements. Member variables may be null, or data sources might not yet be
populated by the underlying binding (even at the expression level).

Loaded
Loaded is raised next. The Loaded event is raised before the final rendering, but after
the layout system has calculated all necessary values for rendering. Loaded entails that
the logical tree that an element is contained within is complete, and connects to a
presentation source that provides the HWND and the rendering surface. Standard data
binding (binding to local sources, such as other properties or directly defined data
sources) will have occurred prior to Loaded. Asynchronous data binding (external or
dynamic sources) might have occurred, but by definition of its asynchronous nature
cannot be guaranteed to have occurred.

The mechanism by which the Loaded event is raised is different than Initialized. The
Initialized event is raised element by element, without a direct coordination by a
completed element tree. By contrast, the Loaded event is raised as a coordinated effort
throughout the entire element tree (specifically, the logical tree). When all elements in
the tree are in a state where they are considered loaded, the Loaded event is first raised
on the root element. The Loaded event is then raised successively on each child
element.

7 Note

This behavior might superficially resemble tunneling for a routed event. However,
no information is carried from event to event. Each element always has the
opportunity to handle its Loaded event, and marking the event data as handled has
no effect beyond that element.

Unloaded
Unloaded is raised last and is initiated by either the presentation source or the visual
parent being removed. When Unloaded is raised and handled, the element that is the
event source parent (as determined by Parent property) or any given element upwards
in the logical or visual trees may have already been unset, meaning that data binding,
resource references, and styles may not be set to their normal or last known run-time
value.

Lifetime Events Application Model Elements


Building on the common lifetime events for elements are the following application
model elements: Application, Window, Page, NavigationWindow, and Frame. These
extend the common lifetime events with additional events that are relevant to their
specific purpose. These are discussed in detail in the following locations:

Application: Application Management Overview.

Window: WPF Windows Overview.

Page, NavigationWindow, and Frame: Navigation Overview.

See also
Dependency Property Value Precedence
Routed Events Overview
Marking Routed Events as Handled, and
Class Handling
Article • 02/06/2023

Handlers for a routed event can mark the event handled within the event data. Handling
the event will effectively shorten the route. Class handling is a programming concept
that is supported by routed events. A class handler has the opportunity to handle a
particular routed event at a class level with a handler that is invoked before any instance
handler on any instance of the class.

Prerequisites
This topic elaborates on concepts introduced in the Routed Events Overview.

When to Mark Events as Handled


When you set the value of the Handled property to true in the event data for a routed
event, this is referred to as "marking the event handled". There is no absolute rule for
when you should mark routed events as handled, either as an application author, or as a
control author who responds to existing routed events or implements new routed
events. For the most part, the concept of "handled" as carried in the routed event's
event data should be used as a limited protocol for your own application's responses to
the various routed events exposed in WPF APIs as well as for any custom routed events.
Another way to consider the "handled" issue is that you should generally mark a routed
event handled if your code responded to the routed event in a significant and relatively
complete way. Typically, there should not be more than one significant response that
requires separate handler implementations for any single routed event occurrence. If
more responses are needed, then the necessary code should be implemented through
application logic that is chained within a single handler rather than by using the routed
event system for forwarding. The concept of what is "significant" is also subjective, and
depends on your application or code. As general guidance, some "significant response"
examples include: setting focus, modifying public state, setting properties that affect the
visual representation, and raising other new events. Examples of nonsignificant
responses include: modifying private state (with no visual impact, or programmatic
representation), logging of events, or looking at arguments of an event and choosing
not to respond to it.
The routed event system behavior reinforces this "significant response" model for using
handled state of a routed event, because handlers added in XAML or the common
signature of AddHandler are not invoked in response to a routed event where the event
data is already marked handled. You must go through the extra effort of adding a
handler with the handledEventsToo parameter version (AddHandler(RoutedEvent,
Delegate, Boolean)) in order to handle routed events that are marked handled by earlier
participants in the event route.

In some circumstances, controls themselves mark certain routed events as handled. A


handled routed event represents a decision by WPF control authors that the control's
actions in response to the routed event are significant or complete as part of the control
implementation, and the event needs no further handling. Usually this is done by adding
a class handler for an event, or by overriding one of the class handler virtuals that exist
on a base class. You can still work around this event handling if necessary; see Working
Around Event Suppression by Controls later in this topic.

"Preview" (Tunneling) Events vs. Bubbling


Events, and Event Handling
Preview routed events are events that follow a tunneling route through the element
tree. The "Preview" expressed in the naming convention is indicative of the general
principle for input events that preview (tunneling) routed events are raised prior to the
equivalent bubbling routed event. Also, input routed events that have a tunneling and
bubbling pair have a distinct handling logic. If the tunneling/preview routed event is
marked as handled by an event listener, then the bubbling routed event will be marked
handled even before any listeners of the bubbling routed event receive it. The tunneling
and bubbling routed events are technically separate events, but they deliberately share
the same instance of event data to enable this behavior.

The connection between the tunneling and bubbling routed events is accomplished by
the internal implementation of how any given WPF class raises its own declared routed
events, and this is true of the paired input routed events. But unless this class-level
implementation exists, there is no connection between a tunneling routed event and a
bubbling routed event that share the naming scheme: without such implementation
they would be two entirely separate routed events and would not be raised in sequence
or share event data.

For more information about how to implement tunnel/bubble input routed event pairs
in a custom class, see Create a Custom Routed Event.
Class Handlers and Instance Handlers
Routed events consider two different types of listeners to the event: class listeners and
instance listeners. Class listeners exist because types have called a particular
EventManager API ,RegisterClassHandler, in their static constructor, or have overridden a
class handler virtual method from an element base class. Instance listeners are particular
class instances/elements where one or more handlers have been attached for that
routed event by a call to AddHandler. Existing WPF routed events make calls to
AddHandler as part of the common language runtime (CLR) event wrapper add{} and
remove{} implementations of the event, which is also how the simple XAML mechanism
of attaching event handlers via an attribute syntax is enabled. Therefore even the simple
XAML usage ultimately equates to an AddHandler call.

Elements within the visual tree are checked for registered handler implementations.
Handlers are potentially invoked throughout the route, in the order that is inherent in
the type of the routing strategy for that routed event. For instance, bubbling routed
events will first invoke those handlers that are attached to the same element that raised
the routed event. Then the routed event "bubbles" to the next parent element and so on
until the application root element is reached.

From the perspective of the root element in a bubbling route, if class handling or any
element closer to the source of the routed event invoke handlers that mark the event
arguments as being handled, then handlers on the root elements are not invoked, and
the event route is effectively shortened before reaching that root element. However, the
route is not completely halted, because handlers can be added using a special
conditional that they should still be invoked, even if a class handler or instance handler
has marked the routed event as handled. This is explained in Adding Instance Handlers
That Are Raised Even When Events Are Marked Handled, later in this topic.

At a deeper level than the event route, there are also potentially multiple class handlers
acting on any given instance of a class. This is because the class handling model for
routed events enables all possible classes in a class hierarchy to each register its own
class handler for each routed event. Each class handler is added to an internal store, and
when the event route for an application is constructed, the class handlers are all added
to the event route. Class handlers are added to the route such that the most-derived
class handler is invoked first, and class handlers from each successive base class are
invoked next. Generally, class handlers are not registered such that they also respond to
routed events that were already marked handled. Therefore, this class handling
mechanism enables one of two choices:

Derived classes can supplement the class handling that is inherited from the base
class by adding a handler that does not mark the routed event handled, because
the base class handler will be invoked sometime after the derived class handler.

Derived classes can replace the class handling from the base class by adding a
class handler that marks the routed event handled. You should be cautious with
this approach, because it will potentially change the intended base control design
in areas such as visual appearance, state logic, input handling, and command
handling.

Class Handling of Routed Events by Control


Base Classes
On each given element node in an event route, class listeners have the opportunity to
respond to the routed event before any instance listener on the element can. For this
reason, class handlers are sometimes used to suppress routed events that a particular
control class implementation does not wish to propagate further, or to provide special
handling of that routed event that is a feature of the class. For instance, a class might
raise its own class-specific event that contains more specifics about what some user
input condition means in the context of that particular class. The class implementation
might then mark the more general routed event as handled. Class handlers are typically
added such that they are not invoked for routed events where shared event data was
already marked handled, but for atypical cases there is also a RegisterClassHandler(Type,
RoutedEvent, Delegate, Boolean) signature that registers class handlers to invoke even
when routed events are marked handled.

Class Handler Virtuals


Some elements, particularly the base elements such as UIElement, expose empty
"On*Event" and "OnPreview*Event" virtual methods that correspond to their list of
public routed events. These virtual methods can be overridden to implement a class
handler for that routed event. The base element classes register these virtual methods as
their class handler for each such routed event using RegisterClassHandler(Type,
RoutedEvent, Delegate, Boolean) as described earlier. The On*Event virtual methods
make it much simpler to implement class handling for the relevant routed events,
without requiring special initialization in static constructors for each type. For instance,
you can add class handling for the DragEnter event in any UIElement derived class by
overriding the OnDragEnter virtual method. Within the override, you could handle the
routed event, raise other events, initiate class-specific logic that might change element
properties on instances, or any combination of those actions. You should generally call
the base implementation in such overrides even if you mark the event handled. Calling
the base implementation is strongly recommended because the virtual method is on the
base class. The standard protected virtual pattern of calling the base implementations
from each virtual essentially replaces and parallels a similar mechanism that is native to
routed event class handling, whereby class handlers for all classes in a class hierarchy are
called on any given instance, starting with the most-derived class' handler and
continuing to the base class handler. You should only omit the base implementation call
if your class has a deliberate requirement to change the base class handling logic.
Whether you call the base implementation before or after your overriding code will
depend on the nature of your implementation.

Input Event Class Handling


The class handler virtual methods are all registered such that they are only invoked in
cases where any shared event data are not already marked handled. Also, for the input
events uniquely, the tunneling and bubbling versions typically are raised in sequence
and share event data. This entails that for a given pair of class handlers of input events
where one is the tunneling version and the other is the bubbling version, you may not
want to mark the event handled immediately. If you implement the tunneling class
handling virtual method to mark the event handled, that will prevent the bubbling class
handler from being invoked (as well as preventing any normally registered instance
handlers for either the tunneling or bubbling event from being invoked).

Once class handling on a node is complete, the instance listeners are considered.

Adding Instance Handlers That Are Raised Even


When Events Are Marked Handled
The AddHandler method supplies a particular overload that allows you to add handlers
that will be invoked by the event system whenever an event reaches the handling
element in the route, even if some other handler has already adjusted the event data to
mark that event as handled. This is not typically done. Generally, handlers can be written
to adjust all areas of application code that might be influenced by an event, regardless
of where it was handled in an element tree, even if multiple end results are desired. Also,
typically there is really only one element that needs to respond to that event, and the
appropriate application logic had already happened. But the handledEventsToo overload
is available for the exceptional cases where some other element in an element tree or
control compositing has already marked an event as handled, but other elements either
higher or lower in the element tree (depending on route) still wish to have their own
handlers invoked.
When to Mark Handled Events as Unhandled
Generally, routed events that are marked handled should not be marked unhandled
(Handled set back to false ) even by handlers that act on handledEventsToo . However,
some input events have high-level and lower-level event representations that can
overlap when the high-level event is seen at one position in the tree and the low-level
event at another position. For instance, consider the case where a child element listens
to a high-level key event such as TextInput while a parent element listens to a low-level
event such as KeyDown. If the parent element handles the low-level event, the higher-
level event can be suppressed even in the child element that intuitively should have first
opportunity to handle the event.

In these situations it may be necessary to add handlers to both parent elements and
child elements for the low-level event. The child element handler implementation can
mark the low-level event as handled, but the parent element handler implementation
would set it unhandled again so that further elements up the tree (as well as the high-
level event) can have the opportunity to respond. This situation is should be fairly rare.

Deliberately Suppressing Input Events for


Control Compositing
The main scenario where class handling of routed events is used is for input events and
composited controls. A composited control is by definition composed of multiple
practical controls or control base classes. Often the author of the control wishes to
amalgamate all of the possible input events that each of the subcomponents might
raise, in order to report the entire control as the singular event source. In some cases the
control author might wish to suppress the events from components entirely, or
substitute a component-defined event that carries more information or implies a more
specific behavior. The canonical example that is immediately visible to any component
author is how a Windows Presentation Foundation (WPF) Button handles any mouse
event that will eventually resolve to the intuitive event that all buttons have: a Click
event.

The Button base class (ButtonBase) derives from Control which in turn derives from
FrameworkElement and UIElement, and much of the event infrastructure needed for
control input processing is available at the UIElement level. In particular, UIElement
processes general Mouse events that handle hit testing for the mouse cursor within its
bounds, and provides distinct events for the most common button actions, such as
MouseLeftButtonDown. UIElement also provides an empty virtual
OnMouseLeftButtonDown as the preregistered class handler for MouseLeftButtonDown,
and ButtonBase overrides it. Similarly, ButtonBase uses class handlers for
MouseLeftButtonUp. In the overrides, which are passed the event data, the
implementations mark that RoutedEventArgs instance as handled by setting Handled to
true , and that same event data is what continues along the remainder of the route to

other class handlers and also to instance handlers or event setters. Also, the
OnMouseLeftButtonUp override will next raise the Click event. The end result for most
listeners will be that the MouseLeftButtonDown and MouseLeftButtonUp events
"disappear" and are replaced instead by Click, an event that holds more meaning
because it is known that this event originated from a true button and not some
composite piece of the button or from some other element entirely.

Working Around Event Suppression by Controls


Sometimes this event suppression behavior within individual controls can interfere with
some more general intentions of event handling logic for your application. For instance,
if for some reason your application had a handler for MouseLeftButtonDown located at
the application root element, you would notice that any mouse click on a button would
not invoke MouseLeftButtonDown or MouseLeftButtonUp handlers at the root level. The
event itself actually did bubble up (again, event routes are not truly ended, but the
routed event system changes their handler invocation behavior after being marked
handled). When the routed event reached the button, the ButtonBase class handling
marked the MouseLeftButtonDown handled because it wished to substitute the Click
event with more meaning. Therefore, any standard MouseLeftButtonDown handler
further up the route would not be invoked. There are two techniques you can use to
ensure that your handlers would be invoked in this circumstance.

The first technique is to deliberately add the handler using the handledEventsToo
signature of AddHandler(RoutedEvent, Delegate, Boolean). A limitation of this approach
is that this technique for attaching an event handler is only possible from code, not from
markup. The simple syntax of specifying the event handler name as an event attribute
value via Extensible Application Markup Language (XAML) does not enable that
behavior.

The second technique works only for input events, where the tunneling and bubbling
versions of the routed event are paired. For these routed events, you can add handlers
to the preview/tunneling equivalent routed event instead. That routed event will tunnel
through the route starting from the root, so the button class handling code would not
intercept it, presuming that you attached the Preview handler at some ancestor element
level in the application's element tree. If you use this approach, be cautious about
marking any Preview event handled. For the example given with
PreviewMouseLeftButtonDown being handled at the root element, if you marked the
event as Handled in the handler implementation, you would actually suppress the Click
event. That is typically not desirable behavior.

See also
EventManager
Preview Events
Create a Custom Routed Event
Routed Events Overview
Preview Events
Article • 02/06/2023

Preview events, also known as tunneling events, are routed events where the direction
of the route travels from the application root towards the element that raised the event
and is reported as the source in event data. Not all event scenarios support or require
preview events; this topic describes the situations where preview events exist, how
applications or components should handle them, and cases where creating preview
events in custom components or classes might be appropriate.

Preview Events and Input


When you handle Preview events in general, be cautious about marking the events
handled in the event data. Handling a Preview event on any element other than the
element that raised it (the element that is reported as the source in the event data) has
the effect of not providing an element the opportunity to handle the event that it
originated. Sometimes this is the desired result, particularly if the elements in question
exist in relationships within the compositing of a control.

For input events specifically, Preview events also share event data instances with the
equivalent bubbling event. If you use a Preview event class handler to mark the input
event handled, the bubbling input event class handler will not be invoked. Or, if you use
a Preview event instance handler to mark the event handled, handlers for the bubbling
event will not typically be invoked. Class handlers or instance handlers can be registered
or attached with an option to be invoked even if the event is marked handled, but that
technique is not commonly used.

For more information about class handling and how it relates to Preview events see
Marking Routed Events as Handled, and Class Handling.

Working Around Event Suppression by Controls


One scenario where Preview events are commonly used is for composited control
handling of input events. Sometimes, the author of the control suppresses a certain
event from originating from their control, perhaps in order to substitute a component-
defined event that carries more information or implies a more specific behavior. For
instance, a Windows Presentation Foundation (WPF) Button suppresses
MouseLeftButtonDown and MouseRightButtonDown bubbling events raised by the
Button or its composite elements in favor of capturing the mouse and raising a Click
event that is always raised by the Button itself. The event and its data still continue
along the route, but because the Button marks the event data as Handled, only handlers
for the event that specifically indicated they should act in the handledEventsToo case are
invoked. If other elements towards the root of your application still wanted an
opportunity to handle a control-suppressed event, one alternative is to attach handlers
in code with handledEventsToo specified as true . But often a simpler technique is to
change the routing direction you handle to be the Preview equivalent of an input event.
For instance, if a control suppresses MouseLeftButtonDown, try attaching a handler for
PreviewMouseLeftButtonDown instead. This technique only works for base element
input events such as MouseLeftButtonDown. These input events use tunnel/bubble
pairs, raise both events, and share the event data.

Each of these techniques has either side effects or limitations. The side effect of
handling the Preview event is that handling the event at that point might disable
handlers that expect to handle the bubbling event, and therefore the limitation is that it
is usually not a good idea to mark the event handled while it is still on the Preview part
of the route. The limitation of the handledEventsToo technique is that you cannot specify
a handledEventsToo handler in XAML as an attribute, you must register the event
handler in code after obtaining an object reference to the element where the handler is
to be attached.

See also
Marking Routed Events as Handled, and Class Handling
Routed Events Overview
Property Change Events
Article • 02/06/2023

Windows Presentation Foundation (WPF) defines several events that are raised in
response to a change in the value of a property. Often the property is a dependency
property. The event itself is sometimes a routed event and is sometimes a standard
common language runtime (CLR) event. The definition of the event varies depending on
the scenario, because some property changes are more appropriately routed through an
element tree, whereas other property changes are generally only of concern to the
object where the property changed.

Identifying a Property Change Event


Not all events that report a property change are explicitly identified as a property
changed event, either by virtue of a signature pattern or a naming pattern. Generally,
the description of the event in the SDK documentation indicates whether the event is
directly tied to a property value change and provides cross-references between the
property and event.

RoutedPropertyChanged Events
Certain events use an event data type and delegate that are explicitly used for property
change events. The event data type is RoutedPropertyChangedEventArgs<T>, and the
delegate is RoutedPropertyChangedEventHandler<T>. The event data and delegate
both have a generic type parameter that is used to specify the actual type of the
changing property when you define the handler. The event data contains two properties,
OldValue and NewValue, which are both then passed as the type argument in the event
data.

The "Routed" part of the name indicates that the property changed event is registered
as a routed event. The advantage of routing a property changed event is that the top
level of a control can receive property changed events if properties on the child
elements (the control's composite parts) change values. For instance, you might create a
control that incorporates a RangeBase control such as a Slider. If the value of the Value
property changes on the slider part, you might want to handle that change on the
parent control rather than on the part.

Because you have an old value and a new value, it might be tempting to use this event
handler as a validator for the property value. However, that is not the design intention of
most property changed events. Generally, the values are provided so that you can act on
those values in other logic areas of your code, but actually changing the values from
within the event handler is not advisable, and may cause unintentional recursion
depending on how your handler is implemented.

If your property is a custom dependency property, or if you are working with a derived
class where you have defined the instantiation code, there is a much better mechanism
for tracking property changes that is built in to the WPF property system: the property
system callbacks CoerceValueCallback and PropertyChangedCallback. For more details
about how you can use the WPF property system for validation and coercion, see
Dependency Property Callbacks and Validation and Custom Dependency Properties.

DependencyPropertyChanged Events
Another pair of types that are part of a property changed event scenario is
DependencyPropertyChangedEventArgs and
DependencyPropertyChangedEventHandler. Events for these property changes are not
routed; they are standard CLR events. DependencyPropertyChangedEventArgs is an
unusual event data reporting type because it does not derive from EventArgs;
DependencyPropertyChangedEventArgs is a structure, not a class.

Events that use DependencyPropertyChangedEventArgs and


DependencyPropertyChangedEventHandler are slightly more common than
RoutedPropertyChanged events. An example of an event that uses these types is

IsMouseCapturedChanged.

Like RoutedPropertyChangedEventArgs<T>, DependencyPropertyChangedEventArgs


also reports an old and new value for the property. Also, the same considerations about
what you can do with the values apply; it is generally not recommended that you
attempt to change the values again on the sender in response to the event.

Property Triggers
A closely related concept to a property changed event is a property trigger. A property
trigger is created within a style or template and enables you to create a conditional
behavior based on the value of the property where the property trigger is assigned.

The property for a property trigger must be a dependency property. It can be (and
frequently is) a read-only dependency property. A good indicator for when a
dependency property exposed by a control is at least partially designed to be a property
trigger is if the property name begins with "Is". Properties that have this naming are
often a read-only Boolean dependency property where the primary scenario for the
property is reporting control state that might have consequences to the real-time UI
and is thus a property trigger candidate.

Some of these properties also have a dedicated property changed event. For instance,
the property IsMouseCaptured has a property changed event
IsMouseCapturedChanged. The property itself is read-only, with its value adjusted by
the input system, and the input system raises IsMouseCapturedChanged on each real-
time change.

Compared to a true property changed event, using a property trigger to act on a


property change has some limitations.

Property triggers work through an exact match logic. You specify a property and a value
that indicates the specific value for which the trigger will act. For instance: <Setter
Property="IsMouseCaptured" Value="true"> ... </Setter> . Because of this limitation, the
majority of property trigger usages will be for Boolean properties, or properties that
take a dedicated enumeration value, where the possible value range is manageable
enough to define a trigger for each case. Or property triggers might exist only for
special values, such as when an items count reaches zero, and there would be no trigger
that accounts for the cases when the property value changes away from zero again
(instead of triggers for all cases, you might need a code event handler here, or a default
behavior that toggles back from the trigger state again when the value is nonzero).

The property trigger syntax is analogous to an "if" statement in programming. If the


trigger condition is true, then the "body" of the property trigger is "executed". The
"body" of a property trigger is not code, it is markup. That markup is limited to using
one or more Setter elements to set other properties of the object where the style or
template is being applied.

To offset the "if" condition of a property trigger that has a wide variety of possible
values, it is generally advisable to set that same property value to a default by using a
Setter. This way, the Trigger contained setter will have precedence when the trigger
condition is true, and the Setter that is not within a Trigger will have precedence
whenever the trigger condition is false.

Property triggers are generally appropriate for scenarios where one or more appearance
properties should change, based on the state of another property on the same element.

To learn more about property triggers, see Styling and Templating.

See also
Routed Events Overview
Dependency Properties Overview
Visual Basic and WPF Event Handling
Article • 02/06/2023

For the Microsoft Visual Basic .NET language specifically, you can use the language-
specific Handles keyword to associate event handlers with instances, instead of
attaching event handlers with attributes or using the AddHandler method. However, the
Handles technique for attaching handlers to instances does have some limitations,

because the Handles syntax cannot support some of the specific routed event features
of the WPF event system.

Using "Handles" in a WPF Application


The event handlers that are connected to instances and events with Handles must all be
defined within the partial class declaration of the instance, which is also a requirement
for event handlers that are assigned through attribute values on elements. You can only
specify Handles for an element on the page that has a Name property value (or x:Name
Directive declared). This is because the Name in XAML creates the instance reference
that is necessary to support the Instance.Event reference format required by the Handles
syntax. The only element that can be used for Handles without a Name reference is the
root-element instance that defines the partial class.

You can assign the same handler to multiple elements by separating Instance.Event
references after Handles with commas.

You can use Handles to assign more than one handler to the same
Instance.Eventreference. Do not assign any importance to the order in which handlers
are given in the Handles reference; you should assume that handlers that handle the
same event can be invoked in any order.

To remove a handler that was added with Handles in the declaration, you can call
RemoveHandler.

You can use Handles to attach handlers for routed events, so long as you attach
handlers to instances that define the event being handled in their members tables. For
routed events, handlers that are attached with Handles follow the same routing rules as
do handlers that are attached as XAML attributes, or with the common signature of
AddHandler. This means that if the event is already marked handled (the Handled
property in the event data is True ), then handlers attached with Handles are not
invoked in response to that event instance. The event could be marked handled by
instance handlers on another element in the route, or by class handling either on the
current element or earlier elements along the route. For input events that support
paired tunnel/bubble events, the tunneling route may have marked the event pair
handled. For more information about routed events, see Routed Events Overview.

Limitations of "Handles" for Adding Handlers


Handles cannot reference handlers for attached events. You must use the add accessor

method for that attached event, or typename.eventname event attributes in XAML. For
details, see Routed Events Overview.

For routed events, you can only use Handles to assign handlers for instances where that
event exists in the instance members table. However, with routed events in general, a
parent element can be a listener for an event from child elements, even if the parent
element does not have that event in its members table. In attribute syntax, you can
specify this through a typename.membername attribute form that qualifies which type
actually defines the event you want to handle. For instance, a parent Page (with no
Click event defined) can listen for button-click events by assigning an attribute handler
in the form Button.Click . But Handles does not support the typename.membername
form, because it must support a conflicting Instance.Event form. For details, see Routed
Events Overview.

Handles cannot attach handlers that are invoked for events that are already marked

handled. Instead, you must use code and call the handledEventsToo overload of
AddHandler(RoutedEvent, Delegate, Boolean).

7 Note

Do not use the Handles syntax in Visual Basic code when you specify an event
handler for the same event in XAML. In this case, the event handler is called twice.

How WPF Implements "Handles" Functionality


When a Extensible Application Markup Language (XAML) page is compiled, the
intermediate file declares Friend WithEvents references to every element on the page
that has a Name property set (or x:Name Directive declared). Each named instance is
potentially an element that can be assigned to a handler through Handles .

7 Note
Within Visual Studio, IntelliSense can show you completion for which elements are
available for a Handles reference in a page. However, this might take one compile
pass so that the intermediate file can populate all the Friends references.

See also
AddHandler
Marking Routed Events as Handled, and Class Handling
Routed Events Overview
XAML in WPF
Weak Event Patterns
Article • 02/06/2023

In applications, it is possible that handlers that are attached to event sources will not be
destroyed in coordination with the listener object that attached the handler to the
source. This situation can lead to memory leaks. Windows Presentation Foundation
(WPF) introduces a design pattern that can be used to address this issue, by providing a
dedicated manager class for particular events and implementing an interface on
listeners for that event. This design pattern is known as the weak event pattern.

Why Implement the Weak Event Pattern?


Listening for events can lead to memory leaks. The typical technique for listening to an
event is to use the language-specific syntax that attaches a handler to an event on a
source. For example, in C#, that syntax is: source.SomeEvent += new
SomeEventHandler(MyEventHandler) .

This technique creates a strong reference from the event source to the event listener.
Ordinarily, attaching an event handler for a listener causes the listener to have an object
lifetime that is influenced by the object lifetime of the source (unless the event handler
is explicitly removed). But in certain circumstances, you might want the object lifetime of
the listener to be controlled by other factors, such as whether it currently belongs to the
visual tree of the application, and not by the lifetime of the source. Whenever the source
object lifetime extends beyond the object lifetime of the listener, the normal event
pattern leads to a memory leak: the listener is kept alive longer than intended.

The weak event pattern is designed to solve this memory leak problem. The weak event
pattern can be used whenever a listener needs to register for an event, but the listener
does not explicitly know when to unregister. The weak event pattern can also be used
whenever the object lifetime of the source exceeds the useful object lifetime of the
listener. (In this case, useful is determined by you.) The weak event pattern allows the
listener to register for and receive the event without affecting the object lifetime
characteristics of the listener in any way. In effect, the implied reference from the source
does not determine whether the listener is eligible for garbage collection. The reference
is a weak reference, thus the naming of the weak event pattern and the related APIs. The
listener can be garbage collected or otherwise destroyed, and the source can continue
without retaining noncollectible handler references to a now destroyed object.
Who Should Implement the Weak Event
Pattern?
Implementing the weak event pattern is interesting primarily for control authors. As a
control author, you are largely responsible for the behavior and containment of your
control and the impact it has on applications in which it is inserted. This includes the
control object lifetime behavior, in particular the handling of the described memory leak
problem.

Certain scenarios inherently lend themselves to the application of the weak event
pattern. One such scenario is data binding. In data binding, it is common for the source
object to be completely independent of the listener object, which is a target of a
binding. Many aspects of WPF data binding already have the weak event pattern applied
in how the events are implemented.

How to Implement the Weak Event Pattern


There are three ways to implement weak event pattern. The following table lists the
three approaches and provides some guidance for when you should use each.

Approach When to Implement

Use an If the event you want to subscribe to has a corresponding WeakEventManager, use
existing the existing weak event manager. For a list of weak event managers that are included
weak with WPF, see the inheritance hierarchy in the WeakEventManager class. Because the
event included weak event managers are limited, you will probably need to choose one of
manager the other approaches.
class

Use a Use a generic WeakEventManager<TEventSource,TEventArgs> when an existing


generic WeakEventManager is not available, you want an easy way to implement, and you
weak are not concerned about efficiency. The generic
event WeakEventManager<TEventSource,TEventArgs> is less efficient than an existing or
manager custom weak event manager. For example, the generic class does more reflection to
class discover the event given the event's name. Also, the code to register the event by
using the generic WeakEventManager<TEventSource,TEventArgs> is more verbose
than using an existing or custom WeakEventManager.

Create a Create a custom WeakEventManager when an existing WeakEventManager is not


custom available and you want the best efficiency. Using a custom WeakEventManager to
weak subscribe to an event will be more efficient, but you do incur the cost of writing
event more code at the beginning.
manager
class
Approach When to Implement

Use a NuGet has several weak event managers and many WPF frameworks also support
third- the pattern (for instance, see Prism's documentation on loosely coupled event
party subscription ).
weak
event
manager

The following sections describe how to implement the weak event pattern. For purposes
of this discussion, the event to subscribe to has the following characteristics.

The event name is SomeEvent .

The event is raised by the EventSource class.

The event handler has type: SomeEventEventHandler (or


EventHandler<SomeEventEventArgs> ).

The event passes a parameter of type SomeEventEventArgs to the event handlers.

Using an Existing Weak Event Manager Class


1. Find an existing weak event manager.

For a list of weak event managers that are included with WPF, see the inheritance
hierarchy in the WeakEventManager class.

2. Use the new weak event manager instead of the normal event hookup.

For example, if your code uses the following pattern to subscribe to an event:

C#

source.SomeEvent += new SomeEventEventHandler(OnSomeEvent);

Change it to the following pattern:

C#

SomeEventWeakEventManager.AddHandler(source, OnSomeEvent);

Similarly, if your code uses the following pattern to unsubscribe from an event:

C#
source.SomeEvent -= new SomeEventEventHandler(OnSomeEvent);

Change it to the following pattern:

C#

SomeEventWeakEventManager.RemoveHandler(source, OnSomeEvent);

Using the Generic Weak Event Manager Class


1. Use the generic WeakEventManager<TEventSource,TEventArgs> class instead of
the normal event hookup.

When you use WeakEventManager<TEventSource,TEventArgs> to register event


listeners, you supply the event source and EventArgs type as the type parameters
to the class and call AddHandler as shown in the following code:

C#

WeakEventManager<EventSource, SomeEventEventArgs>.AddHandler(source,
"SomeEvent", source_SomeEvent);

Creating a Custom Weak Event Manager Class


1. Copy the following class template to your project.

This class inherits from the WeakEventManager class.

C#

class SomeEventWeakEventManager : WeakEventManager


{

private SomeEventWeakEventManager()
{
}

/// <summary>
/// Add a handler for the given source's event.
/// </summary>
public static void AddHandler(EventSource source,
EventHandler<SomeEventEventArgs>
handler)
{
if (source == null)
throw new ArgumentNullException("source");
if (handler == null)
throw new ArgumentNullException("handler");

CurrentManager.ProtectedAddHandler(source, handler);
}

/// <summary>
/// Remove a handler for the given source's event.
/// </summary>
public static void RemoveHandler(EventSource source,
EventHandler<SomeEventEventArgs>
handler)
{
if (source == null)
throw new ArgumentNullException("source");
if (handler == null)
throw new ArgumentNullException("handler");

CurrentManager.ProtectedRemoveHandler(source, handler);
}

/// <summary>
/// Get the event manager for the current thread.
/// </summary>
private static SomeEventWeakEventManager CurrentManager
{
get
{
Type managerType = typeof(SomeEventWeakEventManager);
SomeEventWeakEventManager manager =

(SomeEventWeakEventManager)GetCurrentManager(managerType);

// at first use, create and register a new manager


if (manager == null)
{
manager = new SomeEventWeakEventManager();
SetCurrentManager(managerType, manager);
}

return manager;
}
}

/// <summary>
/// Return a new list to hold listeners to the event.
/// </summary>
protected override ListenerList NewListenerList()
{
return new ListenerList<SomeEventEventArgs>();
}

/// <summary>
/// Listen to the given source for the event.
/// </summary>
protected override void StartListening(object source)
{
EventSource typedSource = (EventSource)source;
typedSource.SomeEvent += new EventHandler<SomeEventEventArgs>
(OnSomeEvent);
}

/// <summary>
/// Stop listening to the given source for the event.
/// </summary>
protected override void StopListening(object source)
{
EventSource typedSource = (EventSource)source;
typedSource.SomeEvent -= new EventHandler<SomeEventEventArgs>
(OnSomeEvent);
}

/// <summary>
/// Event handler for the SomeEvent event.
/// </summary>
void OnSomeEvent(object sender, SomeEventEventArgs e)
{
DeliverEvent(sender, e);
}
}

2. Replace the SomeEventWeakEventManager name with your own name.

3. Replace the three names described previously with the corresponding names for
your event. ( SomeEvent , EventSource , and SomeEventEventArgs )

4. Set the visibility (public / internal / private) of the weak event manager class to the
same visibility as event it manages.

5. Use the new weak event manager instead of the normal event hookup.

For example, if your code uses the following pattern to subscribe to an event:

C#

source.SomeEvent += new SomeEventEventHandler(OnSomeEvent);

Change it to the following pattern:

C#

SomeEventWeakEventManager.AddHandler(source, OnSomeEvent);

Similarly, if your code uses the following pattern to unsubscribe to an event:


C#

source.SomeEvent -= new SomeEventEventHandler(OnSome);

Change it to the following pattern:

C#

SomeEventWeakEventManager.RemoveHandler(source, OnSomeEvent);

See also
WeakEventManager
IWeakEventListener
Routed Events Overview
Data Binding Overview
Events How-to Topics
Article • 02/06/2023

The topics in this section describe how to use events in WPF.

In This Section
Add an Event Handler Using Code
Handle a Routed Event
Create a Custom Routed Event
Find the Source Element in an Event Handler
Add Class Handling for a Routed Event

Reference
RoutedEvent

EventManager

RoutingStrategy

Related Sections
How to: Add an Event Handler Using
Code
Article • 02/06/2023

This example shows how to add an event handler to an element by using code.

If you want to add an event handler to a XAML element, and the markup page that
contains the element has already been loaded, you must add the handler using code.
Alternatively, if you are building up the element tree for an application entirely using
code and not declaring any elements using XAML, you can call specific methods to add
event handlers to the constructed element tree.

Example
The following example adds a new Button to an existing page that is initially defined in
XAML. A code-behind file implements an event handler method and then adds that
method as a new event handler on the Button.

The C# example uses the += operator to assign a handler to an event. This is the same
operator that is used to assign a handler in the common language runtime (CLR) event
handling model. Microsoft Visual Basic does not support this operator as a means of
adding event handlers. It instead requires one of two techniques:

Use the AddHandler method, together with an AddressOf operator, to reference


the event handler implementation.

Use the Handles keyword as part of the event handler definition. This technique is
not shown here; see Visual Basic and WPF Event Handling.

XAML

<TextBlock Name="text1">Start by clicking the button below</TextBlock>


<Button Name="b1" Click="MakeButton">Make new button and add handler to
it</Button>

C#

public partial class RoutedEventAddRemoveHandler {


void MakeButton(object sender, RoutedEventArgs e)
{
Button b2 = new Button();
b2.Content = "New Button";
// Associate event handler to the button. You can remove the event
// handler using "-=" syntax rather than "+=".
b2.Click += new RoutedEventHandler(Onb2Click);
root.Children.Insert(root.Children.Count, b2);
DockPanel.SetDock(b2, Dock.Top);
text1.Text = "Now click the second button...";
b1.IsEnabled = false;
}
void Onb2Click(object sender, RoutedEventArgs e)
{
text1.Text = "New Button (b2) Was Clicked!!";
}

7 Note

Adding an event handler in the initially parsed XAML page is much simpler. Within
the object element where you want to add the event handler, add an attribute that
matches the name of the event that you want to handle. Then specify the value of
that attribute as the name of the event handler method that you defined in the
code-behind file of the XAML page. For more information, see XAML in WPF or
Routed Events Overview.

See also
Routed Events Overview
How-to Topics
How to: Handle a Routed Event
Article • 02/06/2023

This example shows how bubbling events work and how to write a handler that can
process the routed event data.

Example
In Windows Presentation Foundation (WPF), elements are arranged in an element tree
structure. The parent element can participate in the handling of events that are initially
raised by child elements in the element tree. This is possible because of event routing.

Routed events typically follow one of two routing strategies, bubbling or tunneling. This
example focuses on the bubbling event and uses the ButtonBase.Click event to show
how routing works.

The following example creates two Button controls and uses XAML attribute syntax to
attach an event handler to a common parent element, which in this example is
StackPanel. Instead of attaching individual event handlers for each Button child element,
the example uses attribute syntax to attach the event handler to the StackPanel parent
element. This event-handling pattern shows how to use event routing as a technique for
reducing the number of elements where a handler is attached. All the bubbling events
for each Button route through the parent element.

Note that on the parent StackPanel element, the Click event name specified as the
attribute is partially qualified by naming the Button class. The Button class is a
ButtonBase derived class that has the Click event in its members listing. This partial
qualification technique for attaching an event handler is necessary if the event that is
being handled does not exist in the members listing of the element where the routed
event handler is attached.

XAML

<StackPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.RoutedEventHandle"
Name="dpanel"
Button.Click="HandleClick"
>
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Height" Value="20"/>
<Setter Property="Width" Value="250"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style>
</StackPanel.Resources>
<Button Name="Button1">Item 1</Button>
<Button Name="Button2">Item 2</Button>
<TextBlock Name="results"/>
</StackPanel>

The following example handles the Click event. The example reports which element
handles the event and which element raises the event. The event handler is executed
when the user clicks either button.

C#

public partial class RoutedEventHandle : StackPanel


{
StringBuilder eventstr = new StringBuilder();
void HandleClick(object sender, RoutedEventArgs args)
{
// Get the element that handled the event.
FrameworkElement fe = (FrameworkElement)sender;
eventstr.Append("Event handled by element named ");
eventstr.Append(fe.Name);
eventstr.Append("\n");

// Get the element that raised the event.


FrameworkElement fe2 = (FrameworkElement)args.Source;
eventstr.Append("Event originated from source element of type ");
eventstr.Append(args.Source.GetType().ToString());
eventstr.Append(" with Name ");
eventstr.Append(fe2.Name);
eventstr.Append("\n");

// Get the routing strategy.


eventstr.Append("Event used routing strategy ");
eventstr.Append(args.RoutedEvent.RoutingStrategy);
eventstr.Append("\n");

results.Text = eventstr.ToString();
}
}

See also
RoutedEvent
Input Overview
Routed Events Overview
How-to Topics
XAML Syntax In Detail
How to: Create a Custom Routed Event
Article • 08/10/2023

For your custom event to support event routing, you need to register a RoutedEvent
using the RegisterRoutedEvent method. This example demonstrates the basics of
creating a custom routed event.

Example
As shown in the following example, you first register a RoutedEvent using the
RegisterRoutedEvent method. By convention, the RoutedEvent static field name should
end with the suffix Event. In this example, the name of the event is Tap and the routing
strategy of the event is Bubble. After the registration call, you can provide add-and-
remove common language runtime (CLR) event accessors for the event.

Note that even though the event is raised through the OnTap virtual method in this
particular example, how you raise your event or how your event responds to changes
depends on your needs.

Note also that this example basically implements an entire subclass of Button; that
subclass is built as a separate assembly and then instantiated as a custom class on a
separate XAML page. This is to illustrate the concept that subclassed controls can be
inserted into trees composed of other controls, and that in this situation, custom events
on these controls have the very same event routing capabilities as any native WPF
element does.

C#

public class MyButtonSimple: Button


{
// Create a custom routed event by first registering a RoutedEventID
// This event uses the bubbling routing strategy
public static readonly RoutedEvent TapEvent =
EventManager.RegisterRoutedEvent(
"Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler),
typeof(MyButtonSimple));

// Provide CLR accessors for the event


public event RoutedEventHandler Tap
{
add { AddHandler(TapEvent, value); }
remove { RemoveHandler(TapEvent, value); }
}

// This method raises the Tap event


void RaiseTapEvent()
{
RoutedEventArgs newEventArgs = new
RoutedEventArgs(MyButtonSimple.TapEvent);
RaiseEvent(newEventArgs);
}
// For demonstration purposes we raise the event when the MyButtonSimple
is clicked
protected override void OnClick()
{
RaiseTapEvent();
}
}

XAML

<Window
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"
x:Class="SDKSample.RoutedEventCustomApp"

>
<Window.Resources>
<Style TargetType="{x:Type custom:MyButtonSimple}">
<Setter Property="Height" Value="20"/>
<Setter Property="Width" Value="250"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Background" Value="#808080"/>
</Style>
</Window.Resources>
<StackPanel Background="LightGray">
<custom:MyButtonSimple Name="mybtnsimple" Tap="TapHandler">Click to
see Tap custom event work</custom:MyButtonSimple>
</StackPanel>
</Window>

Tunneling events are created the same way, but with RoutingStrategy set to Tunnel in
the registration call. By convention, tunneling events in WPF are prefixed with the word
"Preview".

To see an example of how bubbling events work, see Handle a Routed Event.

See also
Routed Events Overview
Input Overview
Control Authoring Overview
How to: Find the Source Element in an
Event Handler
Article • 02/06/2023

This example shows how to find the source element in an event handler.

Example
The following example shows a Click event handler that is declared in a code-behind file.
When a user clicks the button that the handler is attached to, the handler changes a
property value. The handler code uses the Source property of the routed event data that
is reported in the event arguments to change the Width property value on the Source
element.

XAML

<Button Click="HandleClick">Button 1</Button>

C#

void HandleClick(object sender, RoutedEventArgs e)


{
// You must cast the sender object as a Button element, or at least as
FrameworkElement, to set Width
Button srcButton = e.Source as Button;
srcButton.Width = 200;
}

See also
RoutedEventArgs
Routed Events Overview
How-to Topics
How to: Add Class Handling for a
Routed Event
Article • 02/06/2023

Routed events can be handled either by class handlers or instance handlers on any given
node in the route. Class handlers are invoked first, and can be used by class
implementations to suppress events from instance handling or introduce other event
specific behaviors on events that are owned by base classes. This example illustrates two
closely related techniques for implementing class handlers.

Example
This example uses a custom class based on the Canvas panel. The basic premise of the
application is that the custom class introduces behaviors on its child elements, including
intercepting any left mouse button clicks and marking them handled, before the child
element class or any instance handlers on it will be invoked.

The UIElement class exposes a virtual method that enables class handling on the
PreviewMouseLeftButtonDown event, by simply overriding the event. This is the simplest
way to implement class handling if such a virtual method is available somewhere in your
class' hierarchy. The following code shows the OnPreviewMouseLeftButtonDown
implementation in the "MyEditContainer" that is derived from Canvas. The
implementation marks the event as handled in the arguments, and then adds some
code to give the source element a basic visible change.

C#

protected override void


OnPreviewMouseRightButtonDown(System.Windows.Input.MouseButtonEventArgs e)
{
e.Handled = true; //suppress the click event and other
leftmousebuttondown responders
MyEditContainer ec = (MyEditContainer)e.Source;
if (ec.EditState)
{ ec.EditState = false; }
else
{ ec.EditState = true; }
base.OnPreviewMouseRightButtonDown(e);
}

If no virtual is available on base classes or for that particular method, class handling can
be added directly using a utility method of the EventManager class,
RegisterClassHandler. This method should only be called within the static initialization of
classes that are adding class handling. This example adds another handler for
PreviewMouseLeftButtonDown , and in this case the registered class is the custom class.
In contrast, when using the virtuals, the registered class is really the UIElement base
class. In cases where base classes and subclass each register class handling, the subclass
handlers are invoked first. The behavior in an application would be that first this handler
would show its message box and then the visual change in the virtual method's handler
would be shown.

C#

static MyEditContainer()
{
EventManager.RegisterClassHandler(typeof(MyEditContainer),
PreviewMouseRightButtonDownEvent, new
RoutedEventHandler(LocalOnMouseRightButtonDown));
}
internal static void LocalOnMouseRightButtonDown(object sender,
RoutedEventArgs e)
{
MessageBox.Show("this is invoked before the On* class handler on
UIElement");
//e.Handled = true; //uncommenting this would cause ONLY the subclass'
class handler to respond
}

See also
EventManager
Marking Routed Events as Handled, and Class Handling
Handle a Routed Event
Routed Events Overview
Input (WPF)
Article • 02/06/2023

Windows Presentation Foundation (WPF) includes support for several types of input.
This input includes text, touch, mouse, commands, focus, touch, drag-and-drop, and
digital ink. This section describes topics related to input in WPF.

In This Section
Input Overview
Commanding Overview
Focus Overview
Styling for Focus in Controls, and FocusVisualStyle
Walkthrough: Creating Your First Touch Application
How-to Topics
Digital Ink

Reference
UIElement

FrameworkElement

ContentElement

FrameworkContentElement

Keyboard

Mouse

FocusManager

Related Sections
Controls
Events
Input Overview
Article • 02/06/2023

The WPF and explains the architecture of the input systems.

Input API
The primary input API exposure is found on the base element classes: UIElement,
ContentElement, FrameworkElement, and FrameworkContentElement. For more
information about the base elements, see Base Elements Overview. These classes
provide functionality for input events related to key presses, mouse buttons, mouse
wheel, mouse movement, focus management, and mouse capture, to name a few. By
placing the input API on the base elements, rather than treating all input events as a
service, the input architecture enables the input events to be sourced by a particular
object in the UI, and to support an event routing scheme whereby more than one
element has an opportunity to handle an input event. Many input events have a pair of
events associated with them. For example, the key down event is associated with the
KeyDown and PreviewKeyDown events. The difference in these events is in how they are
routed to the target element. Preview events tunnel down the element tree from the
root element to the target element. Bubbling events bubble up from the target element
to the root element. Event routing in WPF is discussed in more detail later in this
overview and in the Routed Events Overview.

Keyboard and Mouse Classes


In addition to the input API on the base element classes, the Keyboard class and Mouse
classes provide additional API for working with keyboard and mouse input.

Examples of input API on the Keyboard class are the Modifiers property, which returns
the ModifierKeys currently pressed, and the IsKeyDown method, which determines
whether a specified key is pressed.

The following example uses the GetKeyStates method to determine if a Key is in the
down state.

C#

// Uses the Keyboard.GetKeyStates to determine if a key is down.


// A bitwise AND operation is used in the comparison.
// e is an instance of KeyEventArgs.
if ((Keyboard.GetKeyStates(Key.Return) & KeyStates.Down) > 0)
{
btnNone.Background = Brushes.Red;
}

Examples of input API on the Mouse class are MiddleButton, which obtains the state of
the middle mouse button, and DirectlyOver, which gets the element the mouse pointer
is currently over.

The following example determines whether the LeftButton on the mouse is in the
Pressed state.

C#

if (Mouse.LeftButton == MouseButtonState.Pressed)
{
UpdateSampleResults("Left Button Pressed");
}

The Mouse and Keyboard classes are covered in more detail throughout this overview.

Stylus Input
WPF has integrated support for the Stylus. The Stylus is a pen input made popular by
the Tablet PC. WPF applications can treat the stylus as a mouse by using the mouse API,
but WPF also exposes a stylus device abstraction that use a model similar to the
keyboard and mouse. All stylus-related APIs contain the word "Stylus".

Because the stylus can act as a mouse, applications that support only mouse input can
still obtain some level of stylus support automatically. When the stylus is used in such a
manner, the application is given the opportunity to handle the appropriate stylus event
and then handles the corresponding mouse event. In addition, higher-level services such
as ink input are also available through the stylus device abstraction. For more
information about ink as input, see Getting Started with Ink.

Event Routing
A FrameworkElement can contain other elements as child elements in its content model,
forming a tree of elements. In WPF, the parent element can participate in input directed
to its child elements or other descendants by handing events. This is especially useful for
building controls out of smaller controls, a process known as "control composition" or
"compositing." For more information about element trees and how element trees relate
to event routes, see Trees in WPF.
Event routing is the process of forwarding events to multiple elements, so that a
particular object or element along the route can choose to offer a significant response
(through handling) to an event that might have been sourced by a different element.
Routed events use one of three routing mechanisms: direct, bubbling, and tunneling. In
direct routing, the source element is the only element notified, and the event is not
routed to any other elements. However, the direct routed event still offers some
additional capabilities that are only present for routed events as opposed to standard
CLR events. Bubbling works up the element tree by first notifying the element that
sourced the event, then the parent element, and so on. Tunneling starts at the root of
the element tree and works down, ending with the original source element. For more
information about routed events, see Routed Events Overview.

WPF input events generally come in pairs that consists of a tunneling event and a
bubbling event. Tunneling events are distinguished from bubbling events with the
"Preview" prefix. For instance, PreviewMouseMove is the tunneling version of a mouse
move event and MouseMove is the bubbling version of this event. This event pairing is a
convention that is implemented at the element level and is not an inherent capability of
the WPF event system. For details, see the WPF Input Events section in Routed Events
Overview.

Handling Input Events


To receive input on an element, an event handler must be associated with that particular
event. In XAML this is straightforward: you reference the name of the event as an
attribute of the element that will be listening for this event. Then, you set the value of
the attribute to the name of the event handler that you define, based on a delegate. The
event handler must be written in code such as C# and can be included in a code-behind
file.

Keyboard events occur when the operating system reports key actions that occur while
keyboard focus is on an element. Mouse and stylus events each fall into two categories:
events that report changes in pointer position relative to the element, and events that
report changes in the state of device buttons.

Keyboard Input Event Example


The following example listens for a left arrow key press. A StackPanel is created that has
a Button. An event handler to listen for the left arrow key press is attached to the Button
instance.
The first section of the example creates the StackPanel and the Button and attaches the
event handler for the KeyDown.

XAML

<StackPanel>
<Button Background="AliceBlue"
KeyDown="OnButtonKeyDown"
Content="Button1"/>
</StackPanel>

C#

// Create the UI elements.


StackPanel keyboardStackPanel = new StackPanel();
Button keyboardButton1 = new Button();

// Set properties on Buttons.


keyboardButton1.Background = Brushes.AliceBlue;
keyboardButton1.Content = "Button 1";

// Attach Buttons to StackPanel.


keyboardStackPanel.Children.Add(keyboardButton1);

// Attach event handler.


keyboardButton1.KeyDown += new KeyEventHandler(OnButtonKeyDown);

The second section is written in code and defines the event handler. When the left arrow
key is pressed and the Button has keyboard focus, the handler runs and the Background
color of the Button is changed. If the key is pressed, but it is not the left arrow key, the
Background color of the Button is changed back to its starting color.

C#

private void OnButtonKeyDown(object sender, KeyEventArgs e)


{
Button source = e.Source as Button;
if (source != null)
{
if (e.Key == Key.Left)
{
source.Background = Brushes.LemonChiffon;
}
else
{
source.Background = Brushes.AliceBlue;
}
}
}
Mouse Input Event Example
In the following example, the Background color of a Button is changed when the mouse
pointer enters the Button. The Background color is restored when the mouse leaves the
Button.

The first section of the example creates the StackPanel and the Button control and
attaches the event handlers for the MouseEnter and MouseLeave events to the Button.

XAML

<StackPanel>
<Button Background="AliceBlue"
MouseEnter="OnMouseExampleMouseEnter"
MouseLeave="OnMosueExampleMouseLeave">Button

</Button>
</StackPanel>

C#

// Create the UI elements.


StackPanel mouseMoveStackPanel = new StackPanel();
Button mouseMoveButton = new Button();

// Set properties on Button.


mouseMoveButton.Background = Brushes.AliceBlue;
mouseMoveButton.Content = "Button";

// Attach Buttons to StackPanel.


mouseMoveStackPanel.Children.Add(mouseMoveButton);

// Attach event handler.


mouseMoveButton.MouseEnter += new
MouseEventHandler(OnMouseExampleMouseEnter);
mouseMoveButton.MouseLeave += new
MouseEventHandler(OnMosueExampleMouseLeave);

The second section of the example is written in code and defines the event handlers.
When the mouse enters the Button, the Background color of the Button is changed to
SlateGray. When the mouse leaves the Button, the Background color of the Button is
changed back to AliceBlue.

C#

private void OnMouseExampleMouseEnter(object sender, MouseEventArgs e)


{
// Cast the source of the event to a Button.
Button source = e.Source as Button;

// If source is a Button.
if (source != null)
{
source.Background = Brushes.SlateGray;
}
}

C#

private void OnMosueExampleMouseLeave(object sender, MouseEventArgs e)


{
// Cast the source of the event to a Button.
Button source = e.Source as Button;

// If source is a Button.
if (source != null)
{
source.Background = Brushes.AliceBlue;
}
}

Text Input
The TextInput event enables you to listen for text input in a device-independent manner.
The keyboard is the primary means of text input, but speech, handwriting, and other
input devices can generate text input also.

For keyboard input, WPF first sends the appropriate KeyDown/KeyUp events. If those
events are not handled and the key is textual (rather than a control key such as
directional arrows or function keys), then a TextInput event is raised. There is not always
a simple one-to-one mapping between KeyDown/KeyUp and TextInput events because
multiple keystrokes can generate a single character of text input and single keystrokes
can generate multi-character strings. This is especially true for languages such as
Chinese, Japanese, and Korean which use Input Method Editors (IMEs) to generate the
thousands of possible characters in their corresponding alphabets.

When WPF sends a KeyUp/KeyDown event, Key is set to Key.System if the keystrokes
could become part of a TextInput event (if ALT+S is pressed, for example). This allows
code in a KeyDown event handler to check for Key.System and, if found, leave
processing for the handler of the subsequently raised TextInput event. In these cases,
the various properties of the TextCompositionEventArgs argument can be used to
determine the original keystrokes. Similarly, if an IME is active, Key has the value of
Key.ImeProcessed, and ImeProcessedKey gives the original keystroke or keystrokes.
The following example defines a handler for the Click event and a handler for the
KeyDown event.

The first segment of code or markup creates the user interface.

XAML

<StackPanel KeyDown="OnTextInputKeyDown">
<Button Click="OnTextInputButtonClick"
Content="Open" />
<TextBox> . . . </TextBox>
</StackPanel>

C#

// Create the UI elements.


StackPanel textInputStackPanel = new StackPanel();
Button textInputeButton = new Button();
TextBox textInputTextBox = new TextBox();
textInputeButton.Content = "Open";

// Attach elements to StackPanel.


textInputStackPanel.Children.Add(textInputeButton);
textInputStackPanel.Children.Add(textInputTextBox);

// Attach event handlers.


textInputStackPanel.KeyDown += new KeyEventHandler(OnTextInputKeyDown);
textInputeButton.Click += new RoutedEventHandler(OnTextInputButtonClick);

The second segment of code contains the event handlers.

C#

private void OnTextInputKeyDown(object sender, KeyEventArgs e)


{
if (e.Key == Key.O && Keyboard.Modifiers == ModifierKeys.Control)
{
handle();
e.Handled = true;
}
}

private void OnTextInputButtonClick(object sender, RoutedEventArgs e)


{
handle();
e.Handled = true;
}

public void handle()


{
MessageBox.Show("Pretend this opens a file");
}

Because input events bubble up the event route, the StackPanel receives the input
regardless of which element has keyboard focus. The TextBox control is notified first and
the OnTextInputKeyDown handler is called only if the TextBox did not handle the input. If
the PreviewKeyDown event is used instead of the KeyDown event, the
OnTextInputKeyDown handler is called first.

In this example, the handling logic is written two times—one time for CTRL+O, and
again for button's click event. This can be simplified by using commands, instead of
handling the input events directly. Commands are discussed in this overview and in
Commanding Overview.

Touch and Manipulation


New hardware and API in the Windows 7 operating system provide applications the
ability to receive input from multiple touches simultaneously. WPF enables applications
to detect and respond to touch in a manner similar to responding to other input, such
as the mouse or keyboard, by raising events when touch occurs.

WPF exposes two types of events when touch occurs: touch events and manipulation
events. Touch events provide raw data about each finger on a touchscreen and its
movement. Manipulation events interpret the input as certain actions. Both types of
events are discussed in this section.

Prerequisites
You need the following components to develop an application that responds to touch.

Visual Studio 2010.

Windows 7.

A device, such as a touchscreen, that supports Windows Touch.

Terminology
The following terms are used when touch is discussed.

Touch is a type of user input that is recognized by Windows 7. Usually, touch is


initiated by putting fingers on a touch-sensitive screen. Note that devices such as a
touchpad that is common on laptop computers do not support touch if the device
merely converts the finger's position and movement as mouse input.

Multitouch is touch that occurs from more than one point simultaneously.
Windows 7 and WPF supports multitouch. Whenever touch is discussed in the
documentation for WPF, the concepts apply to multitouch.

A manipulation occurs when touch is interpreted as a physical action that is


applied to an object. In WPF, manipulation events interpret input as a translation,
expansion, or rotation manipulation.

A touch device represents a device that produces touch input, such as a single
finger on a touchscreen.

Controls that Respond to Touch


The following controls can be scrolled by dragging a finger across the control if it has
content that is scrolled out of view.

ComboBox

ContextMenu

DataGrid

ListBox

ListView

MenuItem

TextBox

ToolBar

TreeView

The ScrollViewer defines the ScrollViewer.PanningMode attached property that enables


you to specify whether touch panning is enabled horizontally, vertically, both, or neither.
The ScrollViewer.PanningDeceleration property specifies how quickly the scrolling slows
down when the user lifts the finger from the touchscreen. The ScrollViewer.PanningRatio
attached property specifies the ratio of scrolling offset to translate manipulation offset.

Touch Events
The base classes, UIElement, UIElement3D, and ContentElement, define events that you
can subscribe to so your application will respond to touch. Touch events are useful when
your application interprets touch as something other than manipulating an object. For
example, an application that enables a user to draw with one or more fingers would
subscribe to touch events.

All three classes define the following events, which behave similarly, regardless of the
defining class.

TouchDown

TouchMove

TouchUp

TouchEnter

TouchLeave

PreviewTouchDown

PreviewTouchMove

PreviewTouchUp

GotTouchCapture

LostTouchCapture

Like keyboard and mouse events, the touch events are routed events. The events that
begin with Preview are tunneling events and the events that begin with Touch are
bubbling events. For more information about routed events, see Routed Events
Overview. When you handle these events, you can get the position of the input, relative
to any element, by calling the GetTouchPoint or GetIntermediateTouchPoints method.

To understand the interaction among the touch events, consider the scenario where a
user puts one finger on an element, moves the finger in the element, and then lifts the
finger from the element. The following illustration shows the execution of the bubbling
events (the tunneling events are omitted for simplicity).
Touch events

The following list describes the sequence of the events in the preceding illustration.

1. The TouchEnter event occurs one time when the user puts a finger on the element.

2. The TouchDown event occurs one time.

3. The TouchMove event occurs multiple times as the user moves the finger within
the element.

4. The TouchUp event occurs one time when the user lifts the finger from the
element.

5. The TouchLeave event occurs one time.

When more than two fingers are used, the events occur for each finger.

Manipulation Events
For cases where an application enables a user to manipulate an object, the UIElement
class defines manipulation events. Unlike the touch events that simply report the
position of touch, the manipulation events report how the input can be interpreted.
There are three types of manipulations, translation, expansion, and rotation. The
following list describes how to invoke the three types of manipulations.

Put a finger on an object and move the finger across the touchscreen to invoke a
translation manipulation. This usually moves the object.

Put two fingers on an object and move the fingers closer together or farther apart
from one another to invoke an expansion manipulation. This usually resizes the
object.

Put two fingers on an object and rotate the fingers around each other to invoke a
rotation manipulation. This usually rotates the object.

More than one type of manipulation can occur simultaneously.


When you cause objects to respond to manipulations, you can have the object appear
to have inertia. This can make your objects simulate the physical world. For example,
when you push a book across a table, if you push hard enough the book will continue to
move after you release it. WPF enables you to simulate this behavior by raising
manipulation events after the user's fingers releases the object.

For information about how to create an application that enables the user to move,
resize, and rotate an object, see Walkthrough: Creating Your First Touch Application.

The UIElement defines the following manipulation events.

ManipulationStarting

ManipulationStarted

ManipulationDelta

ManipulationInertiaStarting

ManipulationCompleted

ManipulationBoundaryFeedback

By default, a UIElement does not receive these manipulation events. To receive


manipulation events on a UIElement, set UIElement.IsManipulationEnabled to true .

The Execution Path of Manipulation Events


Consider a scenario where a user "throws" an object. The user puts a finger on the
object, moves the finger across the touchscreen for a short distance, and then lifts the
finger while it is moving. The result of this is that the object will move under the user's
finger and continue to move after the user lifts the finger.

The following illustration shows the execution path of manipulation events and
important information about each event.
Manipulation events

The following list describes the sequence of the events in the preceding illustration.

1. The ManipulationStarting event occurs when the user places a finger on the object.
Among other things, this event allows you to set the ManipulationContainer
property. In the subsequent events, the position of the manipulation will be
relative to the ManipulationContainer. In events other than ManipulationStarting,
this property is read-only, so the ManipulationStarting event is the only time that
you can set this property.

2. The ManipulationStarted event occurs next. This event reports the origin of the
manipulation.

3. The ManipulationDelta event occurs multiple times as a user's fingers move on a


touchscreen. The DeltaManipulation property of the ManipulationDeltaEventArgs
class reports whether the manipulation is interpreted as movement, expansion, or
translation. This is where you perform most of the work of manipulating an object.

4. The ManipulationInertiaStarting event occurs when the user's fingers lose contact
with the object. This event enables you to specify the deceleration of the
manipulations during inertia. This is so your object can emulate different physical
spaces or attributes if you choose. For example, suppose your application has two
objects that represent items in the physical world, and one is heavier than the
other. You can make the heavier object decelerate faster than the lighter object.

5. The ManipulationDelta event occurs multiple times as inertia occurs. Note that this
event occurs when the user's fingers move across the touchscreen and when WPF
simulates inertia. In other words, ManipulationDelta occurs before and after the
ManipulationInertiaStarting event. The ManipulationDeltaEventArgs.IsInertial
property reports whether the ManipulationDelta event occurs during inertia, so
you can check that property and perform different actions, depending on its value.
6. The ManipulationCompleted event occurs when the manipulation and any inertia
ends. That is, after all the ManipulationDelta events occur, the
ManipulationCompleted event occurs to signal that the manipulation is complete.

The UIElement also defines the ManipulationBoundaryFeedback event. This event occurs
when the ReportBoundaryFeedback method is called in the ManipulationDelta event.
The ManipulationBoundaryFeedback event enables applications or components to
provide visual feedback when an object hits a boundary. For example, the Window class
handles the ManipulationBoundaryFeedback event to cause the window to slightly
move when its edge is encountered.

You can cancel the manipulation by calling the Cancel method on the event arguments
in any manipulation event except ManipulationBoundaryFeedback event. When you call
Cancel, the manipulation events are no longer raised and mouse events occur for touch.
The following table describes the relationship between the time the manipulation is
canceled and the mouse events that occur.

The event that Cancel is called in The mouse events that occur for input that
already occurred

ManipulationStarting and Mouse down events.


ManipulationStarted

ManipulationDelta Mouse down and mouse move events.

ManipulationInertiaStarting and Mouse down, mouse move, and mouse up events.


ManipulationCompleted

Note that if you call Cancel when the manipulation is in inertia, the method returns
false and the input does not raise mouse events.

The Relationship Between Touch and Manipulation Events


A UIElement can always receive touch events. When the IsManipulationEnabled property
is set to true , a UIElement can receive both touch and manipulation events. If the
TouchDown event is not handled (that is, the Handled property is false ), the
manipulation logic captures the touch to the element and generates the manipulation
events. If the Handled property is set to true in the TouchDown event, the manipulation
logic does not generate manipulation events. The following illustration shows the
relationship between touch events and manipulation events.
Touch and manipulation events

The following list describes the relationship between the touch and manipulation events
that is shown in the preceding illustration.

When the first touch device generates a TouchDown event on a UIElement, the
manipulation logic calls the CaptureTouch method, which generates the
GotTouchCapture event.

When the GotTouchCapture occurs, the manipulation logic calls the


Manipulation.AddManipulator method, which generates the ManipulationStarting
event.

When the TouchMove events occur, the manipulation logic generates the
ManipulationDelta events that occur before the ManipulationInertiaStarting event.

When the last touch device on the element raises the TouchUp event, the
manipulation logic generates the ManipulationInertiaStarting event.

Focus
There are two main concepts that pertain to focus in WPF: keyboard focus and logical
focus.

Keyboard Focus
Keyboard focus refers to the element that is receiving keyboard input. There can be only
one element on the whole desktop that has keyboard focus. In WPF, the element that
has keyboard focus will have IsKeyboardFocused set to true . The static Keyboard
method FocusedElement returns the element that currently has keyboard focus.

Keyboard focus can be obtained by tabbing to an element or by clicking the mouse on


certain elements, such as a TextBox. Keyboard focus can also be obtained
programmatically by using the Focus method on the Keyboard class. Focus attempts to
give the specified element keyboard focus. The element returned by Focus is the
element that currently has keyboard focus.

In order for an element to obtain keyboard focus the Focusable property and the
IsVisible properties must be set to true. Some classes, such as Panel, have Focusable set
to false by default; therefore, you may have to set this property to true if you want
that element to be able to obtain focus.

The following example uses Focus to set keyboard focus on a Button. The
recommended place to set initial focus in an application is in the Loaded event handler.

C#

private void OnLoaded(object sender, RoutedEventArgs e)


{
// Sets keyboard focus on the first Button in the sample.
Keyboard.Focus(firstButton);
}

For more information about keyboard focus, see Focus Overview.

Logical Focus
Logical focus refers to the FocusManager.FocusedElement in a focus scope. There can
be multiple elements that have logical focus in an application, but there may only be
one element that has logical focus in a particular focus scope.

A focus scope is a container element that keeps track of the FocusedElement within its
scope. When focus leaves a focus scope, the focused element will lose keyboard focus
but will retain logical focus. When focus returns to the focus scope, the focused element
will obtain keyboard focus. This allows for keyboard focus to be changed between
multiple focus scopes but insures that the focused element within the focus scope
remains the focused element when focus returns.

An element can be turned into a focus scope in Extensible Application Markup


Language (XAML) by setting the FocusManager attached property IsFocusScope to
true , or in code by setting the attached property by using the SetIsFocusScope method.
The following example makes a StackPanel into a focus scope by setting the
IsFocusScope attached property.

XAML

<StackPanel Name="focusScope1"
FocusManager.IsFocusScope="True"
Height="200" Width="200">
<Button Name="button1" Height="50" Width="50"/>
<Button Name="button2" Height="50" Width="50"/>
</StackPanel>

C#

StackPanel focuseScope2 = new StackPanel();


FocusManager.SetIsFocusScope(focuseScope2, true);

Classes in WPF which are focus scopes by default are Window, Menu, ToolBar, and
ContextMenu.

An element that has keyboard focus will also have logical focus for the focus scope it
belongs to; therefore, setting focus on an element with the Focus method on the
Keyboard class or the base element classes will attempt to give the element keyboard
focus and logical focus.

To determine the focused element in a focus scope, use GetFocusedElement. To change


the focused element for a focus scope, use SetFocusedElement.

For more information about logical focus, see Focus Overview.

Mouse Position
The WPF input API provides helpful information with regard to coordinate spaces. For
example, coordinate (0,0) is the upper-left coordinate, but the upper-left of which
element in the tree? The element that is the input target? The element you attached
your event handler to? Or something else? To avoid confusion, the WPF input API
requires that you specify your frame of reference when you work with coordinates
obtained through the mouse. The GetPosition method returns the coordinate of the
mouse pointer relative to the specified element.

Mouse Capture
Mouse devices specifically hold a modal characteristic known as mouse capture. Mouse
capture is used to maintain a transitional input state when a drag-and-drop operation is
started, so that other operations involving the nominal on-screen position of the mouse
pointer do not necessarily occur. During the drag, the user cannot click without aborting
the drag-and-drop, which makes most mouseover cues inappropriate while the mouse
capture is held by the drag origin. The input system exposes APIs that can determine
mouse capture state, as well as APIs that can force mouse capture to a specific element,
or clear mouse capture state. For more information on drag-and-drop operations, see
Drag and Drop Overview.

Commands
Commands enable input handling at a more semantic level than device input.
Commands are simple directives, such as Cut , Copy , Paste , or Open . Commands are
useful for centralizing your command logic. The same command might be accessed
from a Menu, on a ToolBar, or through a keyboard shortcut. Commands also provide a
mechanism for disabling controls when the command becomes unavailable.

RoutedCommand is the WPF implementation of ICommand. When a RoutedCommand


is executed, a PreviewExecuted and an Executed event are raised on the command
target, which tunnel and bubble through the element tree like other input. If a
command target is not set, the element with keyboard focus will be the command
target. The logic that performs the command is attached to a CommandBinding. When
an Executed event reaches a CommandBinding for that specific command, the
ExecutedRoutedEventHandler on the CommandBinding is called. This handler performs
the action of the command.

For more information on commanding, see Commanding Overview.

WPF provides a library of common commands which consists of ApplicationCommands,


MediaCommands, ComponentCommands, NavigationCommands, and
EditingCommands, or you can define your own.

The following example shows how to set up a MenuItem so that when it is clicked it will
invoke the Paste command on the TextBox, assuming the TextBox has keyboard focus.

XAML

<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste" />
</Menu>
<TextBox />
</StackPanel>
C#

// Creating the UI objects


StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();

// Adding objects to the panel and the menu


stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);

// Setting the command to the Paste command


pasteMenuItem.Command = ApplicationCommands.Paste;

// Setting the command target to the TextBox


pasteMenuItem.CommandTarget = pasteTextBox;

For more information about commands in WPF, see Commanding Overview.

The Input System and Base Elements


Input events such as the attached events defined by the Mouse, Keyboard, and Stylus
classes are raised by the input system and injected into a particular position in the
object model based on hit testing the visual tree at run time.

Each of the events that Mouse, Keyboard, and Stylus define as an attached event is also
re-exposed by the base element classes UIElement and ContentElement as a new routed
event. The base element routed events are generated by classes handling the original
attached event and reusing the event data.

When the input event becomes associated with a particular source element through its
base element input event implementation, it can be routed through the remainder of an
event route that is based on a combination of logical and visual tree objects, and be
handled by application code. Generally, it is more convenient to handle these device-
related input events using the routed events on UIElement and ContentElement,
because you can use more intuitive event handler syntax both in XAML and in code. You
could choose to handle the attached event that initiated the process instead, but you
would face several issues: the attached event may be marked handled by the base
element class handling, and you need to use accessor methods rather than true event
syntax in order to attach handlers for attached events.
What's Next
You now have several techniques to handle input in WPF. You should also have an
improved understanding of the various types of input events and the routed event
mechanisms used by WPF.

Additional resources are available that explain WPF framework elements and event
routing in more detail. See the following overviews for more information, Commanding
Overview, Focus Overview, Base Elements Overview, Trees in WPF, and Routed Events
Overview.

See also
Focus Overview
Commanding Overview
Routed Events Overview
Base Elements Overview
Properties
Commanding Overview
Article • 03/16/2023

Commanding is an input mechanism in Windows Presentation Foundation (WPF) which


provides input handling at a more semantic level than device input. Examples of
commands are the Copy, Cut, and Paste operations found on many applications.

This overview defines what commands are in WPF, which classes are part of the
commanding model, and how to use and create commands in your applications.

This topic contains the following sections:

What Are Commands?

Simple Command Example in WPF

Four Main Concepts in WPF Commanding

Command Library

Creating Custom Commands

What Are Commands


Commands have several purposes. The first purpose is to separate the semantics and
the object that invokes a command from the logic that executes the command. This
allows for multiple and disparate sources to invoke the same command logic, and it
allows the command logic to be customized for different targets. For example, the
editing operations Copy, Cut, and Paste, which are found in many applications, can be
invoked by using different user actions if they are implemented by using commands. An
application might allow a user to cut selected objects or text by either clicking a button,
choosing an item in a menu, or using a key combination, such as CTRL+X. By using
commands, you can bind each type of user action to the same logic.

Another purpose of commands is to indicate whether an action is available. To continue


the example of cutting an object or text, the action only makes sense when something is
selected. If a user tries to cut an object or text without having anything selected, nothing
would happen. To indicate this to the user, many applications disable buttons and menu
items so that the user knows whether it is possible to perform an action. A command
can indicate whether an action is possible by implementing the CanExecute method. A
button can subscribe to the CanExecuteChanged event and be disabled if CanExecute
returns false or be enabled if CanExecute returns true .
The semantics of a command can be consistent across applications and classes, but the
logic of the action is specific to the particular object acted upon. The key combination
CTRL+X invokes the Cut command in text classes, image classes, and Web browsers, but
the actual logic for performing the Cut operation is defined by the application that
performs the cut. A RoutedCommand enables clients to implement the logic. A text
object may cut the selected text into the clipboard, while an image object may cut the
selected image. When an application handles the Executed event, it has access to the
target of the command and can take appropriate action depending on the target's type.

Simple Command Example in WPF


The simplest way to use a command in WPF is to use a predefined RoutedCommand
from one of the command library classes; use a control that has native support for
handling the command; and use a control that has native support for invoking a
command. The Paste command is one of the predefined commands in the
ApplicationCommands class. The TextBox control has built in logic for handling the Paste
command. And the MenuItem class has native support for invoking commands.

The following example shows how to set up a MenuItem so that when it is clicked it will
invoke the Paste command on a TextBox, assuming the TextBox has keyboard focus.

XAML

<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste" />
</Menu>
<TextBox />
</StackPanel>

C#

// Creating the UI objects


StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();

// Adding objects to the panel and the menu


stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);

// Setting the command to the Paste command


pasteMenuItem.Command = ApplicationCommands.Paste;
// Setting the command target to the TextBox
pasteMenuItem.CommandTarget = pasteTextBox;

Four Main Concepts in WPF Commanding


The routed command model in WPF can be broken up into four main concepts: the
command, the command source, the command target, and the command binding:

The command is the action to be executed.

The command source is the object which invokes the command.

The command target is the object that the command is being executed on.

The command binding is the object which maps the command logic to the
command.

In the previous example, the Paste command is the command, the MenuItem is the
command source, the TextBox is the command target, and the command binding is
supplied by the TextBox control. It is worth noting that it is not always the case that the
CommandBinding is supplied by the control that is the command target class. Quite
often the CommandBinding must be created by the application developer, or the
CommandBinding might be attached to an ancestor of the command target.

Commands
Commands in WPF are created by implementing the ICommand interface. ICommand
exposes two methods, Execute, and CanExecute, and an event, CanExecuteChanged.
Execute performs the actions that are associated with the command. CanExecute
determines whether the command can execute on the current command target.
CanExecuteChanged is raised if the command manager that centralizes the
commanding operations detects a change in the command source that might invalidate
a command that has been raised but not yet executed by the command binding. The
WPF implementation of ICommand is the RoutedCommand class and is the focus of this
overview.

The main sources of input in WPF are the mouse, the keyboard, ink, and routed
commands. The more device-oriented inputs use a RoutedEvent to notify objects in an
application page that an input event has occurred. A RoutedCommand is no different.
The Execute and CanExecute methods of a RoutedCommand do not contain the
application logic for the command, but rather they raise routed events that tunnel and
bubble through the element tree until they encounter an object with a
CommandBinding. The CommandBinding contains the handlers for these events and it
is the handlers that perform the command. For more information on event routing in
WPF, see Routed Events Overview.

The Execute method on a RoutedCommand raises the PreviewExecuted and the


Executed events on the command target. The CanExecute method on a
RoutedCommand raises the CanExecute and PreviewCanExecute events on the
command target. These events tunnel and bubble through the element tree until they
encounter an object which has a CommandBinding for that particular command.

WPF supplies a set of common routed commands spread across several classes:
MediaCommands, ApplicationCommands, NavigationCommands,
ComponentCommands, and EditingCommands. These classes consist only of the
RoutedCommand objects and not the implementation logic of the command. The
implementation logic is the responsibility of the object on which the command is being
executed on.

Command Sources
A command source is the object which invokes the command. Examples of command
sources are MenuItem, Button, and KeyGesture.

Command sources in WPF generally implement the ICommandSource interface.

ICommandSource exposes three properties: Command, CommandTarget, and


CommandParameter:

Command is the command to execute when the command source is invoked.

CommandTarget is the object on which to execute the command. It is worth noting


that in WPF the CommandTarget property on ICommandSource is only applicable
when the ICommand is a RoutedCommand. If the CommandTarget is set on an
ICommandSource and the corresponding command is not a RoutedCommand, the
command target is ignored. If the CommandTarget is not set, the element with
keyboard focus will be the command target.

CommandParameter is a user-defined data type used to pass information to the


handlers implementing the command.

The WPF classes that implement ICommandSource are ButtonBase, MenuItem,


Hyperlink, and InputBinding. ButtonBase, MenuItem, and Hyperlink invoke a command
when they are clicked, and an InputBinding invokes a command when the InputGesture
associated with it is performed.
The following example shows how to use a MenuItem in a ContextMenu as a command
source for the Properties command.

XAML

<StackPanel>
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Command="ApplicationCommands.Properties" />
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>

C#

StackPanel cmdSourcePanel = new StackPanel();


ContextMenu cmdSourceContextMenu = new ContextMenu();
MenuItem cmdSourceMenuItem = new MenuItem();

// Add ContextMenu to the StackPanel.


cmdSourcePanel.ContextMenu = cmdSourceContextMenu;
cmdSourcePanel.ContextMenu.Items.Add(cmdSourceMenuItem);

// Associate Command with MenuItem.


cmdSourceMenuItem.Command = ApplicationCommands.Properties;

Typically, a command source will listen to the CanExecuteChanged event. This event
informs the command source that the ability of the command to execute on the current
command target may have changed. The command source can query the current status
of the RoutedCommand by using the CanExecute method. The command source can
then disable itself if the command cannot execute. An example of this is a MenuItem
graying itself out when a command cannot execute.

An InputGesture can be used as a command source. Two types of input gestures in WPF
are the KeyGesture and MouseGesture. You can think of a KeyGesture as a keyboard
shortcut, such as CTRL+C. A KeyGesture is comprised of a Key and a set of ModifierKeys.
A MouseGesture is comprised of a MouseAction and an optional set of ModifierKeys.

In order for an InputGesture to act as a command source, it must be associated with a


command. There are a few ways to accomplish this. One way is to use an InputBinding.

The following example shows how to create a KeyBinding between a KeyGesture and a
RoutedCommand.

XAML
<Window.InputBindings>
<KeyBinding Key="B"
Modifiers="Control"
Command="ApplicationCommands.Open" />
</Window.InputBindings>

C#

KeyGesture OpenKeyGesture = new KeyGesture(


Key.B,
ModifierKeys.Control);

KeyBinding OpenCmdKeybinding = new KeyBinding(


ApplicationCommands.Open,
OpenKeyGesture);

this.InputBindings.Add(OpenCmdKeybinding);

Another way to associate an InputGesture to a RoutedCommand is to add the


InputGesture to the InputGestureCollection on the RoutedCommand.

The following example shows how to add a KeyGesture to the InputGestureCollection of


a RoutedCommand.

C#

KeyGesture OpenCmdKeyGesture = new KeyGesture(


Key.B,
ModifierKeys.Control);

ApplicationCommands.Open.InputGestures.Add(OpenCmdKeyGesture);

CommandBinding
A CommandBinding associates a command with the event handlers that implement the
command.

The CommandBinding class contains a Command property, and PreviewExecuted,


Executed, PreviewCanExecute, and CanExecute events.

Command is the command that the CommandBinding is being associated with. The
event handlers which are attached to the PreviewExecuted and Executed events
implement the command logic. The event handlers attached to the PreviewCanExecute
and CanExecute events determine if the command can execute on the current command
target.
The following example shows how to create a CommandBinding on the root Window of
an application. The CommandBinding associates the Open command with Executed and
CanExecute handlers.

XAML

<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Open"
Executed="OpenCmdExecuted"
CanExecute="OpenCmdCanExecute"/>
</Window.CommandBindings>

C#

// Creating CommandBinding and attaching an Executed and CanExecute handler


CommandBinding OpenCmdBinding = new CommandBinding(
ApplicationCommands.Open,
OpenCmdExecuted,
OpenCmdCanExecute);

this.CommandBindings.Add(OpenCmdBinding);

Next, the ExecutedRoutedEventHandler and a CanExecuteRoutedEventHandler are


created. The ExecutedRoutedEventHandler opens a MessageBox that displays a string
saying the command has been executed. The CanExecuteRoutedEventHandler sets the
CanExecute property to true .

C#

void OpenCmdExecuted(object target, ExecutedRoutedEventArgs e)


{
String command, targetobj;
command = ((RoutedCommand)e.Command).Name;
targetobj = ((FrameworkElement)target).Name;
MessageBox.Show("The " + command + " command has been invoked on target
object " + targetobj);
}

C#

void OpenCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)


{
e.CanExecute = true;
}
A CommandBinding is attached to a specific object, such as the root Window of the
application or a control. The object that the CommandBinding is attached to defines the
scope of the binding. For example, a CommandBinding attached to an ancestor of the
command target can be reached by the Executed event, but a CommandBinding
attached to a descendant of the command target cannot be reached. This is a direct
consequence of the way a RoutedEvent tunnels and bubbles from the object that raises
the event.

In some situations the CommandBinding is attached to the command target itself, such
as with the TextBox class and the Cut, Copy, and Paste commands. Quite often though, it
is more convenient to attach the CommandBinding to an ancestor of the command
target, such as the main Window or the Application object, especially if the same
CommandBinding can be used for multiple command targets. These are design
decisions you will want to consider when you are creating your commanding
infrastructure.

Command Target
The command target is the element on which the command is executed. With regards to
a RoutedCommand, the command target is the element at which routing of the
Executed and CanExecute starts. As noted previously, in WPF the CommandTarget
property on ICommandSource is only applicable when the ICommand is a
RoutedCommand. If the CommandTarget is set on an ICommandSource and the
corresponding command is not a RoutedCommand, the command target is ignored.

The command source can explicitly set the command target. If the command target is
not defined, the element with keyboard focus will be used as the command target. One
of the benefits of using the element with keyboard focus as the command target is that
it allows the application developer to use the same command source to invoke a
command on multiple targets without having to keep track of the command target. For
example, if a MenuItem invokes the Paste command in an application that has a TextBox
control and a PasswordBox control, the target can be either the TextBox or PasswordBox
depending on which control has keyboard focus.

The following example shows how to explicitly set the command target in markup and
in code behind.

XAML

<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste"
CommandTarget="{Binding ElementName=mainTextBox}" />
</Menu>
<TextBox Name="mainTextBox"/>
</StackPanel>

C#

// Creating the UI objects


StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();

// Adding objects to the panel and the menu


stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);

// Setting the command to the Paste command


pasteMenuItem.Command = ApplicationCommands.Paste;

// Setting the command target to the TextBox


pasteMenuItem.CommandTarget = pasteTextBox;

The CommandManager
The CommandManager serves a number of command related functions. It provides a set
of static methods for adding and removing PreviewExecuted, Executed,
PreviewCanExecute, and CanExecute event handlers to and from a specific element. It
provides a means to register CommandBinding and InputBinding objects onto a specific
class. The CommandManager also provides a means, through the RequerySuggested
event, to notify a command when it should raise the CanExecuteChanged event.

The InvalidateRequerySuggested method forces the CommandManager to raise the


RequerySuggested event. This is useful for conditions that should disable/enable a
command but are not conditions that the CommandManager is aware of.

Command Library
WPF provides a set of predefined commands. The command library consists of the
following classes: ApplicationCommands, NavigationCommands, MediaCommands,
EditingCommands, and the ComponentCommands. These classes provide commands
such as Cut, BrowseBack and BrowseForward, Play, Stop, and Pause.

Many of these commands include a set of default input bindings. For example, if you
specify that your application handles the copy command, you automatically get the
keyboard binding "CTRL+C" You also get bindings for other input devices, such as Tablet
PC pen gestures and speech information.

When you reference commands in the various command libraries using XAML, you can
usually omit the class name of the library class that exposes the static command
property. Generally, the command names are unambiguous as strings, and the owning
types exist to provide a logical grouping of commands but are not necessary for
disambiguation. For instance, you can specify Command="Cut" rather than the more
verbose Command="ApplicationCommands.Cut" . This is a convenience mechanism that is
built in to the WPF XAML processor for commands (more precisely, it is a type converter
behavior of ICommand, which the WPF XAML processor references at load time).

Creating Custom Commands


If the commands in the command library classes do not meet your needs, then you can
create your own commands. There are two ways to create a custom command. The first
is to start from the ground up and implement the ICommand interface. The other way,
and the more common approach, is to create a RoutedCommand or a
RoutedUICommand.

For an example of creating a custom RoutedCommand, see Create a Custom


RoutedCommand Sample .

See also
RoutedCommand
CommandBinding
InputBinding
CommandManager
Input Overview
Routed Events Overview
Implement ICommandSource
How to: Add a Command to a MenuItem
Create a Custom RoutedCommand Sample
Focus Overview
Article • 02/06/2023

In WPF there are two main concepts that pertain to focus: keyboard focus and logical
focus. Keyboard focus refers to the element that receives keyboard input and logical
focus refers to the element in a focus scope that has focus. These concepts are
discussed in detail in this overview. Understanding the difference in these concepts is
important for creating complex applications that have multiple regions where focus can
be obtained.

The major classes that participate in focus management are the Keyboard class, the
FocusManager class, and the base element classes, such as UIElement and
ContentElement. For more information about the base elements, see the Base Elements
Overview.

The Keyboard class is concerned primarily with keyboard focus and the FocusManager is
concerned primarily with logical focus, but this is not an absolute distinction. An
element that has keyboard focus will also have logical focus, but an element that has
logical focus does not necessarily have keyboard focus. This is apparent when you use
the Keyboard class to set the element that has keyboard focus, for it also sets logical
focus on the element.

Keyboard Focus
Keyboard focus refers to the element that is currently receiving keyboard input. There
can be only one element on the whole desktop that has keyboard focus. In WPF, the
element that has keyboard focus will have IsKeyboardFocused set to true . The static
property FocusedElement on the Keyboard class gets the element that currently has
keyboard focus.

In order for an element to obtain keyboard focus, the Focusable and the IsVisible
properties on the base elements must be set to true . Some classes, such as the Panel
base class, have Focusable set to false by default; therefore, you must set Focusable to
true if you want such an element to be able to obtain keyboard focus.

Keyboard focus can be obtained through user interaction with the UI, such as tabbing to
an element or clicking the mouse on certain elements. Keyboard focus can also be
obtained programmatically by using the Focus method on the Keyboard class. The
Focus method attempts to give the specified element keyboard focus. The returned
element is the element that has keyboard focus, which might be a different element
than requested if either the old or new focus object block the request.

The following example uses the Focus method to set keyboard focus on a Button.

C#

private void OnLoaded(object sender, RoutedEventArgs e)


{
// Sets keyboard focus on the first Button in the sample.
Keyboard.Focus(firstButton);
}

The IsKeyboardFocused property on the base element classes gets a value indicating
whether the element has keyboard focus. The IsKeyboardFocusWithin property on the
base element classes gets a value indicating whether the element or any one of its visual
child elements has keyboard focus.

When setting initial focus at application startup, the element to receive focus must be in
the visual tree of the initial window loaded by the application, and the element must
have Focusable and IsVisible set to true . The recommended place to set initial focus is
in the Loaded event handler. A Dispatcher callback can also be used by calling Invoke or
BeginInvoke.

Logical Focus
Logical focus refers to the FocusManager.FocusedElement in a focus scope. A focus
scope is an element that keeps track of the FocusedElement within its scope. When
keyboard focus leaves a focus scope, the focused element will lose keyboard focus but
will retain logical focus. When keyboard focus returns to the focus scope, the focused
element will obtain keyboard focus. This allows for keyboard focus to be changed
between multiple focus scopes but ensures that the focused element in the focus scope
regains keyboard focus when focus returns to the focus scope.

There can be multiple elements that have logical focus in an application, but there may
only be one element that has logical focus in a particular focus scope.

An element that has keyboard focus has logical focus for the focus scope it belongs to.

An element can be turned into a focus scope in Extensible Application Markup


Language (XAML) by setting the FocusManager attached property IsFocusScope to
true . In code, an element can be turned into a focus scope by calling SetIsFocusScope.
The following example makes a StackPanel into a focus scope by setting the
IsFocusScope attached property.

XAML

<StackPanel Name="focusScope1"
FocusManager.IsFocusScope="True"
Height="200" Width="200">
<Button Name="button1" Height="50" Width="50"/>
<Button Name="button2" Height="50" Width="50"/>
</StackPanel>

C#

StackPanel focuseScope2 = new StackPanel();


FocusManager.SetIsFocusScope(focuseScope2, true);

GetFocusScope returns the focus scope for the specified element.

Classes in WPF which are focus scopes by default are Window, MenuItem, ToolBar, and
ContextMenu.

GetFocusedElement gets the focused element for the specified focus scope.
SetFocusedElement sets the focused element in the specified focus scope.
SetFocusedElement is typically used to set the initial focused element.

The following example sets the focused element on a focus scope and gets the focused
element of a focus scope.

C#

// Sets the focused element in focusScope1


// focusScope1 is a StackPanel.
FocusManager.SetFocusedElement(focusScope1, button2);

// Gets the focused element for focusScope 1


IInputElement focusedElement = FocusManager.GetFocusedElement(focusScope1);

Keyboard Navigation
The KeyboardNavigation class is responsible for implementing default keyboard focus
navigation when one of the navigation keys is pressed. The navigation keys are: TAB,
SHIFT+TAB, CTRL+TAB, CTRL+SHIFT+TAB, UPARROW, DOWNARROW, LEFTARROW, and
RIGHTARROW keys.
The navigation behavior of a navigation container can be changed by setting the
attached KeyboardNavigation properties TabNavigation, ControlTabNavigation, and
DirectionalNavigation. These properties are of type KeyboardNavigationMode and the
possible values are Continue, Local, Contained, Cycle, Once, and None. The default value
is Continue, which means the element is not a navigation container.

The following example creates a Menu with a number of MenuItem objects. The
TabNavigation attached property is set to Cycle on the Menu. When focus is changed
using the tab key within the Menu, focus will move from each element and when the last
element is reached focus will return to the first element.

XAML

<Menu KeyboardNavigation.TabNavigation="Cycle">
<MenuItem Header="Menu Item 1" />
<MenuItem Header="Menu Item 2" />
<MenuItem Header="Menu Item 3" />
<MenuItem Header="Menu Item 4" />
</Menu>

C#

Menu navigationMenu = new Menu();


MenuItem item1 = new MenuItem();
MenuItem item2 = new MenuItem();
MenuItem item3 = new MenuItem();
MenuItem item4 = new MenuItem();

navigationMenu.Items.Add(item1);
navigationMenu.Items.Add(item2);
navigationMenu.Items.Add(item3);
navigationMenu.Items.Add(item4);

KeyboardNavigation.SetTabNavigation(navigationMenu,
KeyboardNavigationMode.Cycle);

Navigating Focus Programmatically


Additional API to work with focus are MoveFocus and PredictFocus.

MoveFocus changes focus to the next element in the application. A TraversalRequest is


used to specify the direction. The FocusNavigationDirection passed to MoveFocus
specifies the different directions focus can be moved, such as First, Last, Up and Down.

The following example uses MoveFocus to change the focused element.


C#

// Creating a FocusNavigationDirection object and setting it to a


// local field that contains the direction selected.
FocusNavigationDirection focusDirection = _focusMoveValue;

// MoveFocus takes a TraveralReqest as its argument.


TraversalRequest request = new TraversalRequest(focusDirection);

// Gets the element with keyboard focus.


UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;

// Change keyboard focus.


if (elementWithFocus != null)
{
elementWithFocus.MoveFocus(request);
}

PredictFocus returns the object which would receive focus if focus were to be changed.
Currently, only Up, Down, Left, and Right are supported by PredictFocus.

Focus Events
The events related to keyboard focus are PreviewGotKeyboardFocus, GotKeyboardFocus
and PreviewLostKeyboardFocus, LostKeyboardFocus. The events are defined as attached
events on the Keyboard class, but are more readily accessible as equivalent routed
events on the base element classes. For more information about events, see the Routed
Events Overview.

GotKeyboardFocus is raised when the element obtains keyboard focus.


LostKeyboardFocus is raised when the element loses keyboard focus. If the
PreviewGotKeyboardFocus event or the PreviewLostKeyboardFocusEvent event is
handled and Handled is set to true , then focus will not change.

The following example attaches GotKeyboardFocus and LostKeyboardFocus event


handlers to a TextBox.

XAML

<Border BorderBrush="Black" BorderThickness="1"


Width="200" Height="100" Margin="5">
<StackPanel>
<Label HorizontalAlignment="Center" Content="Type Text In This TextBox"
/>
<TextBox Width="175"
Height="50"
Margin="5"
TextWrapping="Wrap"
HorizontalAlignment="Center"
VerticalScrollBarVisibility="Auto"
GotKeyboardFocus="TextBoxGotKeyboardFocus"
LostKeyboardFocus="TextBoxLostKeyboardFocus"
KeyDown="SourceTextKeyDown"/>
</StackPanel>
</Border>

When the TextBox obtains keyboard focus, the Background property of the TextBox is
changed to LightBlue.

C#

private void TextBoxGotKeyboardFocus(object sender,


KeyboardFocusChangedEventArgs e)
{
TextBox source = e.Source as TextBox;

if (source != null)
{
// Change the TextBox color when it obtains focus.
source.Background = Brushes.LightBlue;

// Clear the TextBox.


source.Clear();
}
}

When the TextBox loses keyboard focus, the Background property of the TextBox is
changed back to white.

C#

private void TextBoxLostKeyboardFocus(object sender,


KeyboardFocusChangedEventArgs e)
{
TextBox source = e.Source as TextBox;

if (source != null)
{
// Change the TextBox color when it loses focus.
source.Background = Brushes.White;

// Set the hit counter back to zero and updates the display.
this.ResetCounter();
}
}
The events related to logical focus are GotFocus and LostFocus. These events are
defined on the FocusManager as attached events, but the FocusManager does not
expose CLR event wrappers. UIElement and ContentElement expose these events more
conveniently.

See also
FocusManager
UIElement
ContentElement
Input Overview
Base Elements Overview
Styling for Focus in Controls, and
FocusVisualStyle
Article • 02/06/2023

Windows Presentation Foundation (WPF) provides two parallel mechanisms for


changing the visual appearance of a control when it receives keyboard focus. The first
mechanism is to use property setters for properties such as IsKeyboardFocused within
the style or template that is applied to the control. The second mechanism is to provide
a separate style as the value of the FocusVisualStyle property; the "focus visual style"
creates a separate visual tree for an adorner that draws on top of the control, rather
than changing the visual tree of the control or other UI element by replacing it. This
topic discusses the scenarios where each of these mechanisms is appropriate.

The Purpose of Focus Visual Style


The focus visual style feature provides a common "object model" for introducing visual
user feedback based on keyboard navigation to any UI element. This is possible without
applying a new template to the control, or knowing the specific template composition.

However, precisely because the focus visual style feature works without knowing the
control templates, the visual feedback that can be displayed for a control using a focus
visual style is necessarily limited. What the feature actually does is to overlay a different
visual tree (an adorner) on top of the visual tree as created by a control's rendering
through its template. You define this separate visual tree using a style that fills the
FocusVisualStyle property.

Default Focus Visual Style Behavior


Focus visual styles act only when the focus action was initiated by the keyboard. Any
mouse action or programmatic focus change disables the mode for focus visual styles.
For more information about the distinctions between focus modes, see Focus Overview.

The themes for controls include a default focus visual style behavior that becomes the
focus visual style for all controls in the theme. This theme style is identified by the value
of the static key FocusVisualStyleKey. When you declare your own focus visual style at
the application level, you replace this default style behavior from the themes.
Alternatively, if you define the entire theme, then you should use this same key to define
the style for the default behavior for your entire theme.
In the themes, the default focus visual style is generally very simple. The following is a
rough approximation:

XAML

<Style x:Key="{x:Static SystemParameters.FocusVisualStyleKey}">


<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle StrokeThickness="1"
Stroke="Black"
StrokeDashArray="1 2"
SnapsToDevicePixels="true"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

When to Use Focus Visual Styles


Conceptually, the appearance of focus visual styles applied to controls should be
coherent from control to control. One way to ensure coherence is to change the focus
visual style only if you are composing an entire theme, where each control that is
defined in the theme gets either the very same focus visual style, or some variation of a
style that is visually related from control to control. Alternatively, you might use the
same style (or similar styles) to style every keyboard-focusable element on a page or in
a UI.

Setting FocusVisualStyle on individual control styles that are not part of a theme is not
the intended usage of focus visual styles. This is because an inconsistent visual behavior
between controls can lead to a confusing user experience regarding keyboard focus. If
you are intending control-specific behaviors for keyboard focus that are deliberately not
coherent across a theme, a much better approach is to use triggers in styles for
individual input state properties, such as IsFocused or IsKeyboardFocused.

Focus visual styles act exclusively for keyboard focus. As such, focus visual styles are a
type of accessibility feature. If you want UI changes for any type of focus, whether via
mouse, keyboard, or programmatically, then you should not use focus visual styles, and
should instead use setters and triggers in styles or templates that are working from the
value of general focus properties such as IsFocused or IsKeyboardFocusWithin.

How to Create a Focus Visual Style


The style you create for a focus visual style should always have the TargetType of
Control. The style should consist mainly of a ControlTemplate. You do not specify the
target type to be the type where the focus visual style is assigned to the
FocusVisualStyle.

Because the target type is always Control, you must style by using properties that are
common to all controls (using properties of the Control class and its base classes). You
should create a template that will properly function as an overlay to a UI element and
that will not obscure functional areas of the control. Generally, this means that the visual
feedback should appear outside the control margins, or as temporary or unobtrusive
effects that will not block the hit testing on the control where the focus visual style is
applied. Properties that you can use in template binding that are useful for determining
sizing and positioning of your overlay template include ActualHeight, ActualWidth,
Margin, and Padding.

Alternatives to Using a Focus Visual Style


For situations where using a focus visual style is not appropriate, either because you are
only styling single controls or because you want greater control over the control
template, there are many other accessible properties and techniques that can create
visual behavior in response to changes in focus.

Triggers, setters, and event setters are all discussed in detail in Styling and Templating.
Routed event handling is discussed in Routed Events Overview.

IsKeyboardFocused
If you are specifically interested in keyboard focus, the IsKeyboardFocused dependency
property can be used for a property Trigger. A property trigger in either a style or
template is a more appropriate technique for defining a keyboard focus behavior that is
very specifically for a single control, and which might not visually match the keyboard
focus behavior for other controls.

Another similar dependency property is IsKeyboardFocusWithin, which might be


appropriate to use if you want to visually call out that keyboard focus is somewhere
within compositing or within the functional area of the control. For example, you might
place an IsKeyboardFocusWithin trigger such that a panel that groups several controls
appears differently, even though keyboard focus might more precisely be on an
individual element within that panel.

You can also use the events GotKeyboardFocus and LostKeyboardFocus (as well as their
Preview equivalents). You can use these events as the basis for an EventSetter, or you
can write handlers for the events in code-behind.

Other Focus Properties


If you want all possible causes of changing focus to produce a visual behavior, you
should base a setter or trigger on the IsFocused dependency property, or alternatively
on the GotFocus or LostFocus events used for an EventSetter.

See also
FocusVisualStyle
Styling and Templating
Focus Overview
Input Overview
Walkthrough: Creating Your First Touch
Application
Article • 02/06/2023

WPF enables applications to respond to touch. For example, you can interact with an
application by using one or more fingers on a touch-sensitive device, such as a
touchscreen This walkthrough creates an application that enables the user to move,
resize, or rotate a single object by using touch.

Prerequisites
You need the following components to complete this walkthrough:

Visual Studio.

A device that accepts touch input, such as a touchscreen, that supports Windows
Touch.

Additionally, you should have a basic understanding of how to create an application in


WPF, especially how to subscribe to and handle an event. For more information, see
Walkthrough: My first WPF desktop application.

Creating the Application

To create the application

1. Create a new WPF Application project in Visual Basic or Visual C# named


BasicManipulation . For more information, see Walkthrough: My first WPF desktop

application.

2. Replace the contents of MainWindow.xaml with the following XAML.

This markup creates a simple application that contains a red Rectangle on a


Canvas. The IsManipulationEnabled property of the Rectangle is set to true so that
it will receive manipulation events. The application subscribes to the
ManipulationStarting, ManipulationDelta, and ManipulationInertiaStarting events.
These events contain the logic to move the Rectangle when the user manipulates
it.

XAML
<Window x:Class="BasicManipulation.MainWindow"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Move, Size, and Rotate the Square"
WindowState="Maximized"
ManipulationStarting="Window_ManipulationStarting"
ManipulationDelta="Window_ManipulationDelta"
ManipulationInertiaStarting="Window_InertiaStarting">
<Window.Resources>

<!--The movement, rotation, and size of the Rectangle is


specified by its RenderTransform.-->
<MatrixTransform x:Key="InitialMatrixTransform">
<MatrixTransform.Matrix>
<Matrix OffsetX="200" OffsetY="200"/>
</MatrixTransform.Matrix>
</MatrixTransform>

</Window.Resources>

<Canvas>
<Rectangle Fill="Red" Name="manRect"
Width="200" Height="200"
RenderTransform="{StaticResource
InitialMatrixTransform}"
IsManipulationEnabled="true" />
</Canvas>
</Window>

3. If you are using Visual Basic, in the first line of MainWindow.xaml, replace
x:Class="BasicManipulation.MainWindow" with x:Class="MainWindow" .

4. In the MainWindow class, add the following ManipulationStarting event handler.

The ManipulationStarting event occurs when WPF detects that touch input begins
to manipulate an object. The code specifies that the position of the manipulation
should be relative to the Window by setting the ManipulationContainer property.

C#

void Window_ManipulationStarting(object sender,


ManipulationStartingEventArgs e)
{
e.ManipulationContainer = this;
e.Handled = true;
}

5. In the MainWindow class, add the following ManipulationDelta event handler.


The ManipulationDelta event occurs when the touch input changes position and
can occur multiple times during a manipulation. The event can also occur after a
finger is raised. For example, if the user drags a finger across a screen, the
ManipulationDelta event occurs multiple times as the finger moves. When the user
raises a finger from the screen, the ManipulationDelta event keeps occurring to
simulate inertia.

The code applies the DeltaManipulation to the RenderTransform of the Rectangle


to move it as the user moves the touch input. It also checks whether the Rectangle
is outside the bounds of the Window when the event occurs during inertia. If so,
the application calls the ManipulationDeltaEventArgs.Complete method to end the
manipulation.

C#

void Window_ManipulationDelta(object sender, ManipulationDeltaEventArgs


e)
{

// Get the Rectangle and its RenderTransform matrix.


Rectangle rectToMove = e.OriginalSource as Rectangle;
Matrix rectsMatrix =
((MatrixTransform)rectToMove.RenderTransform).Matrix;

// Rotate the Rectangle.


rectsMatrix.RotateAt(e.DeltaManipulation.Rotation,
e.ManipulationOrigin.X,
e.ManipulationOrigin.Y);

// Resize the Rectangle. Keep it square


// so use only the X value of Scale.
rectsMatrix.ScaleAt(e.DeltaManipulation.Scale.X,
e.DeltaManipulation.Scale.X,
e.ManipulationOrigin.X,
e.ManipulationOrigin.Y);

// Move the Rectangle.


rectsMatrix.Translate(e.DeltaManipulation.Translation.X,
e.DeltaManipulation.Translation.Y);

// Apply the changes to the Rectangle.


rectToMove.RenderTransform = new MatrixTransform(rectsMatrix);

Rect containingRect =
new
Rect(((FrameworkElement)e.ManipulationContainer).RenderSize);

Rect shapeBounds =
rectToMove.RenderTransform.TransformBounds(
new Rect(rectToMove.RenderSize));
// Check if the rectangle is completely in the window.
// If it is not and intertia is occuring, stop the manipulation.
if (e.IsInertial && !containingRect.Contains(shapeBounds))
{
e.Complete();
}

e.Handled = true;
}

6. In the MainWindow class, add the following ManipulationInertiaStarting event


handler.

The ManipulationInertiaStarting event occurs when the user raises all fingers from
the screen. The code sets the initial velocity and deceleration for the movement,
expansion, and rotation of the rectangle.

C#

void Window_InertiaStarting(object sender,


ManipulationInertiaStartingEventArgs e)
{

// Decrease the velocity of the Rectangle's movement by


// 10 inches per second every second.
// (10 inches * 96 pixels per inch / 1000ms^2)
e.TranslationBehavior.DesiredDeceleration = 10.0 * 96.0 / (1000.0 *
1000.0);

// Decrease the velocity of the Rectangle's resizing by


// 0.1 inches per second every second.
// (0.1 inches * 96 pixels per inch / (1000ms^2)
e.ExpansionBehavior.DesiredDeceleration = 0.1 * 96 / (1000.0 *
1000.0);

// Decrease the velocity of the Rectangle's rotation rate by


// 2 rotations per second every second.
// (2 * 360 degrees / (1000ms^2)
e.RotationBehavior.DesiredDeceleration = 720 / (1000.0 * 1000.0);

e.Handled = true;
}

7. Build and run the project.

You should see a red square appear in the window.

Testing the Application


To test the application, try the following manipulations. Note that you can do more than
one of the following at the same time.

To move the Rectangle, put a finger on the Rectangle and move the finger across
the screen.

To resize the Rectangle, put two fingers on the Rectangle and move the fingers
closer together or farther apart from each other.

To rotate the Rectangle, put two fingers on the Rectangle and rotate the fingers
around each other.

To cause inertia, quickly raise your fingers from the screen as you perform the previous
manipulations. The Rectangle will continue to move, resize, or rotate for a few seconds
before it stops.

See also
UIElement.ManipulationStarting
UIElement.ManipulationDelta
UIElement.ManipulationInertiaStarting
Input and Commands How-to Topics
Article • 02/06/2023

The topics in this section describe how to use the input and commanding infrastructure
in Windows Presentation Foundation (WPF).

In This Section
Enable a Command
Change the Cursor Type
Change the Color of an Element Using Focus Events
Apply a FocusVisualStyle to a Control
Detect When the Enter Key is Pressed
Create a Rollover Effect Using Events
Make an Object Follow the Mouse Pointer
Create a RoutedCommand
Implement ICommandSource
Hook Up a Command to a Control with No Command Support
Hook Up a Command to a Control with Command Support

Reference
UIElement

FrameworkElement

ContentElement

FrameworkContentElement

Keyboard

Mouse

FocusManager

Related Sections
How to: Enable a Command
Article • 02/06/2023

The following example demonstrates how to use commanding in Windows Presentation


Foundation (WPF). The example shows how to associate a RoutedCommand to a Button,
create a CommandBinding, and create the event handlers which implement the
RoutedCommand. For more information on commanding, see the Commanding
Overview.

Example
The first section of code creates the user interface (UI), which consists of a Button and a
StackPanel, and creates a CommandBinding that associates the command handlers with
the RoutedCommand.

The Command property of the Button is associated with the Close command.

The CommandBinding is added to the CommandBindingCollection of the root Window.


The Executed and CanExecute event handlers are attached to this binding and
associated with the Close command.

Without the CommandBinding there is no command logic, only a mechanism to invoke


the command. When the Button is clicked, the PreviewExecuted RoutedEvent is raised
on the command target followed by the Executed RoutedEvent. These events traverse
the element tree looking for a CommandBinding for that particular command. It is worth
noting that because RoutedEvent tunnel and bubble through the element tree, care
must be taken in where the CommandBinding is put. If the CommandBinding is on a
sibling of the command target or another node that is not on the route of the
RoutedEvent, the CommandBinding will not be accessed.

XAML

<Window x:Class="WCSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CloseCommand"
Name="RootWindow"
>
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Close"
Executed="CloseCommandHandler"
CanExecute="CanExecuteHandler"
/>
</Window.CommandBindings>
<StackPanel Name="MainStackPanel">
<Button Command="ApplicationCommands.Close"
Content="Close File" />
</StackPanel>
</Window>

C#

// Create ui elements.
StackPanel CloseCmdStackPanel = new StackPanel();
Button CloseCmdButton = new Button();
CloseCmdStackPanel.Children.Add(CloseCmdButton);

// Set Button's properties.


CloseCmdButton.Content = "Close File";
CloseCmdButton.Command = ApplicationCommands.Close;

// Create the CommandBinding.


CommandBinding CloseCommandBinding = new CommandBinding(
ApplicationCommands.Close, CloseCommandHandler, CanExecuteHandler);

// Add the CommandBinding to the root Window.


RootWindow.CommandBindings.Add(CloseCommandBinding);

The next section of code implements the Executed and CanExecute event handlers.

The Executed handler calls a method to close the open file. The CanExecute handler calls
a method to determine whether a file is open. If a file is open, CanExecute is set to true ;
otherwise, it is set to false .

C#

// Executed event handler.


private void CloseCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
// Calls a method to close the file and release resources.
CloseFile();
}

// CanExecute event handler.


private void CanExecuteHandler(object sender, CanExecuteRoutedEventArgs e)
{
// Call a method to determine if there is a file open.
// If there is a file open, then set CanExecute to true.
if (IsFileOpened())
{
e.CanExecute = true;
}
// if there is not a file open, then set CanExecute to false.
else
{
e.CanExecute = false;
}
}

See also
Commanding Overview
How to: Change the Cursor Type
Article • 02/06/2023

This example shows how to change the Cursor of the mouse pointer for a specific
element and for the application.

This example consists of a Extensible Application Markup Language (XAML) file and a
code behind file.

Example
The user interface is created, which consists of a ComboBox to select the desired Cursor,
a pair of RadioButton objects to determine if the cursor change applies to only a single
element or applies to the entire application, and a Border which is the element that the
new cursor is applied to.

XAML

<StackPanel>
<Border Width="300">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<StackPanel Margin="10">
<Label HorizontalAlignment="Left">Cursor Type</Label>
<ComboBox Width="100"
SelectionChanged="CursorTypeChanged"
HorizontalAlignment="Left"
Name="CursorSelector">
<ComboBoxItem Content="AppStarting" />
<ComboBoxItem Content="ArrowCD" />
<ComboBoxItem Content="Arrow" />
<ComboBoxItem Content="Cross" />
<ComboBoxItem Content="HandCursor" />
<ComboBoxItem Content="Help" />
<ComboBoxItem Content="IBeam" />
<ComboBoxItem Content="No" />
<ComboBoxItem Content="None" />
<ComboBoxItem Content="Pen" />
<ComboBoxItem Content="ScrollSE" />
<ComboBoxItem Content="ScrollWE" />
<ComboBoxItem Content="SizeAll" />
<ComboBoxItem Content="SizeNESW" />
<ComboBoxItem Content="SizeNS" />
<ComboBoxItem Content="SizeNWSE" />
<ComboBoxItem Content="SizeWE" />
<ComboBoxItem Content="UpArrow" />
<ComboBoxItem Content="WaitCursor" />
<ComboBoxItem Content="Custom" />
</ComboBox>
</StackPanel>
<!-- The user can select different cursor types using this ComboBox --
>
<StackPanel Margin="10">
<Label HorizontalAlignment="Left">Scope of Cursor</Label>
<StackPanel>
<RadioButton Name="rbScopeElement" IsChecked="True"
Checked="CursorScopeSelected">Display Area
Only</RadioButton>
<RadioButton Name="rbScopeApplication"
Checked="CursorScopeSelected">Entire
Appliation</RadioButton>
</StackPanel>
</StackPanel>
</StackPanel>
</Border>
<!-- When the mouse pointer is over this Border -->
<!-- the selected cursor type is shown -->
<Border Name="DisplayArea" Height="250" Width="400"
Margin="20" Background="AliceBlue">
<Label HorizontalAlignment="Center">
Move Mouse Pointer Over This Area
</Label>
</Border>
</StackPanel>

The following code behind creates a SelectionChanged event handler which is called
when the cursor type is changed in the ComboBox. A switch statement filters on the
cursor name and sets the Cursor property on the Border which is named DisplayArea.

If the cursor change is set to "Entire Application", the OverrideCursor property is set to
the Cursor property of the Border control. This forces the cursor to change for the whole
application.

C#

private void CursorTypeChanged(object sender, SelectionChangedEventArgs e)


{
ComboBox source = e.Source as ComboBox;

if (source != null)
{
ComboBoxItem selectedCursor = source.SelectedItem as ComboBoxItem;

// Changing the cursor of the Border control


// by setting the Cursor property
switch (selectedCursor.Content.ToString())
{
case "AppStarting":
DisplayArea.Cursor = Cursors.AppStarting;
break;
case "ArrowCD":
DisplayArea.Cursor = Cursors.ArrowCD;
break;
case "Arrow":
DisplayArea.Cursor = Cursors.Arrow;
break;
case "Cross":
DisplayArea.Cursor = Cursors.Cross;
break;
case "HandCursor":
DisplayArea.Cursor = Cursors.Hand;
break;
case "Help":
DisplayArea.Cursor = Cursors.Help;
break;
case "IBeam":
DisplayArea.Cursor = Cursors.IBeam;
break;
case "No":
DisplayArea.Cursor = Cursors.No;
break;
case "None":
DisplayArea.Cursor = Cursors.None;
break;
case "Pen":
DisplayArea.Cursor = Cursors.Pen;
break;
case "ScrollSE":
DisplayArea.Cursor = Cursors.ScrollSE;
break;
case "ScrollWE":
DisplayArea.Cursor = Cursors.ScrollWE;
break;
case "SizeAll":
DisplayArea.Cursor = Cursors.SizeAll;
break;
case "SizeNESW":
DisplayArea.Cursor = Cursors.SizeNESW;
break;
case "SizeNS":
DisplayArea.Cursor = Cursors.SizeNS;
break;
case "SizeNWSE":
DisplayArea.Cursor = Cursors.SizeNWSE;
break;
case "SizeWE":
DisplayArea.Cursor = Cursors.SizeWE;
break;
case "UpArrow":
DisplayArea.Cursor = Cursors.UpArrow;
break;
case "WaitCursor":
DisplayArea.Cursor = Cursors.Wait;
break;
case "Custom":
DisplayArea.Cursor = CustomCursor;
break;
default:
break;
}

// If the cursor scope is set to the entire application


// Use OverrideCursor to force the cursor for all elements
if (cursorScopeElementOnly == false)
{
Mouse.OverrideCursor = DisplayArea.Cursor;
}
}
}

See also
Input Overview
How to: Change the Color of an Element
Using Focus Events
Article • 02/06/2023

This example shows how to change the color of an element when it gains and loses
focus by using the GotFocus and LostFocus events.

This example consists of a Extensible Application Markup Language (XAML) file and a
code-behind file.

Example
The following XAML creates the user interface, which consists of two Button objects, and
attaches event handlers for the GotFocus and LostFocus events to the Button objects.

XAML

<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Height" Value="20"/>
<Setter Property="Width" Value="250"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style>
</StackPanel.Resources>
<Button
GotFocus="OnGotFocusHandler"
LostFocus="OnLostFocusHandler">Click Or Tab To Give Keyboard
Focus</Button>
<Button
GotFocus="OnGotFocusHandler"
LostFocus="OnLostFocusHandler">Click Or Tab To Give Keyborad
Focus</Button>
</StackPanel>

The following code behind creates the GotFocus and LostFocus event handlers. When
the Button gains keyboard focus, the Background of the Button is changed to red. When
the Button loses keyboard focus, the Background of the Button is changed back to
white.

C#

public partial class Window1 : Window


{
public Window1()
{
InitializeComponent();
}

// Raised when Button gains focus.


// Changes the color of the Button to Red.
private void OnGotFocusHandler(object sender, RoutedEventArgs e)
{
Button tb = e.Source as Button;
tb.Background = Brushes.Red;
}
// Raised when Button losses focus.
// Changes the color of the Button back to white.
private void OnLostFocusHandler(object sender, RoutedEventArgs e)
{
Button tb = e.Source as Button;
tb.Background = Brushes.White;
}
}

See also
Input Overview
How to: Apply a FocusVisualStyle to a
Control
Article • 02/06/2023

This example shows you how to create a focus visual style in resources and apply the
style to a control, using the FocusVisualStyle property.

Example
The following example defines a style that creates additional control compositing that
only applies when that control is keyboard focused in the user interface (UI). This is
accomplished by defining a style with a ControlTemplate, then referencing that style as a
resource when setting the FocusVisualStyle property.

An external rectangle resembling a border is placed outside of the rectangular area.


Unless otherwise modified, the sizing of the style uses the ActualHeight and
ActualWidth of the rectangular control where the focus visual style is applied. This
example sets negative values for the Margin to make the border appear slightly outside
the focused control.

XAML

<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Page.Resources>
<Style x:Key="MyFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="-2" StrokeThickness="1" Stroke="Red"
StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<StackPanel Background="Ivory" Orientation="Horizontal">
<Canvas Width="10"/>
<Button Width="100" Height="30" FocusVisualStyle="{DynamicResource
MyFocusVisual}">
Focus Here</Button>
<Canvas Width="100"/>
<Button Width="100" Height="30" FocusVisualStyle="{DynamicResource
MyFocusVisual}">
Focus Here</Button>
</StackPanel>
</Page>

A FocusVisualStyle is additive to any control template style that comes either from an
explicit style or a theme style; the primary style for a control can still be created by using
a ControlTemplate and setting that style to the Style property.

Focus visual styles should be used consistently across a theme or a UI, rather than using
a different one for each focusable element. For details, see Styling for Focus in Controls,
and FocusVisualStyle.

See also
FocusVisualStyle
Styling and Templating
Styling for Focus in Controls, and FocusVisualStyle
How to: Detect When the Enter Key
Pressed
Article • 02/06/2023

This example shows how to detect when the Enter key is pressed on the keyboard.

This example consists of a Extensible Application Markup Language (XAML) file and a
code-behind file.

Example
When the user presses the Enter key in the TextBox, the input in the text box appears in
another area of the user interface (UI).

The following XAML creates the user interface, which consists of a StackPanel, a
TextBlock, and a TextBox.

XAML

<StackPanel>
<TextBlock Width="300" Height="20">
Type some text into the TextBox and press the Enter key.
</TextBlock>
<TextBox Width="300" Height="30" Name="textBox1"
KeyDown="OnKeyDownHandler"/>
<TextBlock Width="300" Height="100" Name="textBlock1"/>
</StackPanel>

The following code behind creates the KeyDown event handler. If the key that is pressed
is the Enter key, a message is displayed in the TextBlock.

C#

private void OnKeyDownHandler(object sender, KeyEventArgs e)


{
if (e.Key == Key.Return)
{
textBlock1.Text = "You Entered: " + textBox1.Text;
}
}

See also
Input Overview
Routed Events Overview
How to: Create a Rollover Effect Using
Events
Article • 02/06/2023

This example shows how to change the color of an element as the mouse pointer enters
and leaves the area occupied by the element.

This example consists of a Extensible Application Markup Language (XAML) file and a
code-behind file.

7 Note

This example demonstrates how to use events, but the recommended way to
achieve this same effect is to use a Trigger in a style. For more information, see
Styling and Templating.

Example
The following XAML creates the user interface, which consists of Border around a
TextBlock, and attaches the MouseEnter and MouseLeave event handlers to the Border.

XAML

<StackPanel>
<Border MouseEnter="OnMouseEnterHandler"
MouseLeave="OnMouseLeaveHandler"
Name="border1" Margin="10"
BorderThickness="1"
BorderBrush="Black"
VerticalAlignment="Center"
Width="300" Height="100">
<Label Margin="10" FontSize="14"
HorizontalAlignment="Center">Move Cursor Over Me</Label>
</Border>
</StackPanel>

The following code behind creates the MouseEnter and MouseLeave event handlers.
When the mouse pointer enters the Border, the background of the Border is changed to
red. When the mouse pointer leaves the Border, the background of the Border is
changed back to white.

C#
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}

// raised when mouse cursor enters the area occupied by the element
void OnMouseEnterHandler(object sender, MouseEventArgs e)
{
border1.Background = Brushes.Red;
}

// raised when mouse cursor leaves the area occupied by the element
void OnMouseLeaveHandler(object sender, MouseEventArgs e)
{
border1.Background = Brushes.White;
}
}
How to: Make an Object Follow the
Mouse Pointer
Article • 08/10/2023

This example shows how to change the dimensions of an object when the mouse
pointer moves on the screen.

The example includes an Extensible Application Markup Language (XAML) file that
creates the user interface (UI) and a code-behind file that creates the event handler.

Example
The following XAML creates the UI, which consists of an Ellipse inside of a StackPanel,
and attaches the event handler for the MouseMove event.

XAML

<Window x:Class="WCSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="mouseMoveWithPointer"
Height="400"
Width="500"
>
<Canvas MouseMove="MouseMoveHandler"
Background="LemonChiffon">
<Ellipse Name="ellipse" Fill="LightBlue"
Width="100" Height="100"/>
</Canvas>
</Window>

The following code behind creates the MouseMove event handler. When the mouse
pointer moves, the height and the width of the Ellipse are increased and decreased.

C#

// raised when the mouse pointer moves.


// Expands the dimensions of an Ellipse when the mouse moves.
private void MouseMoveHandler(object sender, MouseEventArgs e)
{
// Get the x and y coordinates of the mouse pointer.
System.Windows.Point position = e.GetPosition(this);
double pX = position.X;
double pY = position.Y;
// Sets the Height/Width of the circle to the mouse coordinates.
ellipse.Width = pX;
ellipse.Height = pY;
}

See also
Input Overview
How to: Create a RoutedCommand
Article • 02/06/2023

This example shows how to create a custom RoutedCommand and how to implement
the custom command by creating a ExecutedRoutedEventHandler and a
CanExecuteRoutedEventHandler and attaching them to a CommandBinding. For more
information on commanding, see the Commanding Overview.

Example
The first step in creating a RoutedCommand is defining the command and instantiating
it.

C#

public static RoutedCommand CustomRoutedCommand = new RoutedCommand();

In order to use the command in an application, event handlers which define what the
command does must be created

C#

private void ExecutedCustomCommand(object sender,


ExecutedRoutedEventArgs e)
{
MessageBox.Show("Custom Command Executed");
}

C#

// CanExecuteRoutedEventHandler that only returns true if


// the source is a control.
private void CanExecuteCustomCommand(object sender,
CanExecuteRoutedEventArgs e)
{
Control target = e.Source as Control;

if(target != null)
{
e.CanExecute = true;
}
else
{
e.CanExecute = false;
}
}

Next, a CommandBinding is created which associates the command with the event
handlers. The CommandBinding is created on a specific object. This object defines the
scope of the CommandBinding in the element tree

XAML

<Window x:Class="SDKSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:SDKSamples"
Height="600" Width="800"
>
<Window.CommandBindings>
<CommandBinding Command="{x:Static custom:Window1.CustomRoutedCommand}"
Executed="ExecutedCustomCommand"
CanExecute="CanExecuteCustomCommand" />
</Window.CommandBindings>

C#

CommandBinding customCommandBinding = new CommandBinding(


CustomRoutedCommand, ExecutedCustomCommand, CanExecuteCustomCommand);

// attach CommandBinding to root window


this.CommandBindings.Add(customCommandBinding);

The final step is invoking the command. One way to invoke a command is to associate it
with a ICommandSource, such as a Button.

XAML

<StackPanel>
<Button Command="{x:Static custom:Window1.CustomRoutedCommand}"
Content="CustomRoutedCommand"/>
</StackPanel>

C#

// create the ui
StackPanel CustomCommandStackPanel = new StackPanel();
Button CustomCommandButton = new Button();
CustomCommandStackPanel.Children.Add(CustomCommandButton);

CustomCommandButton.Command = CustomRoutedCommand;
When the Button is clicked, the Execute method on the custom RoutedCommand is
called. The RoutedCommand raises the PreviewExecuted and Executed routed events.
These events traverse the element tree looking for a CommandBinding for this particular
command. If a CommandBinding is found, the ExecutedRoutedEventHandler associated
with CommandBinding is called.

See also
RoutedCommand
Commanding Overview
How to: Implement ICommandSource
Article • 07/27/2022

This example shows how to create a command source by implementing


ICommandSource. A command source is an object that knows how to invoke a
command. The ICommandSource interface exposes three members:

Command: the command that will be invoked.


CommandParameter: a user-defined data type which is passed from the command
source to the method that handles the command.
CommandTarget: the object that the command is being executed on.

In this example, a class is created that inherits from the Slider control and implements
the ICommandSource interface.

Example
WPF provides a number of classes which implement ICommandSource, such as Button,
MenuItem, and Hyperlink. A command source defines how it invokes a command. These
classes invoke a command when they're clicked and they only become a command
source when their Command property is set.

In this example, you'll invoke the command when the slider is moved, or more
accurately, when the Value property is changed.

The following is the class definition:

C#

public class CommandSlider : Slider, ICommandSource


{
public CommandSlider() : base()
{
}

The next step is to implement the ICommandSource members. In this example, the
properties are implemented as DependencyProperty objects. This enables the properties
to use data binding. For more information about the DependencyProperty class, see the
Dependency Properties Overview. For more information about data binding, see the
Data Binding Overview.

Only the Command property is shown here.


C#

// Make Command a dependency property so it can use databinding.


public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(
"Command",
typeof(ICommand),
typeof(CommandSlider),
new PropertyMetadata((ICommand)null,
new PropertyChangedCallback(CommandChanged)));

public ICommand Command


{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}

The following is the DependencyProperty change callback:

C#

// Command dependency property change callback.


private static void CommandChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
CommandSlider cs = (CommandSlider)d;
cs.HookUpCommand((ICommand)e.OldValue,(ICommand)e.NewValue);
}

The next step is to add and remove the command which is associated with the
command source. The Command property cannot simply be overwritten when a new
command is added, because the event handlers associated with the previous command,
if there was one, must be removed first.

C#

// Add a new command to the Command Property.


private void HookUpCommand(ICommand oldCommand, ICommand newCommand)
{
// If oldCommand is not null, then we need to remove the handlers.
if (oldCommand != null)
{
RemoveCommand(oldCommand, newCommand);
}
AddCommand(oldCommand, newCommand);
}

// Remove an old command from the Command Property.


private void RemoveCommand(ICommand oldCommand, ICommand newCommand)
{
EventHandler handler = CanExecuteChanged;
oldCommand.CanExecuteChanged -= handler;
}

// Add the command.


private void AddCommand(ICommand oldCommand, ICommand newCommand)
{
EventHandler handler = new EventHandler(CanExecuteChanged);
canExecuteChangedHandler = handler;
if (newCommand != null)
{
newCommand.CanExecuteChanged += canExecuteChangedHandler;
}
}

The next step is to create logic for the CanExecuteChanged handler.

The CanExecuteChanged event notifies the command source that the ability of the
command to execute on the current command target may have changed. When a
command source receives this event, it typically calls the CanExecute method on the
command. If the command cannot execute on the current command target, the
command source will typically disable itself. If the command can execute on the current
command target, the command source will typically enable itself.

C#

private void CanExecuteChanged(object sender, EventArgs e)


{

if (this.Command != null)
{
RoutedCommand command = this.Command as RoutedCommand;

// If a RoutedCommand.
if (command != null)
{
if (command.CanExecute(CommandParameter, CommandTarget))
{
this.IsEnabled = true;
}
else
{
this.IsEnabled = false;
}
}
// If a not RoutedCommand.
else
{
if (Command.CanExecute(CommandParameter))
{
this.IsEnabled = true;
}
else
{
this.IsEnabled = false;
}
}
}
}

The last step is the Execute method. If the command is a RoutedCommand, the
RoutedCommand Execute method is called; otherwise, the ICommand Execute method
is called.

C#

// If Command is defined, moving the slider will invoke the command;


// Otherwise, the slider will behave normally.
protected override void OnValueChanged(double oldValue, double newValue)
{
base.OnValueChanged(oldValue, newValue);

if (this.Command != null)
{
RoutedCommand command = Command as RoutedCommand;

if (command != null)
{
command.Execute(CommandParameter, CommandTarget);
}
else
{
((ICommand)Command).Execute(CommandParameter);
}
}
}

See also
ICommandSource
ICommand
RoutedCommand
Commanding Overview
How to: Hook Up a Command to a
Control with No Command Support
Article • 02/06/2023

The following example shows how to hook up a RoutedCommand to a Control which


does not have built in support for the command. For a complete sample which hooks up
commands to multiple sources, see the Create a Custom RoutedCommand Sample
sample.

Example
Windows Presentation Foundation (WPF) provides a library of common commands
which application programmers encounter regularly. The classes which comprise the
command library are: ApplicationCommands, ComponentCommands,
NavigationCommands, MediaCommands, and EditingCommands.

The static RoutedCommand objects which make up these classes do not supply
command logic. The logic for the command is associated with the command with a
CommandBinding. Many controls in WPF have built in support for some of the
commands in the command library. TextBox, for example, supports many of the
application edit commands such as Paste, Copy, Cut, Redo, and Undo. The application
developer does not have to do anything special to get these commands to work with
these controls. If the TextBox is the command target when the command is executed, it
will handle the command using the CommandBinding that is built into the control.

The following shows how to use a Button as the command source for the Open
command. A CommandBinding is created that associates the specified
CanExecuteRoutedEventHandler and the CanExecuteRoutedEventHandler with the
RoutedCommand.

First, the command source is created. A Button is used as the command source.

XAML

<Button Command="ApplicationCommands.Open" Name="MyButton"


Height="50" Width="200">
Open (KeyBindings: Ctrl+R, Ctrl+0)
</Button>

C#
// Button used to invoke the command
Button CommandButton = new Button();
CommandButton.Command = ApplicationCommands.Open;
CommandButton.Content = "Open (KeyBindings: Ctrl-R, Ctrl-0)";
MainStackPanel.Children.Add(CommandButton);

Next, the ExecutedRoutedEventHandler and the CanExecuteRoutedEventHandler are


created. The ExecutedRoutedEventHandler simply opens a MessageBox to signify that
the command executed. The CanExecuteRoutedEventHandler sets the CanExecute
property to true . Normally, the can execute handler would perform more robust checks
to see if the command could execute on the current command target.

C#

void OpenCmdExecuted(object target, ExecutedRoutedEventArgs e)


{
String command, targetobj;
command = ((RoutedCommand)e.Command).Name;
targetobj = ((FrameworkElement)target).Name;
MessageBox.Show("The " + command + " command has been invoked on target
object " + targetobj);
}
void OpenCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}

Finally, a CommandBinding is created on the root Window of the application that


associates the routed events handlers to the Open command.

XAML

<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Open"
Executed="OpenCmdExecuted"
CanExecute="OpenCmdCanExecute"/>
</Window.CommandBindings>

C#

// Creating CommandBinding and attaching an Executed and CanExecute handler


CommandBinding OpenCmdBinding = new CommandBinding(
ApplicationCommands.Open,
OpenCmdExecuted,
OpenCmdCanExecute);
this.CommandBindings.Add(OpenCmdBinding);

See also
Commanding Overview
Hook Up a Command to a Control with Command Support
How to: Hook Up a Command to a
Control with Command Support
Article • 02/06/2023

The following example shows how to hook up a RoutedCommand to a Control which


has built in support for the command. For a complete sample which hooks up
commands to multiple sources, see the Create a Custom RoutedCommand Sample
sample.

Example
Windows Presentation Foundation (WPF) provides a library of common commands
which application programmers encounter regularly. The classes which comprise the
command library are: ApplicationCommands, ComponentCommands,
NavigationCommands, MediaCommands, and EditingCommands.

The static RoutedCommand objects which make up these classes do not supply
command logic. The logic for the command is associated with the command with a
CommandBinding. Some controls have built in CommandBindings for some commands.
This mechanism allows the semantics of a command to stay the same, while the actual
implementation is can change. A TextBox, for example, handles the Paste command
differently than a control designed to support images, but the basic idea of what it
means to paste something stays the same. The command logic cannot be supplied by
the command, but rather must be supplied by the control or the application.

Many controls in WPF do have built in support for some of the commands in the
command library. TextBox, for example, supports many of the application edit
commands such as Paste, Copy, Cut, Redo, and Undo. The application developer does
not have to do anything special to get these commands to work with these controls. If
the TextBox is the command target when the command is executed, it will handle the
command using the CommandBinding that is built into the control.

The following shows how to use a MenuItem as the command source for the Paste
command, where a TextBox is the target of the command. All the logic that defines how
the TextBox performs the paste is built into the TextBox control.

A MenuItem is created and it's Command property is set to the Paste command. The
CommandTarget is not explicitly set to the TextBox object. When the CommandTarget is
not set, the target for the command is the element which has keyboard focus. If the
element which has keyboard focus does not support the Paste command or cannot
currently execute the paste command (the clipboard is empty, for example) then the
MenuItem would be grayed out.

XAML

<Window x:Class="SDKSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MenuItemCommandTask"
>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Command="ApplicationCommands.Paste" Width="75" />
</Menu>
<TextBox BorderBrush="Black" BorderThickness="2" Margin="25"
TextWrapping="Wrap">
The MenuItem will not be enabled until
this TextBox gets keyboard focus
</TextBox>
</DockPanel>
</Window>

C#

// Window1 constructor
public Window1()
{
InitializeComponent();

// Instantiating UIElements.
DockPanel mainPanel = new DockPanel();
Menu mainMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();
TextBox mainTextBox = new TextBox();

// Associating the MenuItem with the Paste command.


pasteMenuItem.Command = ApplicationCommands.Paste;

// Setting properties on the TextBox.


mainTextBox.Text =
"The MenuItem will not be enabled until this TextBox receives
keyboard focus.";
mainTextBox.Margin = new Thickness(25);
mainTextBox.BorderBrush = Brushes.Black;
mainTextBox.BorderThickness = new Thickness(2);
mainTextBox.TextWrapping = TextWrapping.Wrap;

// Attaching UIElements to the Window.


this.AddChild(mainPanel);
mainMenu.Items.Add(pasteMenuItem);
mainPanel.Children.Add(mainMenu);
mainPanel.Children.Add(mainTextBox);
// Defining DockPanel layout.
DockPanel.SetDock(mainMenu, Dock.Top);
DockPanel.SetDock(mainTextBox, Dock.Bottom);
}

See also
Commanding Overview
Hook Up a Command to a Control with No Command Support
Digital Ink
Article • 02/06/2023

This section discusses the use of digital ink in the WPF. Traditionally found only in the
Tablet PC SDK, digital ink is now available in the core Windows Presentation Foundation.
This means you can now develop full-fledged Tablet PC applications by using the power
of Windows Presentation Foundation.

In This Section
Overviews
How-to Topics

Related Sections
Windows Presentation Foundation
Digital Ink Overviews
Article • 02/06/2023

In This Section
Getting Started with Ink
Collecting Ink
Handwriting Recognition
Storing Ink
The Ink Object Model: Windows Forms and COM versus WPF
Advanced Ink Handling
Get Started with Ink in WPF
Article • 09/22/2022

Windows Presentation Foundation (WPF) has an ink feature that makes it easy to
incorporate digital ink into your app.

Prerequisites
To use the following examples, first install Visual Studio. It also helps to know how to
write basic WPF apps. For help getting started with WPF, see Walkthrough: My first WPF
desktop application.

Quick Start
This section helps you write a simple WPF application that collects ink.

Got Ink?
To create a WPF app that supports ink:

1. Open Visual Studio.

2. Create a new WPF App.

In the New Project dialog, expand the Installed > Visual C# or Visual Basic >
Windows Desktop category. Then, select the WPF App (.NET Framework) app
template. Enter a name, and then select OK.

Visual Studio creates the project, and MainWindow.xaml opens in the designer.

3. Type <InkCanvas/> between the <Grid> tags.


4. Press F5 to launch your application in the debugger.

5. Using a stylus or mouse, write hello world in the window.

You've written the ink equivalent of a "hello world" application with only 12 keystrokes!

Spice Up Your App


Let’s take advantage of some features of the WPF. Replace everything between the
opening and closing <Window> tags with the following markup:

XAML

<Page>
<InkCanvas Name="myInkCanvas" MouseRightButtonUp="RightMouseUpHandler">
<InkCanvas.Background>
<LinearGradientBrush>
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="Blue" Offset="0.5" />
<GradientStop Color="HotPink" Offset="1.0" />
</LinearGradientBrush>
</InkCanvas.Background>
</InkCanvas>
</Page>

This XAML creates a gradient brush background on your inking surface.

Add Some Code Behind the XAML


While XAML makes it very easy to design the user interface, any real-world application
needs to add code to handle events. Here is a simple example that zooms in on the ink
in response to a right-click from a mouse.

1. Set the MouseRightButtonUp handler in your XAML:

XAML

<InkCanvas Name="myInkCanvas" MouseRightButtonUp="RightMouseUpHandler">

2. In Solution Explorer, expand MainWindow.xaml and open the code-behind file


(MainWindow.xaml.cs or MainWindow.xaml.vb). Add the following event handler
code:

C#

private void RightMouseUpHandler(object sender,

System.Windows.Input.MouseButtonEventArgs e)
{
Matrix m = new Matrix();
m.Scale(1.1d, 1.1d);
((InkCanvas)sender).Strokes.Transform(m, true);
}
3. Run the application. Add some ink, and then right-click with the mouse or perform
a press-and-hold equivalent with a stylus.

The display zooms in each time you click with the right mouse button.

Use Procedural Code Instead of XAML


You can access all WPF features from procedural code. Follow these steps to create a
"Hello Ink World" application for WPF that doesn’t use any XAML at all.

1. Create a new console application project in Visual Studio.

In the New Project dialog, expand the Installed > Visual C# or Visual Basic >
Windows Desktop category. Then, select the Console App (.NET Framework) app
template. Enter a name, and then select OK.

2. Paste the following code into the Program.cs or Program.vb file:

C#

using System;
using System.Windows;
using System.Windows.Controls;
class Program : Application
{
Window win;
InkCanvas ic;

protected override void OnStartup(StartupEventArgs args)


{
base.OnStartup(args);
win = new Window();
ic = new InkCanvas();
win.Content = ic;
win.Show();
}

[STAThread]
static void Main(string[] args)
{
new Program().Run();
}
}

3. Add references to the PresentationCore, PresentationFramework, and


WindowsBase assemblies by right-clicking on References in Solution Explorer and
choosing Add Reference.
4. Build the application by pressing F5.

See also
Digital Ink
Collecting Ink
Handwriting Recognition
Storing Ink
Collect Ink
Article • 07/20/2022

The Windows Presentation Foundation platform collects digital ink as a core part of its
functionality. This topic discusses methods for collection of ink in Windows Presentation
Foundation (WPF).

Prerequisites
To use the following examples, you must first install Visual Studio and the Windows SDK.
You should also understand how to write applications for the WPF. For more information
about getting started with WPF, see Walkthrough: My first WPF desktop application.

Use the InkCanvas Element


The System.Windows.Controls.InkCanvas element provides the easiest way to collect ink
in WPF. Use an InkCanvas element to receive and display ink input. You commonly input
ink through the use of a stylus, which interacts with a digitizer to produce ink strokes. In
addition, a mouse can be used in place of a stylus. The created strokes are represented
as Stroke objects, and they can be manipulated both programmatically and by user
input. The InkCanvas enables users to select, modify, or delete an existing Stroke.

By using XAML, you can set up ink collection as easily as adding an InkCanvas element
to your tree. The following example adds an InkCanvas to a default WPF project created
in Visual Studio:

XAML

<Grid>
<InkCanvas/>
</Grid>

The InkCanvas element can also contain child elements, making it possible to add ink
annotation capabilities to almost any type of XAML element. For example, to add inking
capabilities to a text element, simply make it a child of an InkCanvas:

XAML

<InkCanvas>
<TextBlock>Show text here.</TextBlock>
</InkCanvas>
Adding support for marking up an image with ink is just as easy:

XAML

<InkCanvas>
<Image Source="myPicture.jpg"/>
</InkCanvas>

InkCollection Modes
The InkCanvas provides support for various input modes through its EditingMode
property.

Manipulate Ink
The InkCanvas provides support for many ink editing operations. For example,
InkCanvas supports back-of-pen erase, and no additional code is needed to add the
functionality to the element.

Selection

Setting selection mode is as simple as setting the InkCanvasEditingMode property to


Select.

The following code sets the editing mode based on the value of a CheckBox:

C#

// Set the selection mode based on a checkbox


if ((bool)cbSelectionMode.IsChecked)
{
theInkCanvas.EditingMode = InkCanvasEditingMode.Select;
}
else
{
theInkCanvas.EditingMode = InkCanvasEditingMode.Ink;
}

DrawingAttributes

Use the DrawingAttributes property to change the appearance of ink strokes. For
instance, the Color member of DrawingAttributes sets the color of the rendered Stroke.

The following example changes the color of the selected strokes to red:
C#

// Get the selected strokes from the InkCanvas


StrokeCollection selection = theInkCanvas.GetSelectedStrokes();

// Check to see if any strokes are actually selected


if (selection.Count > 0)
{
// Change the color of each stroke in the collection to red
foreach (System.Windows.Ink.Stroke stroke in selection)
{
stroke.DrawingAttributes.Color = System.Windows.Media.Colors.Red;
}
}

DefaultDrawingAttributes
The DefaultDrawingAttributes property provides access to properties such as the height,
width, and color of the strokes to be created in an InkCanvas. Once you change the
DefaultDrawingAttributes, all future strokes entered into the InkCanvas are rendered
with the new property values.

In addition to modifying the DefaultDrawingAttributes in the code-behind file, you can


use XAML syntax for specifying DefaultDrawingAttributes properties.

The next example demonstrates how to set the Color property. To use this code, create a
new WPF project called "HelloInkCanvas" in Visual Studio. Replace the code in the
MainWindow.xaml file with the following code:

XAML

<Window x:Class="HelloInkCanvas.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Ink="clr-namespace:System.Windows.Ink;assembly=PresentationCore"
Title="Hello, InkCanvas!" Height="300" Width="300"
>
<Grid>
<InkCanvas Name="inkCanvas1" Background="Ivory">
<InkCanvas.DefaultDrawingAttributes>
<Ink:DrawingAttributes xmlns:ink="system-windows-ink" Color="Red"
Width="5" />
</InkCanvas.DefaultDrawingAttributes>
</InkCanvas>

<!-- This stack panel of buttons is a sibling to InkCanvas (not a child)


but overlapping it,
higher in z-order, so that ink is collected and rendered behind -->
<StackPanel Name="buttonBar" VerticalAlignment="Top" Height="26"
Orientation="Horizontal" Margin="5">
<Button Click="Ink">Ink</Button>
<Button Click="Highlight">Highlight</Button>
<Button Click="EraseStroke">EraseStroke</Button>
<Button Click="Select">Select</Button>
</StackPanel>
</Grid>
</Window>

Next, add the following button event handlers to the code behind file, inside the
MainWindow class:

C#

// Set the EditingMode to ink input.


private void Ink(object sender, RoutedEventArgs e)
{
inkCanvas1.EditingMode = InkCanvasEditingMode.Ink;

// Set the DefaultDrawingAttributes for a red pen.


inkCanvas1.DefaultDrawingAttributes.Color = Colors.Red;
inkCanvas1.DefaultDrawingAttributes.IsHighlighter = false;
inkCanvas1.DefaultDrawingAttributes.Height = 2;
}

// Set the EditingMode to highlighter input.


private void Highlight(object sender, RoutedEventArgs e)
{
inkCanvas1.EditingMode = InkCanvasEditingMode.Ink;

// Set the DefaultDrawingAttributes for a highlighter pen.


inkCanvas1.DefaultDrawingAttributes.Color = Colors.Yellow;
inkCanvas1.DefaultDrawingAttributes.IsHighlighter = true;
inkCanvas1.DefaultDrawingAttributes.Height = 25;
}

// Set the EditingMode to erase by stroke.


private void EraseStroke(object sender, RoutedEventArgs e)
{
inkCanvas1.EditingMode = InkCanvasEditingMode.EraseByStroke;
}

// Set the EditingMode to selection.


private void Select(object sender, RoutedEventArgs e)
{
inkCanvas1.EditingMode = InkCanvasEditingMode.Select;
}

After copying this code, press F5 in Visual Studio to run the program in the debugger.
Notice how the StackPanel places the buttons on top of the InkCanvas. If you try to ink
over the top of the buttons, the InkCanvas collects and renders the ink behind the
buttons. This is because the buttons are siblings of the InkCanvas as opposed to
children. Also, the buttons are higher in the z-order, so the ink is rendered behind them.

See also
DrawingAttributes
DefaultDrawingAttributes
System.Windows.Ink
Handwriting Recognition
Article • 07/27/2022

This section discusses the fundamentals of recognition as it pertains to digital ink in the
WPF platform.

Recognition Solutions
The following example shows how to recognize ink using the Microsoft.Ink.InkCollector
class.

7 Note

This sample requires that handwriting recognizers be installed on the system.

Create a new WPF application project in Visual Studio called InkRecognition. Replace
the contents of the Window1.xaml file with the following XAML code. This code renders
the application's user interface.

XAML

<Window x:Class="InkRecognition.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="InkRecognition"
>
<Canvas Name="theRootCanvas">
<Border
Background="White"
BorderBrush="Black"
BorderThickness="2"
Height="300"
Width="300"
Canvas.Top="10"
Canvas.Left="10">
<InkCanvas Name="theInkCanvas"></InkCanvas>
</Border>
<TextBox Name="textBox1"
Height="25"
Width="225"
Canvas.Top="325"
Canvas.Left="10"></TextBox>
<Button
Height="25"
Width="75"
Canvas.Top="325"
Canvas.Left="235"
Click="buttonClick">Recognize</Button>
<Button x:Name="btnClear" Content="Clear Canvas" Canvas.Left="10"
Canvas.Top="367" Width="75" Click="btnClear_Click"/>
</Canvas>
</Window>

Add a reference to the Microsoft Ink assembly, Microsoft.Ink.dll, which can be found in
\Program Files\Common Files\Microsoft Shared\Ink. Replace the contents of the code
behind file with the following code.

C#

using System.Windows;
using Microsoft.Ink;
using System.IO;

namespace InkRecognition
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>

public partial class Window1 : Window


{

public Window1()
{
InitializeComponent();
}

// Recognizes handwriting by using RecognizerContext


private void buttonClick(object sender, RoutedEventArgs e)
{
using (MemoryStream ms = new MemoryStream())
{
theInkCanvas.Strokes.Save(ms);
var myInkCollector = new InkCollector();
var ink = new Ink();
ink.Load(ms.ToArray());

using (RecognizerContext context = new RecognizerContext())


{
if (ink.Strokes.Count > 0)
{
context.Strokes = ink.Strokes;
RecognitionStatus status;

var result = context.Recognize(out status);

if (status == RecognitionStatus.NoError)
textBox1.Text = result.TopString;
else
MessageBox.Show("Recognition failed");
}
else
{
MessageBox.Show("No stroke detected");
}
}
}
}

private void btnClear_Click(object sender, RoutedEventArgs e) {


theInkCanvas.Strokes.Clear();
}
}
}

See also
Microsoft.Ink.InkCollector
Storing Ink
Article • 02/06/2023

The Save methods provide support for storing ink as Ink Serialized Format (ISF).
Constructors for the StrokeCollection class provide support for reading ink data.

Ink Storage and Retrieval


This section discusses how to store and retrieve ink in the WPF platform.

The following example implements a button-click event handler that presents the user
with a File Save dialog box and saves the ink from an InkCanvas out to a file.

C#

private void buttonSaveAsClick(object sender, RoutedEventArgs e)


{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "isf files (*.isf)|*.isf";

if (saveFileDialog1.ShowDialog() == true)
{
FileStream fs = new FileStream(saveFileDialog1.FileName,
FileMode.Create);
theInkCanvas.Strokes.Save(fs);
fs.Close();
}
}

The following example implements a button-click event handler that presents the user
with a File Open dialog box and reads ink from the file into an InkCanvas element.

C#

private void buttonLoadClick(object sender, RoutedEventArgs e)


{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "isf files (*.isf)|*.isf";

if (openFileDialog1.ShowDialog() == true)
{
FileStream fs = new FileStream(openFileDialog1.FileName,
FileMode.Open);
theInkCanvas.Strokes = new StrokeCollection(fs);
fs.Close();
}
}
See also
InkCanvas
Windows Presentation Foundation
The Ink Object Model: Windows Forms
and COM versus WPF
Article • 08/18/2022

There are essentially three platforms that support digital ink: the Tablet PC Windows
Forms platform, the Tablet PC COM platform, and the Windows Presentation Foundation
(WPF) platform. The Windows Forms and COM platforms share a similar object model,
but the object model for the WPF platform is substantially different. This topic discusses
the differences at a high-level so that developers that have worked with one object
model can better understand the other.

Enabling Ink in an Application


All three platforms ship objects and controls that enable an application to receive input
from a tablet pen. The Windows Forms and COM platforms ship with
Microsoft.Ink.InkPicture, Microsoft.Ink.InkEdit, Microsoft.Ink.InkOverlay and
Microsoft.Ink.InkCollector classes. Microsoft.Ink.InkPicture and Microsoft.Ink.InkEdit are
controls that you can add to an application to collect ink. The Microsoft.Ink.InkOverlay
and Microsoft.Ink.InkCollector can be attached to an existing window to ink-enable
windows and custom controls.

The WPF platform includes the InkCanvas control. You can add an InkCanvas to your
application and begin collecting ink immediately. With the InkCanvas, the user can copy,
select, and resize ink. You can add other controls to the InkCanvas, and the user can
handwrite over those controls, too. You can create an ink-enabled custom control by
adding an InkPresenter to it and collecting its stylus points.

The following table lists where to learn more about enabling ink in an application:

To do this… On the WPF Platform… On the Windows Forms/COM


Platforms…

Add an ink-enabled control to an See Getting Started with See Auto Claims Form Sample
application Ink.

Enable ink on a custom control See Creating an Ink Input See Ink Clipboard Sample.
Control.

Ink Data
On the Windows Forms and COM platforms, Microsoft.Ink.InkCollector,
Microsoft.Ink.InkOverlay, Microsoft.Ink.InkEdit, and Microsoft.Ink.InkPicture each expose
a Microsoft.Ink.Ink object. The Microsoft.Ink.Ink object contains the data for one or more
Microsoft.Ink.Stroke objects and exposes common methods and properties to manage
and manipulate those strokes. The Microsoft.Ink.Ink object manages the lifetime of the
strokes it contains; the Microsoft.Ink.Ink object creates and deletes the strokes that it
owns. Each Microsoft.Ink.Stroke has an identifier that is unique within its parent
Microsoft.Ink.Ink object.

On the WPF platform, the System.Windows.Ink.Stroke class owns and manages its own
lifetime. A group of Stroke objects can be collected together in a StrokeCollection, which
provides methods for common ink data management operations such as hit testing,
erasing, transforming, and serializing the ink. A Stroke can belong to zero, one, or more
StrokeCollection objects at any give time. Instead of having a Microsoft.Ink.Ink object,
the InkCanvas and InkPresenter contain a System.Windows.Ink.StrokeCollection.

The following pair of illustrations compares the ink data object models. On the Windows
Forms and COM platforms, the Microsoft.Ink.Ink object constrains the lifetime of the
Microsoft.Ink.Stroke objects, and the stylus packets belong to the individual strokes. Two
or more strokes can reference the same Microsoft.Ink.DrawingAttributes object, as
shown in the following illustration.

On the WPF, each System.Windows.Ink.Stroke is a common language runtime object


that exists as long as something has a reference to it. Each Stroke references a
StylusPointCollection and System.Windows.Ink.DrawingAttributes object, which are also
common language runtime objects.
The following table compares how to accomplish some common tasks on the WPF
platform and the Windows Forms and COM platforms.

Task Windows Presentation Foundation Windows Forms and COM

Save Ink Save Microsoft.Ink.Ink.Save

Load Ink Create a StrokeCollection with the Microsoft.Ink.Ink.Load


StrokeCollection constructor.

Hit test HitTest Microsoft.Ink.Ink.HitTest

Copy Ink CopySelection Microsoft.Ink.Ink.ClipboardCopy

Paste Ink Paste Microsoft.Ink.Ink.ClipboardPaste

Access custom AddPropertyData (the properties are Use


properties on a stored internally and accessed via Microsoft.Ink.Ink.ExtendedProperties
collection of AddPropertyData, RemovePropertyData,
strokes and ContainsPropertyData)

Sharing ink between platforms


Although the platforms have different object models for the ink data, sharing the data
between the platforms is very easy. The following examples save ink from a Windows
Forms application and load the ink into a Windows Presentation Foundation application.

C#

using Microsoft.Ink;
using System.Drawing;

C#
/// <summary>
/// Saves the digital ink from a Windows Forms application.
/// </summary>
/// <param name="inkToSave">An Ink object that contains the
/// digital ink.</param>
/// <returns>A MemoryStream containing the digital ink.</returns>
MemoryStream SaveInkInWinforms(Ink inkToSave)
{
byte[] savedInk = inkToSave.Save();

return (new MemoryStream(savedInk));


}

C#

using System.Windows.Ink;

C#

/// <summary>
/// Loads digital ink into a StrokeCollection, which can be
/// used by a WPF application.
/// </summary>
/// <param name="savedInk">A MemoryStream containing the digital ink.
</param>
public void LoadInkInWPF(MemoryStream inkStream)
{
strokes = new StrokeCollection(inkStream);
}

The following examples save ink from a Windows Presentation Foundation application
and load the ink into a Windows Forms application.

C#

using System.Windows.Ink;

C#

/// <summary>
/// Saves the digital ink from a WPF application.
/// </summary>
/// <param name="inkToSave">A StrokeCollection that contains the
/// digital ink.</param>
/// <returns>A MemoryStream containing the digital ink.</returns>
MemoryStream SaveInkInWPF(StrokeCollection strokesToSave)
{
MemoryStream savedInk = new MemoryStream();
strokesToSave.Save(savedInk);

return savedInk;
}

C#

using Microsoft.Ink;
using System.Drawing;

C#

/// <summary>
/// Loads digital ink into a Windows Forms application.
/// </summary>
/// <param name="savedInk">A MemoryStream containing the digital ink.
</param>
public void LoadInkInWinforms(MemoryStream savedInk)
{
theInk = new Ink();
theInk.Load(savedInk.ToArray());
}

Events from the Tablet Pen


The Microsoft.Ink.InkOverlay, Microsoft.Ink.InkCollector, and Microsoft.Ink.InkPicture on
the Windows Forms and COM platforms receive events when the user inputs pen data.
The Microsoft.Ink.InkOverlay or Microsoft.Ink.InkCollector is attached to a window or a
control, and can subscribe to the events raised by the tablet input data. The thread on
which these events occurs depends on whether the events are raised with a pen, a
mouse, or programmatically. For more information about threading in relation to these
events, see General Threading Considerations and Threads on Which an Event Can Fire.

On the Windows Presentation Foundation platform, the UIElement class has events for
pen input. This means that every control exposes the full set of stylus events. The stylus
events have tunneling/bubbling event pairs and always occur on the application thread.
For more information, see Routed Events Overview.

The following diagram shows compares the object models for the classes that raise
stylus events. The Windows Presentation Foundation object model shows only the
bubbling events, not the tunneling event counterparts.
Pen Data
All three platforms provide you with ways to intercept and manipulate the data that
comes in from a tablet pen. On the Windows Forms and COM Platforms, this is achieved
by creating a Microsoft.StylusInput.RealTimeStylus, attaching a window or control to it,
and creating a class that implements the Microsoft.StylusInput.IStylusSyncPlugin or
Microsoft.StylusInput.IStylusAsyncPlugin interface. The custom plug-in is then added to
the plug-in collection of the Microsoft.StylusInput.RealTimeStylus. For more information
about this object model, see Architecture of the StylusInput APIs.

On the WPF platform, the UIElement class exposes a collection of plug-ins, similar in
design to the Microsoft.StylusInput.RealTimeStylus. To intercept pen data, create a class
that inherits from StylusPlugIn and add the object to the StylusPlugIns collection of the
UIElement. For more information about this interaction, see Intercepting Input from the
Stylus.

On all platforms, a thread pool receives the ink data via stylus events and sends it to the
application thread. For more information about threading on the COM and Windows
Platforms, see Threading Considerations for the StylusInput APIs. For more information
about threading on the Windows Presentation Software, see The Ink Threading Model.

The following illustration compares the object models for the classes that receive pen
data on the pen thread pool.
Advanced Ink Handling
Article • 02/06/2023

The WPF ships with the InkCanvas, and is an element you can put in your application to
immediately start collecting and displaying ink. However, if the InkCanvas control does
not provide a fine enough level of control, you can maintain control at a higher level by
customizing your own ink collection and ink rendering classes using
System.Windows.Input.StylusPlugIns.

The System.Windows.Input.StylusPlugIns classes provide a mechanism for implementing


low-level control over Stylus input and dynamically rendering ink. The StylusPlugIn class
provides a mechanism for you to implement custom behavior and apply it to the stream
of data coming from the stylus device for optimal performance. The DynamicRenderer, a
specialized StylusPlugIn, allows you to customize dynamically rendering ink data in real-
time which means that the DynamicRenderer draws digital ink immediately as
StylusPoint data is generated, so it appears to "flow" from the stylus device.

In This Section
Custom Rendering Ink
Intercepting Input from the Stylus
Creating an Ink Input Control
The Ink Threading Model
Custom Rendering Ink
Article • 02/06/2023

The DrawingAttributes property of a stroke allows you to specify the appearance of a


stroke, such as its size, color, and shape, but there may be times that you want to
customize the appearance beyond what DrawingAttributes allow. You may want to
customize the appearance of ink by rendering in the appearance of an air brush, oil
paint, and many other effects. The Windows Presentation Foundation (WPF) allows you
to custom render ink by implementing a custom DynamicRenderer and Stroke object.

This topic contains the following subsections:

Architecture

Implementing a Dynamic Renderer

Implementing Custom Strokes

Implementing a Custom InkCanvas

Conclusion

Architecture
Ink rendering occurs two times; when a user writes ink to an inking surface, and again
after the stroke is added to the ink-enabled surface. The DynamicRenderer renders the
ink when the user moves the tablet pen on the digitizer, and the Stroke renders itself
once it is added to an element.

There are three classes to implement when dynamically rendering ink.

1. DynamicRenderer: Implement a class that derives from DynamicRenderer. This


class is a specialized StylusPlugIn that renders the stroke as it is drawn. The
DynamicRenderer does the rendering on a separate thread, so the inking surface
appears to collect ink even when the application user interface (UI) thread is
blocked. For more information about the threading model, see The Ink Threading
Model. To customize dynamically rendering a stroke, override the OnDraw method.

2. Stroke: Implement a class that derives from Stroke. This class is responsible for
static rendering of the StylusPoint data after it has been converted into a Stroke
object. Override the DrawCore method to ensure that static rendering of the stroke
is consistent with dynamic rendering.
3. InkCanvas: Implement a class that derives from InkCanvas. Assign the customized
DynamicRenderer to the DynamicRenderer property. Override the
OnStrokeCollected method and add a custom stroke to the Strokes property. This
ensures that the appearance of the ink is consistent.

Implementing a Dynamic Renderer


Although the DynamicRenderer class is a standard part of WPF, to perform more
specialized rendering, you must create a customized dynamic renderer that derives from
the DynamicRenderer and override the OnDraw method.

The following example demonstrates a customized DynamicRenderer that draws ink


with a linear gradient brush effect.

C#

using System;
using System.Windows.Media;
using System.Windows;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Input;
using System.Windows.Ink;

C#

// A StylusPlugin that renders ink with a linear gradient brush effect.


class CustomDynamicRenderer : DynamicRenderer
{
[ThreadStatic]
static private Brush brush = null;

[ThreadStatic]
static private Pen pen = null;

private Point prevPoint;

protected override void OnStylusDown(RawStylusInput rawStylusInput)


{
// Allocate memory to store the previous point to draw from.
prevPoint = new Point(double.NegativeInfinity,
double.NegativeInfinity);
base.OnStylusDown(rawStylusInput);
}

protected override void OnDraw(DrawingContext drawingContext,


StylusPointCollection stylusPoints,
Geometry geometry, Brush fillBrush)
{
// Create a new Brush, if necessary.
brush ??= new LinearGradientBrush(Colors.Red, Colors.Blue, 20d);

// Create a new Pen, if necessary.


pen ??= new Pen(brush, 2d);

// Draw linear gradient ellipses between


// all the StylusPoints that have come in.
for (int i = 0; i < stylusPoints.Count; i++)
{
Point pt = (Point)stylusPoints[i];
Vector v = Point.Subtract(prevPoint, pt);

// Only draw if we are at least 4 units away


// from the end of the last ellipse. Otherwise,
// we're just redrawing and wasting cycles.
if (v.Length > 4)
{
// Set the thickness of the stroke based
// on how hard the user pressed.
double radius = stylusPoints[i].PressureFactor * 10d;
drawingContext.DrawEllipse(brush, pen, pt, radius, radius);
prevPoint = pt;
}
}
}
}

Implementing Custom Strokes


Implement a class that derives from Stroke. This class is responsible for rendering
StylusPoint data after it has been converted into a Stroke object. Override the DrawCore
class to do the actual drawing.

Your Stroke class can also store custom data by using the AddPropertyData method.
This data is stored with the stroke data when persisted.

The Stroke class can also perform hit testing. You can also implement your own hit
testing algorithm by overriding the HitTest method in the current class.

The following C# code demonstrates a custom Stroke class that renders StylusPoint data
as a 3D stroke.

C#

using System;
using System.Windows.Media;
using System.Windows;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Input;
using System.Windows.Ink;

C#

// A class for rendering custom strokes


class CustomStroke : Stroke
{
Brush brush;
Pen pen;

public CustomStroke(StylusPointCollection stylusPoints)


: base(stylusPoints)
{
// Create the Brush and Pen used for drawing.
brush = new LinearGradientBrush(Colors.Red, Colors.Blue, 20d);
pen = new Pen(brush, 2d);
}

protected override void DrawCore(DrawingContext drawingContext,


DrawingAttributes drawingAttributes)
{
// Allocate memory to store the previous point to draw from.
Point prevPoint = new Point(double.NegativeInfinity,
double.NegativeInfinity);

// Draw linear gradient ellipses between


// all the StylusPoints in the Stroke.
for (int i = 0; i < this.StylusPoints.Count; i++)
{
Point pt = (Point)this.StylusPoints[i];
Vector v = Point.Subtract(prevPoint, pt);

// Only draw if we are at least 4 units away


// from the end of the last ellipse. Otherwise,
// we're just redrawing and wasting cycles.
if (v.Length > 4)
{
// Set the thickness of the stroke
// based on how hard the user pressed.
double radius = this.StylusPoints[i].PressureFactor * 10d;
drawingContext.DrawEllipse(brush, pen, pt, radius, radius);
prevPoint = pt;
}
}
}
}

Implementing a Custom InkCanvas


The easiest way to use your customized DynamicRenderer and stroke is to implement a
class that derives from InkCanvas and uses these classes. The InkCanvas has a
DynamicRenderer property that specifies how the stroke is rendered when the user is
drawing it.

To custom render strokes on an InkCanvas do the following:

Create a class that derives from the InkCanvas.

Assign your customized DynamicRenderer to the InkCanvas.DynamicRenderer


property.

Override the OnStrokeCollected method. In this method, remove the original


stroke that was added to the InkCanvas. Then create a custom stroke, add it to the
Strokes property, and call the base class with a new
InkCanvasStrokeCollectedEventArgs that contains the custom stroke.

The following C# code demonstrates a custom InkCanvas class that uses a customized
DynamicRenderer and collects custom strokes.

C#

public class CustomRenderingInkCanvas : InkCanvas


{
CustomDynamicRenderer customRenderer = new CustomDynamicRenderer();

public CustomRenderingInkCanvas() : base()


{
// Use the custom dynamic renderer on the
// custom InkCanvas.
this.DynamicRenderer = customRenderer;
}

protected override void


OnStrokeCollected(InkCanvasStrokeCollectedEventArgs e)
{
// Remove the original stroke and add a custom stroke.
this.Strokes.Remove(e.Stroke);
CustomStroke customStroke = new CustomStroke(e.Stroke.StylusPoints);
this.Strokes.Add(customStroke);

// Pass the custom stroke to base class' OnStrokeCollected method.


InkCanvasStrokeCollectedEventArgs args =
new InkCanvasStrokeCollectedEventArgs(customStroke);
base.OnStrokeCollected(args);
}
}
An InkCanvas can have more than one DynamicRenderer. You can add multiple
DynamicRenderer objects to the InkCanvas by adding them to the StylusPlugIns
property.

Conclusion
You can customize the appearance of ink by deriving your own DynamicRenderer,
Stroke, and InkCanvas classes. Together, these classes ensure that the appearance of the
stroke is consistent when the user draws the stroke and after it is collected.

See also
Advanced Ink Handling
Intercepting Input from the Stylus
Article • 08/18/2022

The System.Windows.Input.StylusPlugIns architecture provides a mechanism for


implementing low-level control over Stylus input and the creation of digital ink Stroke
objects. The StylusPlugIn class provides a mechanism for you to implement custom
behavior and apply it to the stream of data coming from the stylus device for the
optimal performance.

This topic contains the following subsections:

Architecture

Implementing Stylus Plug-ins

Adding Your Plug-in to an InkCanvas

Conclusion

Architecture
The StylusPlugIn is the evolution of the StylusInput APIs, described in Accessing and
Manipulating Pen Input.

Each UIElement has a StylusPlugIns property that is a StylusPlugInCollection. You can


add a StylusPlugIn to an element's StylusPlugIns property to manipulate StylusPoint data
as it is generated. StylusPoint data consists of all the properties supported by the system
digitizer, including the X and Y point data, as well as PressureFactor data.

Your StylusPlugIn objects are inserted directly into the stream of data coming from the
Stylus device when you add the StylusPlugIn to the StylusPlugIns property. The order in
which plug-ins are added to the StylusPlugIns collection dictates the order in which they
will receive StylusPoint data. For example, if you add a filter plug-in that restricts input to
a particular region, and then add a plug-in that recognizes gestures as they are written,
the plug-in that recognizes gestures will receive filtered StylusPoint data.

Implementing Stylus Plug-ins


To implement a plug-in, derive a class from StylusPlugIn. This class is applied o the
stream of data as it comes in from the Stylus. In this class you can modify the values of
the StylusPoint data.
U Caution

If a StylusPlugIn throws or causes an exception, the application will close. You


should thoroughly test controls that consume a StylusPlugIn and only use a control
if you are certain the StylusPlugIn will not throw an exception.

The following example demonstrates a plug-in that restricts the stylus input by
modifying the X and Y values in the StylusPoint data as it comes in from the Stylus
device.

C#

using System;
using System.Windows.Media;
using System.Windows;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Input;
using System.Windows.Ink;

C#

// A StylusPlugin that restricts the input area.


class FilterPlugin : StylusPlugIn
{
protected override void OnStylusDown(RawStylusInput rawStylusInput)
{
// Call the base class before modifying the data.
base.OnStylusDown(rawStylusInput);

// Restrict the stylus input.


Filter(rawStylusInput);
}

protected override void OnStylusMove(RawStylusInput rawStylusInput)


{
// Call the base class before modifying the data.
base.OnStylusMove(rawStylusInput);

// Restrict the stylus input.


Filter(rawStylusInput);
}

protected override void OnStylusUp(RawStylusInput rawStylusInput)


{
// Call the base class before modifying the data.
base.OnStylusUp(rawStylusInput);

// Restrict the stylus input


Filter(rawStylusInput);
}

private void Filter(RawStylusInput rawStylusInput)


{
// Get the StylusPoints that have come in.
StylusPointCollection stylusPoints =
rawStylusInput.GetStylusPoints();

// Modify the (X,Y) data to move the points


// inside the acceptable input area, if necessary.
for (int i = 0; i < stylusPoints.Count; i++)
{
StylusPoint sp = stylusPoints[i];
if (sp.X < 50) sp.X = 50;
if (sp.X > 250) sp.X = 250;
if (sp.Y < 50) sp.Y = 50;
if (sp.Y > 250) sp.Y = 250;
stylusPoints[i] = sp;
}

// Copy the modified StylusPoints back to the RawStylusInput.


rawStylusInput.SetStylusPoints(stylusPoints);
}
}

Adding Your Plug-in to an InkCanvas


The easiest way to use your custom plug-in is to implement a class that derives from
InkCanvas and add it to the StylusPlugIns property.

The following example demonstrates a custom InkCanvas that filters the ink.

C#

public class FilterInkCanvas : InkCanvas


{
FilterPlugin filter = new FilterPlugin();

public FilterInkCanvas()
: base()
{
this.StylusPlugIns.Add(filter);
}
}

If you add a FilterInkCanvas to your application and run it, you will notice that the ink
isn't restricted to a region until after the user completes a stroke. This is because the
InkCanvas has a DynamicRenderer property, which is a StylusPlugIn and is already a
member of the StylusPlugIns collection. The custom StylusPlugIn you added to the
StylusPlugIns collection receives the StylusPoint data after DynamicRenderer receives
data. As a result, the StylusPoint data will not be filtered until after the user lifts the pen
to end a stroke. To filter the ink as the user draws it, you must insert the FilterPlugin
before the DynamicRenderer.

The following C# code demonstrates a custom InkCanvas that filters the ink as it is
drawn.

C#

public class DynamicallyFilteredInkCanvas : InkCanvas


{
FilterPlugin filter = new FilterPlugin();

public DynamicallyFilteredInkCanvas()
: base()
{
int dynamicRenderIndex =
this.StylusPlugIns.IndexOf(this.DynamicRenderer);

this.StylusPlugIns.Insert(dynamicRenderIndex, filter);
}
}

Conclusion
By deriving your own StylusPlugIn classes and inserting them into StylusPlugInCollection
collections, you can greatly enhance the behavior of your digital ink. You have access to
the StylusPoint data as it is generated, giving you the opportunity to customize the
Stylus input. Because you have such low-level access to the StylusPoint data, you can
implement ink collection and rendering with optimal performance for your application.

See also
Advanced Ink Handling
Accessing and Manipulating Pen Input
Creating an Ink Input Control
Article • 07/20/2022

You can create a custom control that dynamically and statically renders ink. That is,
render ink as a user draws a stroke, causing the ink to appear to "flow" from the tablet
pen, and display ink after it is added to the control, either via the tablet pen, pasted
from the Clipboard, or loaded from a file. To dynamically render ink, your control must
use a DynamicRenderer. To statically render ink, you must override the stylus event
methods (OnStylusDown, OnStylusMove, and OnStylusUp) to collect StylusPoint data,
create strokes, and add them to an InkPresenter (which renders the ink on the control).

This topic contains the following subsections:

How to: Collect Stylus Point Data and Create Ink Strokes

How to: Enable Your Control to Accept Input from the Mouse

Putting it together

Using Additional Plug-ins and DynamicRenderers

Conclusion

How to: Collect Stylus Point Data and Create


Ink Strokes
To create a control that collects and manages ink strokes do the following:

1. Derive a class from Control or one of the classes derived from Control, such as
Label.

C#

using System;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Controls;
using System.Windows;

C#

class InkControl : Label


{
C#

2. Add an InkPresenter to the class and set the Content property to the new
InkPresenter.

C#

InkPresenter ip;

public InkControl()
{
// Add an InkPresenter for drawing.
ip = new InkPresenter();
this.Content = ip;
}

3. Attach the RootVisual of the DynamicRenderer to the InkPresenter by calling the


AttachVisuals method, and add the DynamicRenderer to the StylusPlugIns
collection. This allows the InkPresenter to display the ink as the stylus point data is
collected by your control.

C#

public InkControl()
{

C#

// Add a dynamic renderer that


// draws ink as it "flows" from the stylus.
dr = new DynamicRenderer();
ip.AttachVisuals(dr.RootVisual, dr.DrawingAttributes);
this.StylusPlugIns.Add(dr);
}

4. Override the OnStylusDown method. In this method, capture the stylus with a call
to Capture. By capturing the stylus, your control will to continue to receive
StylusMove and StylusUp events even if the stylus leaves the control's boundaries.
This is not strictly mandatory, but almost always desired for a good user
experience. Create a new StylusPointCollection to gather StylusPoint data. Finally,
add the initial set of StylusPoint data to the StylusPointCollection.
C#

protected override void OnStylusDown(StylusDownEventArgs e)


{
// Capture the stylus so all stylus input is routed to this
control.
Stylus.Capture(this);

// Allocate memory for the StylusPointsCollection and


// add the StylusPoints that have come in so far.
stylusPoints = new StylusPointCollection();
StylusPointCollection eventPoints =
e.GetStylusPoints(this, stylusPoints.Description);

stylusPoints.Add(eventPoints);
}

5. Override the OnStylusMove method and add the StylusPoint data to the
StylusPointCollection object that you created earlier.

C#

protected override void OnStylusMove(StylusEventArgs e)


{
if (stylusPoints == null)
{
return;
}

// Add the StylusPoints that have come in since the


// last call to OnStylusMove.
StylusPointCollection newStylusPoints =
e.GetStylusPoints(this, stylusPoints.Description);
stylusPoints.Add(newStylusPoints);
}

6. Override the OnStylusUp method and create a new Stroke with the
StylusPointCollection data. Add the new Stroke you created to the Strokes
collection of the InkPresenter and release stylus capture.

C#

protected override void OnStylusUp(StylusEventArgs e)


{
if (stylusPoints == null)
{
return;
}

// Add the StylusPoints that have come in since the


// last call to OnStylusMove.
StylusPointCollection newStylusPoints =
e.GetStylusPoints(this, stylusPoints.Description);
stylusPoints.Add(newStylusPoints);

// Create a new stroke from all the StylusPoints since


OnStylusDown.
Stroke stroke = new Stroke(stylusPoints);

// Add the new stroke to the Strokes collection of the


InkPresenter.
ip.Strokes.Add(stroke);

// Clear the StylusPointsCollection.


stylusPoints = null;

// Release stylus capture.


Stylus.Capture(null);
}

How to: Enable Your Control to Accept Input


from the Mouse
If you add the preceding control to your application, run it, and use the mouse as an
input device, you will notice that the strokes are not persisted. To persist the strokes
when the mouse is used as the input device do the following:

1. Override the OnMouseLeftButtonDown and create a new StylusPointCollection Get


the position of the mouse when the event occurred and create a StylusPoint using
the point data and add the StylusPoint to the StylusPointCollection.

C#

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)


{

base.OnMouseLeftButtonDown(e);

// If a stylus generated this event, return.


if (e.StylusDevice != null)
{
return;
}

// Start collecting the points.


stylusPoints = new StylusPointCollection();
Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
}
2. Override the OnMouseMove method. Get the position of the mouse when the
event occurred and create a StylusPoint using the point data. Add the StylusPoint
to the StylusPointCollection object that you created earlier.

C#

protected override void OnMouseMove(MouseEventArgs e)


{

base.OnMouseMove(e);

// If a stylus generated this event, return.


if (e.StylusDevice != null)
{
return;
}

// Don't collect points unless the left mouse button


// is down.
if (e.LeftButton == MouseButtonState.Released ||
stylusPoints == null)
{
return;
}

Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
}

3. Override the OnMouseLeftButtonUp method. Create a new Stroke with the


StylusPointCollection data, and add the new Stroke you created to the Strokes
collection of the InkPresenter.

C#

protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)


{

base.OnMouseLeftButtonUp(e);

// If a stylus generated this event, return.


if (e.StylusDevice != null)
{
return;
}

if (stylusPoints == null)
{
return;
}
Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));

// Create a stroke and add it to the InkPresenter.


Stroke stroke = new Stroke(stylusPoints);
stroke.DrawingAttributes = dr.DrawingAttributes;
ip.Strokes.Add(stroke);

stylusPoints = null;
}

Putting it together
The following example is a custom control that collects ink when the user uses either the
mouse or the pen.

C#

using System;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Controls;
using System.Windows;

C#

// A control for managing ink input


class InkControl : Label
{
InkPresenter ip;
DynamicRenderer dr;

// The StylusPointsCollection that gathers points


// before Stroke from is created.
StylusPointCollection stylusPoints = null;

public InkControl()
{
// Add an InkPresenter for drawing.
ip = new InkPresenter();
this.Content = ip;

// Add a dynamic renderer that


// draws ink as it "flows" from the stylus.
dr = new DynamicRenderer();
ip.AttachVisuals(dr.RootVisual, dr.DrawingAttributes);
this.StylusPlugIns.Add(dr);
}
static InkControl()
{
// Allow ink to be drawn only within the bounds of the control.
Type owner = typeof(InkControl);
ClipToBoundsProperty.OverrideMetadata(owner,
new FrameworkPropertyMetadata(true));
}

protected override void OnStylusDown(StylusDownEventArgs e)


{
// Capture the stylus so all stylus input is routed to this control.
Stylus.Capture(this);

// Allocate memory for the StylusPointsCollection and


// add the StylusPoints that have come in so far.
stylusPoints = new StylusPointCollection();
StylusPointCollection eventPoints =
e.GetStylusPoints(this, stylusPoints.Description);

stylusPoints.Add(eventPoints);
}

protected override void OnStylusMove(StylusEventArgs e)


{
if (stylusPoints == null)
{
return;
}

// Add the StylusPoints that have come in since the


// last call to OnStylusMove.
StylusPointCollection newStylusPoints =
e.GetStylusPoints(this, stylusPoints.Description);
stylusPoints.Add(newStylusPoints);
}

protected override void OnStylusUp(StylusEventArgs e)


{
if (stylusPoints == null)
{
return;
}

// Add the StylusPoints that have come in since the


// last call to OnStylusMove.
StylusPointCollection newStylusPoints =
e.GetStylusPoints(this, stylusPoints.Description);
stylusPoints.Add(newStylusPoints);

// Create a new stroke from all the StylusPoints since OnStylusDown.


Stroke stroke = new Stroke(stylusPoints);

// Add the new stroke to the Strokes collection of the InkPresenter.


ip.Strokes.Add(stroke);
// Clear the StylusPointsCollection.
stylusPoints = null;

// Release stylus capture.


Stylus.Capture(null);
}

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)


{

base.OnMouseLeftButtonDown(e);

// If a stylus generated this event, return.


if (e.StylusDevice != null)
{
return;
}

// Start collecting the points.


stylusPoints = new StylusPointCollection();
Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
}

protected override void OnMouseMove(MouseEventArgs e)


{

base.OnMouseMove(e);

// If a stylus generated this event, return.


if (e.StylusDevice != null)
{
return;
}

// Don't collect points unless the left mouse button


// is down.
if (e.LeftButton == MouseButtonState.Released ||
stylusPoints == null)
{
return;
}

Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
}

protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)


{

base.OnMouseLeftButtonUp(e);

// If a stylus generated this event, return.


if (e.StylusDevice != null)
{
return;
}

if (stylusPoints == null)
{
return;
}

Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));

// Create a stroke and add it to the InkPresenter.


Stroke stroke = new Stroke(stylusPoints);
stroke.DrawingAttributes = dr.DrawingAttributes;
ip.Strokes.Add(stroke);

stylusPoints = null;
}
}

Using Additional Plug-ins and


DynamicRenderers
Like the InkCanvas, your custom control can have custom StylusPlugIn and additional
DynamicRenderer objects. Add these to the StylusPlugIns collection. The order of the
StylusPlugIn objects in the StylusPlugInCollection affects the appearance of the ink when
it is rendered. Suppose you have a DynamicRenderer called dynamicRenderer and a
custom StylusPlugIn called translatePlugin that offsets the ink from the tablet pen. If
translatePlugin is the first StylusPlugIn in the StylusPlugInCollection, and
dynamicRenderer is the second, the ink that "flows" will be offset as the user moves the

pen. If dynamicRenderer is first, and translatePlugin is second, the ink will not be offset
until the user lifts the pen.

Conclusion
You can create a control that collects and renders ink by overriding the stylus event
methods. By creating your own control, deriving your own StylusPlugIn classes, and
inserting them the into StylusPlugInCollection, you can implement virtually any behavior
imaginable with digital ink. You have access to the StylusPoint data as it is generated,
giving you the opportunity to customize Stylus input and render it on the screen as
appropriate for your application. Because you have such low-level access to the
StylusPoint data, you can implement ink collection and render it with optimal
performance for your application.

See also
Advanced Ink Handling
Accessing and Manipulating Pen Input
The Ink Threading Model
Article • 02/06/2023

One of the benefits of ink on a Tablet PC is that it feels a lot like writing with a regular
pen and paper. To accomplish this, the tablet pen collects input data at a much higher
rate than a mouse does and renders the ink as the user writes. The application's user
interface (UI) thread is not sufficient for collecting pen data and rendering ink, because
it can become blocked. To solve this, a WPF application uses two additional threads
when a user writes ink.

The following list describes the threads that take part in collecting and rendering digital
ink:

Pen thread - the thread that takes input from the stylus. (In reality, this is a thread
pool, but this topic refers to it as a pen thread.)

Application user interface thread - the thread that controls the user interface of the
application.

Dynamic rendering thread - the thread that renders the ink while the user draws a
stroke. The dynamic rendering thread is different than the thread that renders
other UI elements for the application, as mentioned in Window Presentation
Foundation Threading Model.

The inking model is the same whether the application uses the InkCanvas or a custom
control similar to the one in Creating an Ink Input Control. Although this topic discusses
threading in terms of the InkCanvas, the same concepts apply when you create a custom
control.

Threading Overview
The following diagram illustrates the threading model when a user draws a stroke:

1. Actions occurring while the user draws the stroke


a. When the user draws a stroke, the stylus points come in on the pen thread.
Stylus plug-ins, including the DynamicRenderer, accept the stylus points on the
pen thread and have the chance to modify them before the InkCanvas receives
them.

b. The DynamicRenderer renders the stylus points on the dynamic rendering


thread. This happens at the same time as the previous step.

c. The InkCanvas receives the stylus points on the UI thread.

2. Actions occurring after the user ends the stroke

a. When the user finishes drawing the stroke, the InkCanvas creates a Stroke
object and adds it to the InkPresenter, which statically renders it.

b. The UI thread alerts the DynamicRenderer that the stroke is statically rendered,
so the DynamicRenderer removes its visual representation of the stroke.

Ink collection and Stylus Plug-ins


Each UIElement has a StylusPlugInCollection. The StylusPlugIn objects in the
StylusPlugInCollection receive and can modify the stylus points on the pen thread. The
StylusPlugIn objects receive the stylus points according to their order in the
StylusPlugInCollection.

The following diagram illustrates the hypothetical situation where the StylusPlugIns
collection of a UIElement contains stylusPlugin1 , a DynamicRenderer, and
stylusPlugin2 , in that order.

In the previous diagram, the following behavior takes place:

1. StylusPlugin1 modifies the values for x and y.


2. DynamicRenderer receives the modified stylus points and renders them on the
dynamic rendering thread.

3. StylusPlugin2 receives the modified stylus points and further modifies the values
for x and y.

4. The application collects the stylus points, and, when the user finishes the stroke,
statically renders the stroke.

Suppose that stylusPlugin1 restricts the stylus points to a rectangle and stylusPlugin2
translates the stylus points to the right. In the previous scenario, the DynamicRenderer
receives the restricted stylus points, but not the translated stylus points. When the user
draws the stroke, the stroke is rendered within the bounds of the rectangle, but the
stroke doesn't appear to be translated until the user lifts the pen.

Performing operations with a Stylus Plug-in on the UI


thread
Because accurate hit-testing cannot be performed on the pen thread, some elements
might occasionally receive stylus input intended for other elements. If you need to make
sure the input was routed correctly before performing an operation, subscribe to and
perform the operation in the OnStylusDownProcessed, OnStylusMoveProcessed, or
OnStylusUpProcessed method. These methods are invoked by the application thread
after accurate hit-testing has been performed. To subscribe to these methods, call the
NotifyWhenProcessed method in the method that occurs on the pen thread.

The following diagram illustrates the relationship between the pen thread and UI thread
with respect to the stylus events of a StylusPlugIn.
Rendering Ink
As the user draws a stroke, DynamicRenderer renders the ink on a separate thread so
the ink appears to "flow" from the pen even when the UI thread is busy. The
DynamicRenderer builds a visual tree on the dynamic rendering thread as it collects
stylus points. When the user finishes the stroke, the DynamicRenderer asks to be
notified when the application does the next rendering pass. After the application
completes the next rendering pass, the DynamicRenderer cleans up its visual tree. The
following diagram illustrates this process.

1. The user begins the stroke.


a. The DynamicRenderer creates the visual tree.
2. The user is drawing the stroke.
a. The DynamicRenderer builds the visual tree.

3. The user ends the stroke.

a. The InkPresenter adds the stroke to its visual tree.

b. The Media Integration Layer (MIL) statically renders the strokes.

c. The DynamicRenderer cleans up the visuals.


Digital Ink How-to Topics
Article • 02/06/2023

In This Section
Select Ink from a Custom Control
Add Custom Data to Ink Data
Erase Ink on a Custom Control
Recognize Application Gestures
Drag and Drop Ink
Data Bind to an InkCanvas
Analyze Ink with Analysis Hints
Rotate Ink
Disable the RealTimeStylus for WPF Applications
How to: Select Ink from a Custom
Control
Article • 02/06/2023

By adding an IncrementalLassoHitTester to your custom control, you can enable your


control so that a user can select ink with a lasso tool, similar to the way the InkCanvas
selects ink with a lasso.

This example assumes you are familiar with creating an ink-enabled custom control. To
create a custom control that accepts ink input, see Creating an Ink Input Control.

Example
When the user draws a lasso, the IncrementalLassoHitTester predicts which strokes will
be within the lasso path's boundaries after the user completes the lasso. Strokes that are
determined to be within the lasso path's boundaries can be thought of as being
selected. Selected strokes can also become unselected. For example, if the user reverses
direction while drawing the lasso, the IncrementalLassoHitTester may unselect some
strokes.

The IncrementalLassoHitTester raises the SelectionChanged event, which enables your


custom control to respond while the user is drawing the lasso. For example, you can
change the appearance of strokes as the user selects and unselects them.

Managing the Ink Mode


It is helpful to the user if the lasso appears differently than the ink on your control. To
accomplish this, your custom control must keep track of whether the user is writing or
selecting ink. The easiest way to do this is to declare an enumeration with two values:
one to indicate that the user is writing ink and one to indicate that the user is selecting
ink.

C#

// Enum that keeps track of whether StrokeCollectionDemo is in ink mode


// or select mode.
public enum InkMode
{
Ink, Select
}
Next, add two DrawingAttributes to the class: one to use when the user writes ink, one
to use when the user selects ink. In the constructor, initialize the DrawingAttributes and
attach both AttributeChanged events to the same event handler. Then set the
DrawingAttributes property of the DynamicRenderer to the ink DrawingAttributes.

C#

DrawingAttributes inkDA;
DrawingAttributes selectDA;

C#

// In the constructor.
// Selection drawing attributes use dark gray ink.
selectDA = new DrawingAttributes();
selectDA.Color = Colors.DarkGray;

// ink drawing attributes use default attributes


inkDA = new DrawingAttributes();
inkDA.Width = 5;
inkDA.Height = 5;

inkDA.AttributeChanged += new
PropertyDataChangedEventHandler(DrawingAttributesChanged);
selectDA.AttributeChanged += new
PropertyDataChangedEventHandler(DrawingAttributesChanged);

Add a property that exposes the selection mode. When the user changes the selection
mode, set the DrawingAttributes property of the DynamicRenderer to the appropriate
DrawingAttributes object and then reattach the RootVisual Property to the InkPresenter.

C#

// Property to indicate whether the user is inputting or


// selecting ink.
public InkMode Mode
{
get
{
return mode;
}

set
{
mode = value;

// Set the DrawingAttributes of the DynamicRenderer


if (mode == InkMode.Ink)
{
renderer.DrawingAttributes = inkDA;
}
else
{
renderer.DrawingAttributes = selectDA;
}

// Reattach the visual of the DynamicRenderer to the InkPresenter.


presenter.DetachVisuals(renderer.RootVisual);
presenter.AttachVisuals(renderer.RootVisual,
renderer.DrawingAttributes);
}
}

Expose the DrawingAttributes as properties so applications can determine the


appearance of the ink strokes and selection strokes.

C#

// Property to allow the user to change the pen's DrawingAttributes.


public DrawingAttributes InkDrawingAttributes
{
get
{
return inkDA;
}
}

// Property to allow the user to change the Selector'newStroke


DrawingAttributes.
public DrawingAttributes SelectDrawingAttributes
{
get
{
return selectDA;
}
}

When a property of a DrawingAttributes object changes, the RootVisual must be


reattached to the InkPresenter. In the event handler for the AttributeChanged event,
reattach the RootVisual to the InkPresenter.

C#

void DrawingAttributesChanged(object sender, PropertyDataChangedEventArgs e)


{
// Reattach the visual of the DynamicRenderer to the InkPresenter
// whenever the DrawingAttributes change.
presenter.DetachVisuals(renderer.RootVisual);
presenter.AttachVisuals(renderer.RootVisual,
renderer.DrawingAttributes);
}

Using the IncrementalLassoHitTester


Create and initialize a StrokeCollection that contains the selected strokes.

C#

// StylusPointCollection that collects the stylus points from the stylus


events.
StylusPointCollection stylusPoints;

When the user starts to draw a stroke, either ink or the lasso, unselect any selected
strokes. Then, if the user is drawing a lasso, create an IncrementalLassoHitTester by
calling GetIncrementalLassoHitTester, subscribe to the SelectionChanged event, and call
AddPoints. This code can be a separate method and called from the OnStylusDown and
OnMouseDown methods.

C#

private void InitializeHitTester(StylusPointCollection collectedPoints)


{
// Deselect any selected strokes.
foreach (Stroke selectedStroke in selectedStrokes)
{
selectedStroke.DrawingAttributes.Color = inkDA.Color;
}
selectedStrokes.Clear();

if (mode == InkMode.Select)
{
// Remove the previously drawn lasso, if it exists.
if (lassoPath != null)
{
presenter.Strokes.Remove(lassoPath);
lassoPath = null;
}

selectionTester =
presenter.Strokes.GetIncrementalLassoHitTester(80);
selectionTester.SelectionChanged +=
new
LassoSelectionChangedEventHandler(selectionTester_SelectionChanged);
selectionTester.AddPoints(collectedPoints);
}
}
Add the stylus points to the IncrementalLassoHitTester while the user draws the lasso.
Call the following method from the OnStylusMove, OnStylusUp, OnMouseMove, and
OnMouseLeftButtonUp methods.

C#

private void AddPointsToHitTester(StylusPointCollection collectedPoints)


{

if (mode == InkMode.Select &&


selectionTester != null &&
selectionTester.IsValid)
{
// When the control is selecting strokes, add the
// stylus packetList to selectionTester.
selectionTester.AddPoints(collectedPoints);
}
}

Handle the IncrementalLassoHitTester.SelectionChanged event to respond when the


user selects and unselects strokes. The LassoSelectionChangedEventArgs class has the
SelectedStrokes and DeselectedStrokes properties that get the strokes that were
selected and unselected, respectively.

C#

void selectionTester_SelectionChanged(object sender,


LassoSelectionChangedEventArgs args)
{
// Change the color of all selected strokes to red.
foreach (Stroke selectedStroke in args.SelectedStrokes)
{
selectedStroke.DrawingAttributes.Color = Colors.Red;
selectedStrokes.Add(selectedStroke);
}

// Change the color of all unselected strokes to


// their original color.
foreach (Stroke unselectedStroke in args.DeselectedStrokes)
{
unselectedStroke.DrawingAttributes.Color = inkDA.Color;
selectedStrokes.Remove(unselectedStroke);
}
}

When the user finishes drawing the lasso, unsubscribe from the SelectionChanged event
and call EndHitTesting.

C#
if (mode == InkMode.Select && lassoPath == null)
{
// Add the lasso to the InkPresenter and add the packetList
// to selectionTester.
lassoPath = newStroke;
lassoPath.DrawingAttributes = selectDA.Clone();
presenter.Strokes.Add(lassoPath);
selectionTester.SelectionChanged -= new
LassoSelectionChangedEventHandler
(selectionTester_SelectionChanged);
selectionTester.EndHitTesting();
}

Putting it All Together.


The following example is a custom control that enables a user to select ink with a lasso.

C#

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Input;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Ink;

// Enum that keeps track of whether StrokeCollectionDemo is in ink mode


// or select mode.
public enum InkMode
{
Ink, Select
}

// This control allows the user to input and select ink. When the
// user selects ink, the lasso remains visible until they erase, or clip
// the selected strokes, or clear the selection. When the control is
// in selection mode, strokes that are selected turn red.
public class InkSelector : Label
{
InkMode mode;

DrawingAttributes inkDA;
DrawingAttributes selectDA;

InkPresenter presenter;
IncrementalLassoHitTester selectionTester;
StrokeCollection selectedStrokes = new StrokeCollection();

// StylusPointCollection that collects the stylus points from the stylus


events.
StylusPointCollection stylusPoints;
// Stroke that represents the lasso.
Stroke lassoPath;

DynamicRenderer renderer;

public InkSelector()
{
mode = InkMode.Ink;

// Use an InkPresenter to display the strokes on the custom control.


presenter = new InkPresenter();
this.Content = presenter;

// In the constructor.
// Selection drawing attributes use dark gray ink.
selectDA = new DrawingAttributes();
selectDA.Color = Colors.DarkGray;

// ink drawing attributes use default attributes


inkDA = new DrawingAttributes();
inkDA.Width = 5;
inkDA.Height = 5;

inkDA.AttributeChanged += new
PropertyDataChangedEventHandler(DrawingAttributesChanged);
selectDA.AttributeChanged += new
PropertyDataChangedEventHandler(DrawingAttributesChanged);

// Add a DynmaicRenderer to the control so ink appears


// to "flow" from the tablet pen.
renderer = new DynamicRenderer();
renderer.DrawingAttributes = inkDA;
this.StylusPlugIns.Add(renderer);
presenter.AttachVisuals(renderer.RootVisual,
renderer.DrawingAttributes);
}

static InkSelector()
{
// Allow ink to be drawn only within the bounds of the control.
Type owner = typeof(InkSelector);
ClipToBoundsProperty.OverrideMetadata(owner,
new FrameworkPropertyMetadata(true));
}

// Prepare to collect stylus packets. If Mode is set to Select,


// get the IncrementalHitTester from the InkPresenter'newStroke
// StrokeCollection and subscribe to its StrokeHitChanged event.
protected override void OnStylusDown(StylusDownEventArgs e)
{
base.OnStylusDown(e);

Stylus.Capture(this);
// Create a new StylusPointCollection using the
StylusPointDescription
// from the stylus points in the StylusDownEventArgs.
stylusPoints = new StylusPointCollection();
StylusPointCollection eventPoints = e.GetStylusPoints(this,
stylusPoints.Description);

stylusPoints.Add(eventPoints);

InitializeHitTester(eventPoints);
}

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)


{
base.OnMouseLeftButtonDown(e);

Mouse.Capture(this);

if (e.StylusDevice != null)
{
return;
}

Point pt = e.GetPosition(this);

StylusPointCollection collectedPoints = new


StylusPointCollection(new Point[] { pt });

stylusPoints = new StylusPointCollection();

stylusPoints.Add(collectedPoints);

InitializeHitTester(collectedPoints);
}
private void InitializeHitTester(StylusPointCollection collectedPoints)
{
// Deselect any selected strokes.
foreach (Stroke selectedStroke in selectedStrokes)
{
selectedStroke.DrawingAttributes.Color = inkDA.Color;
}
selectedStrokes.Clear();

if (mode == InkMode.Select)
{
// Remove the previously drawn lasso, if it exists.
if (lassoPath != null)
{
presenter.Strokes.Remove(lassoPath);
lassoPath = null;
}

selectionTester =
presenter.Strokes.GetIncrementalLassoHitTester(80);
selectionTester.SelectionChanged +=
new
LassoSelectionChangedEventHandler(selectionTester_SelectionChanged);
selectionTester.AddPoints(collectedPoints);
}
}

// Collect the stylus packets as the stylus moves.


protected override void OnStylusMove(StylusEventArgs e)
{
if (stylusPoints == null)
{
return;
}

StylusPointCollection collectedPoints = e.GetStylusPoints(this,


stylusPoints.Description);
stylusPoints.Add(collectedPoints);
AddPointsToHitTester(collectedPoints);
}

protected override void OnMouseMove(MouseEventArgs e)


{

base.OnMouseMove(e);

if (e.StylusDevice != null)
{
return;
}

if (e.LeftButton == MouseButtonState.Released)
{
return;
}

stylusPoints ??= new StylusPointCollection();

Point pt = e.GetPosition(this);

StylusPointCollection collectedPoints = new


StylusPointCollection(new Point[] { pt });

stylusPoints.Add(collectedPoints);

AddPointsToHitTester(collectedPoints);
}

private void AddPointsToHitTester(StylusPointCollection collectedPoints)


{

if (mode == InkMode.Select &&


selectionTester != null &&
selectionTester.IsValid)
{
// When the control is selecting strokes, add the
// stylus packetList to selectionTester.
selectionTester.AddPoints(collectedPoints);
}
}

// When the user lifts the stylus, create a Stroke from the
// collected stylus points and add it to the InkPresenter.
// When the control is selecting strokes, add the
// point data to the IncrementalHitTester.
protected override void OnStylusUp(StylusEventArgs e)
{
stylusPoints ??= new StylusPointCollection();
StylusPointCollection collectedPoints =
e.GetStylusPoints(this, stylusPoints.Description);

stylusPoints.Add(collectedPoints);
AddPointsToHitTester(collectedPoints);
AddStrokeToPresenter();
stylusPoints = null;

Stylus.Capture(null);
}

protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)


{

base.OnMouseLeftButtonUp(e);

if (e.StylusDevice != null) return;

if (stylusPoints == null) stylusPoints = new


StylusPointCollection();

Point pt = e.GetPosition(this);

StylusPointCollection collectedPoints = new


StylusPointCollection(new Point[] { pt });

stylusPoints.Add(collectedPoints);
AddPointsToHitTester(collectedPoints);
AddStrokeToPresenter();

stylusPoints = null;

Mouse.Capture(null);
}

private void AddStrokeToPresenter()


{
Stroke newStroke = new Stroke(stylusPoints);

if (mode == InkMode.Ink)
{
// Add the stroke to the InkPresenter.
newStroke.DrawingAttributes = inkDA.Clone();
presenter.Strokes.Add(newStroke);
}

if (mode == InkMode.Select && lassoPath == null)


{
// Add the lasso to the InkPresenter and add the packetList
// to selectionTester.
lassoPath = newStroke;
lassoPath.DrawingAttributes = selectDA.Clone();
presenter.Strokes.Add(lassoPath);
selectionTester.SelectionChanged -= new
LassoSelectionChangedEventHandler
(selectionTester_SelectionChanged);
selectionTester.EndHitTesting();
}
}

void selectionTester_SelectionChanged(object sender,


LassoSelectionChangedEventArgs args)
{
// Change the color of all selected strokes to red.
foreach (Stroke selectedStroke in args.SelectedStrokes)
{
selectedStroke.DrawingAttributes.Color = Colors.Red;
selectedStrokes.Add(selectedStroke);
}

// Change the color of all unselected strokes to


// their original color.
foreach (Stroke unselectedStroke in args.DeselectedStrokes)
{
unselectedStroke.DrawingAttributes.Color = inkDA.Color;
selectedStrokes.Remove(unselectedStroke);
}
}

// Property to indicate whether the user is inputting or


// selecting ink.
public InkMode Mode
{
get
{
return mode;
}

set
{
mode = value;

// Set the DrawingAttributes of the DynamicRenderer


if (mode == InkMode.Ink)
{
renderer.DrawingAttributes = inkDA;
}
else
{
renderer.DrawingAttributes = selectDA;
}

// Reattach the visual of the DynamicRenderer to the


InkPresenter.
presenter.DetachVisuals(renderer.RootVisual);
presenter.AttachVisuals(renderer.RootVisual,
renderer.DrawingAttributes);
}
}
void DrawingAttributesChanged(object sender,
PropertyDataChangedEventArgs e)
{
// Reattach the visual of the DynamicRenderer to the InkPresenter
// whenever the DrawingAttributes change.
presenter.DetachVisuals(renderer.RootVisual);
presenter.AttachVisuals(renderer.RootVisual,
renderer.DrawingAttributes);
}

// Property to allow the user to change the pen's DrawingAttributes.


public DrawingAttributes InkDrawingAttributes
{
get
{
return inkDA;
}
}

// Property to allow the user to change the Selector'newStroke


DrawingAttributes.
public DrawingAttributes SelectDrawingAttributes
{
get
{
return selectDA;
}
}
}

See also
IncrementalLassoHitTester
StrokeCollection
StylusPointCollection
Creating an Ink Input Control
How to: Add Custom Data to Ink Data
Article • 02/06/2023

You can add custom data to ink that will be saved when the ink is saved as ink serialized
format (ISF). You can save the custom data to the DrawingAttributes, the
StrokeCollection, or the Stroke. Being able to save custom data on three objects gives
you the ability to decide the best place to save the data. All three classes use similar
methods to store and access custom data.

Only the following types can be saved as custom data:

Boolean

Boolean[]

Byte

Byte[]

Char

Char[]

DateTime

DateTime[]

Decimal

Decimal[]

Double

Double[]

Int16

Int16[]

Int32

Int32[]

Int64

Int64[]
Single

Single[]

String

UInt16

UInt16[]

UInt32

UInt32[]

UInt64

UInt64[]

Example
The following example demonstrates how to add and retrieve custom data from a
StrokeCollection.

C#

Guid timestamp = new Guid("12345678-9012-3456-7890-123456789012");

// Add a timestamp to the StrokeCollection.


private void AddTimestamp()
{

inkCanvas1.Strokes.AddPropertyData(timestamp, DateTime.Now);
}

// Get the timestamp of the StrokeCollection.


private void GetTimestamp()
{

if (inkCanvas1.Strokes.ContainsPropertyData(timestamp))
{
object date = inkCanvas1.Strokes.GetPropertyData(timestamp);

if (date is DateTime)
{
MessageBox.Show("This StrokeCollection's timestamp is " +
((DateTime)date).ToString());
}
}
else
{
MessageBox.Show(
"The StrokeCollection does not have a timestamp.");
}
}

The following example creates an application that displays an InkCanvas and two
buttons. The button, switchAuthor , enables two pens to be used by two different
authors. The button changePenColors changes the color of each stroke on the InkCanvas
according to the author. The application defines two DrawingAttributes objects and
adds a custom property to each one that indicates which author drew the Stroke. When
the user clicks changePenColors , the application changes the appearance of the stroke
according to the value of the custom property.

XAML

<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Adding Custom Data to Ink" Height="500" Width="700"
>
<DockPanel Name="root">

<StackPanel Background="DarkSlateBlue">
<Button Name="switchAuthor" Click="switchAuthor_click" >
Switch to student's pen
</Button>
<Button Name="changePenColors" Click="changeColor_click" >
Change the color of the pen ink
</Button>
</StackPanel>
<InkCanvas Name="inkCanvas1">
</InkCanvas>
</DockPanel>
</Window>

C#

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Ink;

/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>

public partial class Window1 : Window


{
Guid authorGuid = new Guid("12345678-9012-3456-7890-123456789012");
DrawingAttributes teachersDA = new DrawingAttributes();
DrawingAttributes studentsDA = new DrawingAttributes();
string teacher = "teacher";
string student = "student";
bool useStudentPen = false;

public Window1()
{
InitializeComponent();

teachersDA.Color = Colors.Red;
teachersDA.Width = 5;
teachersDA.Height = 5;
teachersDA.AddPropertyData(authorGuid, teacher);

studentsDA.Color = Colors.Blue;
studentsDA.Width = 5;
studentsDA.Height = 5;
studentsDA.AddPropertyData(authorGuid, student);

inkCanvas1.DefaultDrawingAttributes = teachersDA;
}

// Switch between using the 'pen' DrawingAttributes and the


// 'highlighter' DrawingAttributes.
void switchAuthor_click(Object sender, RoutedEventArgs e)
{
useStudentPen = !useStudentPen;

if (useStudentPen)
{
switchAuthor.Content = "Use teacher's pen";
inkCanvas1.DefaultDrawingAttributes = studentsDA;
}
else
{
switchAuthor.Content = "Use student's pen";
inkCanvas1.DefaultDrawingAttributes = teachersDA;
}
}

// Change the color of the ink that on the InkCanvas that used the pen.
void changeColor_click(Object sender, RoutedEventArgs e)
{
foreach (Stroke s in inkCanvas1.Strokes)
{
if (s.DrawingAttributes.ContainsPropertyData(authorGuid))
{
object data =
s.DrawingAttributes.GetPropertyData(authorGuid);
if ((data is string) && ((string)data == teacher))
{
s.DrawingAttributes.Color = Colors.Black;
}
if ((data is string) && ((string)data == student))
{
s.DrawingAttributes.Color = Colors.Green;
}
}
}
}
}
How to: Erase Ink on a Custom Control
Article • 02/06/2023

The IncrementalStrokeHitTester determines whether the currently drawn stroke


intersects another stroke. This is useful for creating a control that enables a user to erase
parts of a stroke, the way a user can on an InkCanvas when the EditingMode is set to
EraseByPoint.

Example
The following example creates a custom control that enables the user to erase parts of
strokes. This example creates a control that contains ink when it is initialized. To create a
control that collects ink, see Creating an Ink Input Control.

C#

using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.IO;

// This control initializes with ink already on it and allows the


// user to erase the ink with the tablet pen or mouse.
public class InkEraser : Label
{
IncrementalStrokeHitTester eraseTester;

InkPresenter presenter;

string strokesString =
@"ALwHAxdIEETLgIgERYQBGwIAJAFGhAEbAgAkAQUBOBkgMgkA9P8CAekiOkUzCQD4n"
+ "wIBWiA6RTgIAP4DAAAAgH8RAACAPx8JEQAAAAAAAPA/CiUHh/A6N4HR0AivFX8Vs"
+ "IfsiuyLSaIeDSLwabiHm0GgUDi+KZkACjsQh/A9t4IC5VJpfLhaIxyxXIh7Dncnh"
+ "+6e7qODwoERlPAw8EpGoJAgh61IKjCYXBYDA4DAIHF67KIHAAojB4fwMteBn+RKB"
+ "lziaIfwWTeCwePqbM8WgIeeQCDQOFRvcIAKNA+H8B8XgQHkUbjQTTnGuaZns3l4h"
+ "/DWt4a0YKBBOA94D6HRCAiGnp5CS8LExMLB1tOgYIAKUBOH8KnXhU7lMold+tcbi"
+ "kChkqu2EtPYxp9bmYCH8HDHg4ZhMIwRyMHH+4Jt8nleX8c0/D/AkYwxJGiHkkQgM"
+ "Ch9CqcFhMDQCBwWAwuR2eAACmgdh/EpF4lA6XMUfhMXgMHgVDxBFpRKpZII5EINA"
+ "OA64M+J4Lw1CIoAh/B2x4PS4bQodAopEI5IJBki4waEx2Qy+dy+ayHgleEmmHH8c"
+ "e3MZOCGw5TWd3CwsHAwMCgRAEAgElKwOHZKBApaGIfxezeL0uN02N8IzwaGEpNIJ"
+ "ZxHnELyOj0GfyuU6FgmhplIgIfwYgeDHeaI1vjOtZgcHgHAYb9hUCgEFgsPm1xnM"
+ "ZkYhsnYJgZeZh4uAgCgnSBIOJv4OAgwCmkgh/GrR41X4dGoRJL9EKra5HKY7IZ3C"
+ "4fj/M06olSoU8kkehUbh8jkMdCH8IJXhAXhMCk8JuNlmNyh0YiEumUwn2wMRxyHw"
+ "2TzWmzeb02OzGKxMITwIhnrjzbb44zRhGEKRhCM4zrr6sQKXRWH8kuXkmPj0DiXC"
+ "gcJbC9HZZgkKgUG4bLh3YrwJHAYw2CAh/CiN4Tq7DOZr4BB/AFtdOWW5P2h1Wkzv"
+ "l4+YwqXf8d5fZ7ih51QKbB4LQrLAYDBIDABA4BO4nAICApvIIfy4BeXA2DRSrQlL"
+ "oHHsYQ/KMXlsvl8rn8Xkcdg+G9NVaUWimUDYk9Ah/BoF4M0YBCqZPYqk8dwLf7hD"
+ "YNBJFLKBNqZTqNubWshl9VoM1reFYZYQEBGUsDAwKEjYuDQKBgICBgCAgIOAg4nI"
+ "8OACloSh/BFl4Gf/IOt6FXfF8F4ToPCZzlPwP4+B+DHmQO847rfDeCcG8eKh/EZV"
+ "4i9eZt8A9nUF8VzxaUe5grl7YrPaHfpRKJNx4yHmUuj1vicwmMBEAjUVgKB61A=";

public InkEraser()
{
presenter = new InkPresenter();
this.Content = presenter;

// Create a StrokeCollection the string and add it to


StrokeCollectionConverter converter =
new StrokeCollectionConverter();

if (converter.CanConvertFrom(typeof(string)))
{
StrokeCollection newStrokes =
converter.ConvertFrom(strokesString) as StrokeCollection;
presenter.Strokes.Clear();
presenter.Strokes.Add(newStrokes);
}
}

protected override void OnStylusDown(StylusDownEventArgs e)


{
base.OnStylusDown(e);
StylusPointCollection points = e.GetStylusPoints(this);

InitializeEraserHitTester(points);
}

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)


{
base.OnMouseLeftButtonDown(e);

if (e.StylusDevice != null)
{
return;
}

Point pt = e.GetPosition(this);

StylusPointCollection collectedPoints = new


StylusPointCollection(new Point[] { pt });

InitializeEraserHitTester(collectedPoints);
}

// Prepare to collect stylus packets. Get the


// IncrementalHitTester from the InkPresenter's
// StrokeCollection and subscribe to its StrokeHitChanged event.
private void InitializeEraserHitTester(StylusPointCollection points)
{
EllipseStylusShape eraserTip = new EllipseStylusShape(3, 3, 0);
eraseTester =
presenter.Strokes.GetIncrementalStrokeHitTester(eraserTip);
eraseTester.StrokeHit += new
StrokeHitEventHandler(eraseTester_StrokeHit);
eraseTester.AddPoints(points);
}

protected override void OnStylusMove(StylusEventArgs e)


{
StylusPointCollection points = e.GetStylusPoints(this);

AddPointsToEraserHitTester(points);
}

protected override void OnMouseMove(MouseEventArgs e)


{
base.OnMouseMove(e);

if (e.StylusDevice != null)
{
return;
}

if (e.LeftButton == MouseButtonState.Released)
{
return;
}

Point pt = e.GetPosition(this);

StylusPointCollection collectedPoints = new


StylusPointCollection(new Point[] { pt });

AddPointsToEraserHitTester(collectedPoints);
}

// Collect the StylusPackets as the stylus moves.


private void AddPointsToEraserHitTester(StylusPointCollection points)
{
if (eraseTester.IsValid)
{
eraseTester.AddPoints(points);
}
}

// Unsubscribe from the StrokeHitChanged event when the


// user lifts the stylus.
protected override void OnStylusUp(StylusEventArgs e)
{
StylusPointCollection points = e.GetStylusPoints(this);

StopEraseHitTesting(points);
}

protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)


{
base.OnMouseLeftButtonUp(e);

if (e.StylusDevice != null)
{
return;
}

Point pt = e.GetPosition(this);

StylusPointCollection collectedPoints = new


StylusPointCollection(new Point[] { pt });

StopEraseHitTesting(collectedPoints);
}

private void StopEraseHitTesting(StylusPointCollection points)


{
eraseTester.AddPoints(points);
eraseTester.StrokeHit -= new
StrokeHitEventHandler(eraseTester_StrokeHit);
eraseTester.EndHitTesting();
}

// When the stylus intersects a stroke, erase that part of


// the stroke. When the stylus dissects a stoke, the
// Stroke.Erase method returns a StrokeCollection that contains
// the two new strokes.
void eraseTester_StrokeHit(object sender,
StrokeHitEventArgs args)
{
StrokeCollection eraseResult =
args.GetPointEraseResults();
StrokeCollection strokesToReplace = new StrokeCollection();
strokesToReplace.Add(args.HitStroke);

// Replace the old stroke with the new one.


if (eraseResult.Count > 0)
{
presenter.Strokes.Replace(strokesToReplace, eraseResult);
}
else
{
presenter.Strokes.Remove(strokesToReplace);
}
}
}
How To: Recognize Application Gestures
Article • 02/06/2023

The following example demonstrates how to erase ink when a user makes a ScratchOut
gesture on an InkCanvas. This example assumes an InkCanvas, called inkCanvas1 , is
declared in the XAML file.

Example
C#

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Collections.ObjectModel;

public partial class Window1 : Window


{
public Window1()
{
InitializeComponent();

if (inkCanvas1.IsGestureRecognizerAvailable)
{
inkCanvas1.EditingMode = InkCanvasEditingMode.InkAndGesture;
inkCanvas1.Gesture += new
InkCanvasGestureEventHandler(inkCanvas1_Gesture);
inkCanvas1.SetEnabledGestures(
new ApplicationGesture[] { ApplicationGesture.ScratchOut });
}
}

void inkCanvas1_Gesture(object sender, InkCanvasGestureEventArgs e)


{
ReadOnlyCollection<GestureRecognitionResult> gestureResults =
e.GetGestureRecognitionResults();

// Check the first recognition result for a gesture.


if ((gestureResults[0].RecognitionConfidence ==
RecognitionConfidence.Strong) &&
(gestureResults[0].ApplicationGesture ==
ApplicationGesture.ScratchOut))
{
StrokeCollection hitStrokes = inkCanvas1.Strokes.HitTest(
e.Strokes.GetBounds(), 10);

if (hitStrokes.Count > 0)
{
inkCanvas1.Strokes.Remove(hitStrokes);
}
}
}
}

See also
ApplicationGesture
InkCanvas
Gesture
How to: Drag and Drop Ink
Article • 02/06/2023

Example
The following example creates an application that enables the user to drag selected
strokes from one InkCanvas to the other.

XAML

<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="InkDragDropSample" Height="500" Width="700"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>

<InkCanvas Name="ic1" AllowDrop="True"


Grid.Column="0" Grid.Row="0"
Margin="10,10,10,10" Background="AliceBlue"
PreviewMouseDown="InkCanvas_PreviewMouseDown"
Drop="InkCanvas_Drop"/>

<InkCanvas Name="ic2" AllowDrop="True"


Grid.Column="1" Grid.Row="0"
Margin="10,10,10,10" Background="Beige"
PreviewMouseDown="InkCanvas_PreviewMouseDown"
Drop="InkCanvas_Drop"/>

<CheckBox Grid.Row="1"
Checked="switchToSelect" Unchecked="switchToInk">
Select Mode
</CheckBox>
</Grid>
</Window>

C#

using System;
using System.IO;
using System.Windows;
using System.Windows.Ink;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;

public partial class Window1 : Window


{

public Window1()
{
InitializeComponent();
}

void InkCanvas_PreviewMouseDown(object sender, MouseEventArgs e)


{
InkCanvas ic = (InkCanvas)sender;

Point pt = e.GetPosition(ic);

// If the user is moving selected strokes, prepare the strokes to be


// moved to another InkCanvas.
if (ic.HitTestSelection(pt) ==
InkCanvasSelectionHitResult.Selection)
{
StrokeCollection selectedStrokes = ic.GetSelectedStrokes();
StrokeCollection strokesToMove = selectedStrokes.Clone();

// Remove the offset of the selected strokes so they


// are positioned when the strokes are dropped.
Rect inkBounds = strokesToMove.GetBounds();
TranslateStrokes(strokesToMove, -inkBounds.X, -inkBounds.Y);

// Perform drag and drop.


MemoryStream ms = new MemoryStream();
strokesToMove.Save(ms);
DataObject dataObject = new DataObject(
StrokeCollection.InkSerializedFormat, ms);

DragDropEffects effects =
DragDrop.DoDragDrop(ic, dataObject,
DragDropEffects.Move);

if ((effects & DragDropEffects.Move) ==


DragDropEffects.Move)
{
// Remove the selected strokes
// from the current InkCanvas.
ic.Strokes.Remove(selectedStrokes);
}
}
}

void InkCanvas_Drop(object sender, DragEventArgs e)


{
// Get the strokes that were moved.
InkCanvas ic = (InkCanvas)sender;
MemoryStream ms = (MemoryStream)e.Data.GetData(
StrokeCollection.InkSerializedFormat);
ms.Position = 0;
StrokeCollection strokes = new StrokeCollection(ms);

// Translate the strokes to the position at which


// they were dropped.
Point pt = e.GetPosition(ic);
TranslateStrokes(strokes, pt.X, pt.Y);

// Add the strokes to the InkCanvas and keep them selected.


ic.Strokes.Add(strokes);
ic.Select(strokes);
}

// Helper method that transletes the specified strokes.


void TranslateStrokes(StrokeCollection strokes,
double x, double y)
{
Matrix mat = new Matrix();
mat.Translate(x, y);
strokes.Transform(mat, false);
}

void switchToSelect(object sender, RoutedEventArgs e)


{
ic1.EditingMode = InkCanvasEditingMode.Select;
ic2.EditingMode = InkCanvasEditingMode.Select;
}

void switchToInk(object sender, RoutedEventArgs e)


{
ic1.EditingMode = InkCanvasEditingMode.Ink;
ic2.EditingMode = InkCanvasEditingMode.Ink;
}
}
How to: Data Bind to an InkCanvas
Article • 02/06/2023

Example
The following example demonstrates how to bind the Strokes property of an InkCanvas
to another InkCanvas.

XAML

<InkCanvas Background="LightGray"
Canvas.Top="0" Canvas.Left="0"
Height="400" Width="200" Name="ic"/>

<!-- Bind the Strokes of the second InkCavas to the first InkCanvas
and mirror the strokes along the Y axis.-->
<InkCanvas Background="LightBlue"
Canvas.Top="0" Canvas.Left="200"
Height="400" Width="200"
Strokes="{Binding ElementName=ic, Path=Strokes}">
<InkCanvas.LayoutTransform>
<ScaleTransform ScaleX="-1" ScaleY="1" />
</InkCanvas.LayoutTransform>
</InkCanvas>

The following example demonstrates how to bind the DefaultDrawingAttributes


property to a data source.

XAML

<Canvas.Resources>
<!--Define an array containing some DrawingAttributes.-->
<x:Array x:Key="MyDrawingAttributes" x:Type="{x:Type DrawingAttributes}">
<DrawingAttributes Color="Black" FitToCurve="true" Width="3"
Height="3"/>
<DrawingAttributes Color="Blue" FitToCurve="false" Width="5"
Height="5"/>
<DrawingAttributes Color="Red" FitToCurve="true" Width="7"
Height="7"/>
</x:Array>

<!--Create a DataTemplate to display the DrawingAttributes shown above-->


<DataTemplate DataType="{x:Type DrawingAttributes}" >
<Border Width="80" Height="{Binding Path=Height}">
<Border.Background >
<SolidColorBrush Color="{Binding Path=Color}"/>
</Border.Background>
</Border>
</DataTemplate>
</Canvas.Resources>

XAML

<!--Bind the InkCavas' DefaultDrawingAtributes to


a Listbox, called lbDrawingAttributes.-->
<InkCanvas Name="inkCanvas1" Background="LightGreen"
Canvas.Top="400" Canvas.Left="0"
Height="400" Width="400"
DefaultDrawingAttributes="{Binding
ElementName=lbDrawingAttributes, Path=SelectedItem}"
>
</InkCanvas>

<!--Use the array, MyDrawingAttributes, to populate a ListBox-->


<ListBox Name="lbDrawingAttributes"
Canvas.Top="400" Canvas.Left="450"
Height="100" Width="100"
ItemsSource="{StaticResource MyDrawingAttributes}" />

The following example declares two InkCanvas objects in XAML and establishes data
binding between them and other data sources. The first InkCanvas, called ic , is bound
to two data sources. The EditingMode and DefaultDrawingAttributes properties on ic
are bound to ListBox objects, which are in turn bound to arrays defined in the XAML.
The EditingMode, DefaultDrawingAttributes, and Strokes properties of the second
InkCanvas are bound to the first InkCanvas, ic .

XAML

<Canvas>
<Canvas.Resources>
<!--Define an array containing the InkEditingMode Values.-->
<x:Array x:Key="MyEditingModes" x:Type="{x:Type InkCanvasEditingMode}">
<x:Static Member="InkCanvasEditingMode.Ink"/>
<x:Static Member="InkCanvasEditingMode.Select"/>
<x:Static Member="InkCanvasEditingMode.EraseByPoint"/>
<x:Static Member="InkCanvasEditingMode.EraseByStroke"/>
</x:Array>

<!--Define an array containing some DrawingAttributes.-->


<x:Array x:Key="MyDrawingAttributes"
x:Type="{x:Type DrawingAttributes}">
<DrawingAttributes Color="Black" FitToCurve="true"
Width="3" Height="3"/>
<DrawingAttributes Color="Blue" FitToCurve="false"
Width="5" Height="5"/>
<DrawingAttributes Color="Red" FitToCurve="true"
Width="7" Height="7"/>
</x:Array>
<!--Create a DataTemplate to display the
DrawingAttributes shown above-->
<DataTemplate DataType="{x:Type DrawingAttributes}" >
<Border Width="80" Height="{Binding Path=Height}">
<Border.Background >
<SolidColorBrush Color="{Binding Path=Color}"/>
</Border.Background>
</Border>
</DataTemplate>
</Canvas.Resources>

<!--Bind the first InkCavas' DefaultDrawingAtributes to a


Listbox, called lbDrawingAttributes, and its EditingMode to
a ListBox called lbEditingMode.-->
<InkCanvas Name="ic" Background="LightGray"
Canvas.Top="0" Canvas.Left="0"
Height="400" Width="200"
DefaultDrawingAttributes="{Binding
ElementName=lbDrawingAttributes, Path=SelectedItem}"
EditingMode=
"{Binding ElementName=lbEditingMode, Path=SelectedItem}"
>
</InkCanvas>

<!--Bind the Strokes, DefaultDrawingAtributes, and, EditingMode properties


of
the second InkCavas the first InkCanvas.-->
<InkCanvas Background="LightBlue"
Canvas.Top="0" Canvas.Left="200"
Height="400" Width="200"
Strokes="{Binding ElementName=ic, Path=Strokes}"
DefaultDrawingAttributes="{Binding
ElementName=ic, Path=DefaultDrawingAttributes}"
EditingMode="{Binding ElementName=ic, Path=EditingMode}">

<InkCanvas.LayoutTransform>
<ScaleTransform ScaleX="-1" ScaleY="1" />
</InkCanvas.LayoutTransform>

</InkCanvas>

<!--Use the array, MyEditingModes, to populate a ListBox-->


<ListBox Name="lbEditingMode"
Canvas.Top="0" Canvas.Left="450"
Height="100" Width="100"
ItemsSource="{StaticResource MyEditingModes}" />

<!--Use the array, MyDrawingAttributes, to populate a ListBox-->


<ListBox Name="lbDrawingAttributes"
Canvas.Top="150" Canvas.Left="450"
Height="100" Width="100"
ItemsSource="{StaticResource MyDrawingAttributes}" />

</Canvas>
How to: Analyze Ink with Analysis Hints
Article • 07/27/2022

An System.Windows.Ink.AnalysisHintNode provides a hint for the


System.Windows.Ink.InkAnalyzer to which it is attached. The hint applies to the area
specified by the System.Windows.Ink.ContextNode.Location%2A property of the
System.Windows.Ink.AnalysisHintNode and provides extra context to the ink analyzer to
improve recognition accuracy. The System.Windows.Ink.InkAnalyzer applies this context
information when analyzing ink obtained from within the hint's area.

Example
The following example is an application that uses multiple
System.Windows.Ink.AnalysisHintNode objects on a form that accepts ink input. The
application uses the System.Windows.Ink.AnalysisHintNode.Factoid%2A property to
provide context information for each entry on the form. The application uses
background analysis to analyze the ink and clears the form of all ink five seconds after
the user stops adding ink.

XAML

<Window x:Class="FormAnalyzer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="FormAnalyzer"
SizeToContent="WidthAndHeight"
>
<StackPanel Orientation="Vertical">
<InkCanvas Name="xaml_writingCanvas" Height="500" Width="840"
StrokeCollected="RestartAnalysis" >
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Label}">
<Setter Property="FontSize" Value="20"/>
<Setter Property="FontFamily" Value="Arial"/>
</Style>

<Style TargetType="{x:Type TextBlock}">


<Setter Property="FontSize" Value="18"/>
<Setter Property="VerticalAlignment"
Value="Center"/>
</Style>
</Grid.Resources>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="160"></ColumnDefinition>
<ColumnDefinition Width="160"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="160"></ColumnDefinition>
<ColumnDefinition Width="160"></ColumnDefinition>
</Grid.ColumnDefinitions>

<Grid.RowDefinitions>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
</Grid.RowDefinitions>

<Label Grid.Row="0" Grid.Column="0">Title</Label>


<Label Grid.Row="1" Grid.Column="0">Director</Label>
<Label Grid.Row="2" Grid.Column="0">Starring</Label>
<Label Grid.Row="3" Grid.Column="0">Rating</Label>
<Label Grid.Row="3" Grid.Column="3">Year</Label>
<Label Grid.Row="4" Grid.Column="0">Genre</Label>

<TextBlock Name="xaml_blockTitle"
Grid.Row="0" Grid.Column="1"
Grid.ColumnSpan="5"/>
<TextBlock Name="xaml_blockDirector"
Grid.Row="1" Grid.Column="1"
Grid.ColumnSpan="5"/>
<TextBlock Name="xaml_blockStarring"
Grid.Row="2" Grid.Column="1"
Grid.ColumnSpan="5"/>
<TextBlock Name="xaml_blockRating"
Grid.Row="3" Grid.Column="1"
Grid.ColumnSpan="2"/>
<TextBlock Name="xaml_blockYear"
Grid.Row="3" Grid.Column="4"
Grid.ColumnSpan="2"/>
<TextBlock Name="xaml_blockGenre"
Grid.Row="4" Grid.Column="1"
Grid.ColumnSpan="5"/>

<Line Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="6"


StrokeThickness="2" Stroke="Black"
X1="0" Y1="100" X2="840" Y2="100" />
<Line Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="6"
StrokeThickness="2" Stroke="Black"
X1="0" Y1="100" X2="840" Y2="100" />
<Line Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="6"
StrokeThickness="2" Stroke="Black"
X1="0" Y1="100" X2="840" Y2="100" />
<Line Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="6"
StrokeThickness="2" Stroke="Black"
X1="0" Y1="100" X2="840" Y2="100" />
<Line Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="6"
StrokeThickness="2" Stroke="Black"
X1="420" Y1="0" X2="420" Y2="100" />
</Grid>
</InkCanvas>
</StackPanel>
</Window>

C#

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Threading;

public partial class FormAnalyzer : Window


{
private InkAnalyzer analyzer;

private AnalysisHintNode hintNodeTitle;


private AnalysisHintNode hintNodeDirector;
private AnalysisHintNode hintNodeStarring;
private AnalysisHintNode hintNodeRating;
private AnalysisHintNode hintNodeYear;
private AnalysisHintNode hintNodeGenre;

// Timer that raises an event to


// clear the InkCanvas.
private DispatcherTimer strokeRemovalTimer;

private const int CLEAR_STROKES_DELAY = 5;

public FormAnalyzer()
{
InitializeComponent();
}

protected override void OnContentRendered(EventArgs e)


{
base.OnContentRendered(e);

// Initialize the Analyzer.


analyzer = new InkAnalyzer();
analyzer.ResultsUpdated +=
new ResultsUpdatedEventHandler(analyzer_ResultsUpdated);

// Add analysis hints for each form area.


// Use the absolute Width and Height of the Grid's
// RowDefinition and ColumnDefinition properties defined in XAML,
// to calculate the bounds of the AnalysisHintNode objects.
hintNodeTitle = analyzer.CreateAnalysisHint(
new Rect(100, 0, 740, 100));
hintNodeDirector = analyzer.CreateAnalysisHint(
new Rect(100, 100, 740, 100));
hintNodeStarring = analyzer.CreateAnalysisHint(
new Rect(100, 200, 740, 100));
hintNodeRating = analyzer.CreateAnalysisHint(
new Rect(100, 300, 320, 100));
hintNodeYear = analyzer.CreateAnalysisHint(
new Rect(520, 300, 320, 100));
hintNodeGenre = analyzer.CreateAnalysisHint(
new Rect(100, 400, 740, 100));

//Set the factoids on the hints.


hintNodeTitle.Factoid = "(!IS_DEFAULT)";
hintNodeDirector.Factoid = "(!IS_PERSONALNAME_FULLNAME)";
hintNodeStarring.Factoid = "(!IS_PERSONALNAME_FULLNAME)";
hintNodeRating.Factoid = "(!IS_DEFAULT)";
hintNodeYear.Factoid = "(!IS_DATE_YEAR)";
hintNodeGenre.Factoid = "(!IS_DEFAULT)";
}

/// <summary>
/// InkCanvas.StrokeCollected event handler. Begins
/// ink analysis and starts the timer to clear the strokes.
/// If five seconds pass without a Stroke being added,
/// the strokes on the InkCanvas will be cleared.
/// </summary>
/// <par am name="sender">InkCanvas that raises the
/// StrokeCollected event.</param>
/// <param name="args">Contains the event data.</param>
private void RestartAnalysis(object sender,
InkCanvasStrokeCollectedEventArgs args)
{

// If strokeRemovalTimer is enabled, stop it.


if (strokeRemovalTimer != null && strokeRemovalTimer.IsEnabled)
{
strokeRemovalTimer.Stop();
}

// Restart the timer to clear the strokes in five seconds


strokeRemovalTimer = new DispatcherTimer(
TimeSpan.FromSeconds(CLEAR_STROKES_DELAY),
DispatcherPriority.Normal,
ClearCanvas,
Dispatcher.CurrentDispatcher);

// Add the new stroke to the InkAnalyzer and


// begin background analysis.
analyzer.AddStroke(args.Stroke);
analyzer.BackgroundAnalyze();
}

/// <summary>
/// Analyzer.ResultsUpdated event handler.
/// </summary>
/// <param name="sender">InkAnalyzer that raises the
/// event.</param>
/// <param name="e">Event data</param>
/// <remarks>This method checks each AnalysisHint for
/// analyzed ink and then populated the TextBlock that
/// corresponds to the area on the form.</remarks>
void analyzer_ResultsUpdated(object sender, ResultsUpdatedEventArgs e)
{
string recoText;

recoText = hintNodeTitle.GetRecognizedString();
if (recoText != "") xaml_blockTitle.Text = recoText;

recoText = hintNodeDirector.GetRecognizedString();
if (recoText != "") xaml_blockDirector.Text = recoText;

recoText = hintNodeStarring.GetRecognizedString();
if (recoText != "") xaml_blockStarring.Text = recoText;

recoText = hintNodeRating.GetRecognizedString();
if (recoText != "") xaml_blockRating.Text = recoText;

recoText = hintNodeYear.GetRecognizedString();
if (recoText != "") xaml_blockYear.Text = recoText;

recoText = hintNodeGenre.GetRecognizedString();
if (recoText != "") xaml_blockGenre.Text = recoText;
}

//Clear the canvas, but leave the current strokes in the analyzer.
private void ClearCanvas(object sender, EventArgs args)
{
strokeRemovalTimer.Stop();

xaml_writingCanvas.Strokes.Clear();
}
}
How to: Rotate Ink
Article • 02/06/2023

Example to rotate Ink


The following example copies the ink from an InkCanvas to a Canvas that contains an
InkPresenter. When the application copies the ink, it also rotates the ink 90 degrees
clockwise.

XAML

<Canvas>
<InkCanvas Name="inkCanvas1" Background="LightBlue"
Height="200" Width="200"
Canvas.Top="20" Canvas.Left="20" />

<Border Name="canvas1" Background="LightGreen"


Height="200" Width="200" ClipToBounds="True"
Canvas.Top="20" Canvas.Left="240" >
<InkPresenter Name="inkPresenter1"/>
</Border>
<Button Click="button_Click"
Canvas.Top="240" Canvas.Left="170">
Copy and Rotate Strokes
</Button>
</Canvas>

C#

// Button.Click event handler that rotates the strokes


// and copies them to a Canvas.
private void button_Click(object sender, RoutedEventArgs e)
{
StrokeCollection copiedStrokes = inkCanvas1.Strokes.Clone();
Matrix rotatingMatrix = new Matrix();
double canvasLeft = Canvas.GetLeft(inkCanvas1);
double canvasTop = Canvas.GetTop(inkCanvas1);
Point rotatePoint = new Point(canvas1.Width / 2, canvas1.Height / 2);

rotatingMatrix.RotateAt(90, rotatePoint.X, rotatePoint.Y);


copiedStrokes.Transform(rotatingMatrix, false);
inkPresenter1.Strokes = copiedStrokes;
}

Adorner for Strokes


The following example is a custom Adorner that rotates the strokes on an InkPresenter.

C#

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Ink;

public class RotatingStrokesAdorner : Adorner


{
// The Thumb to drag to rotate the strokes.
Thumb rotateHandle;

// The surrounding boarder.


Path outline;

VisualCollection visualChildren;

// The center of the strokes.


Point center;
double lastAngle;

RotateTransform rotation;

const int HANDLEMARGIN = 10;

// The bounds of the Strokes;


Rect strokeBounds = Rect.Empty;

public RotatingStrokesAdorner(UIElement adornedElement)


: base(adornedElement)
{

visualChildren = new VisualCollection(this);


rotateHandle = new Thumb();
rotateHandle.Cursor = Cursors.SizeNWSE;
rotateHandle.Width = 20;
rotateHandle.Height = 20;
rotateHandle.Background = Brushes.Blue;

rotateHandle.DragDelta += new
DragDeltaEventHandler(rotateHandle_DragDelta);
rotateHandle.DragCompleted += new
DragCompletedEventHandler(rotateHandle_DragCompleted);

outline = new Path();


outline.Stroke = Brushes.Blue;
outline.StrokeThickness = 1;
visualChildren.Add(outline);
visualChildren.Add(rotateHandle);

strokeBounds = AdornedStrokes.GetBounds();
}

/// <summary>
/// Draw the rotation handle and the outline of
/// the element.
/// </summary>
/// <param name="finalSize">The final area within the
/// parent that this element should use to arrange
/// itself and its children.</param>
/// <returns>The actual size used. </returns>
protected override Size ArrangeOverride(Size finalSize)
{
if (strokeBounds.IsEmpty)
{
return finalSize;
}

center = new Point(strokeBounds.X + strokeBounds.Width / 2,


strokeBounds.Y + strokeBounds.Height / 2);

// The rectangle that determines the position of the Thumb.


Rect handleRect = new Rect(strokeBounds.X,
strokeBounds.Y - (strokeBounds.Height / 2 +
HANDLEMARGIN),
strokeBounds.Width, strokeBounds.Height);

if (rotation != null)
{
handleRect.Transform(rotation.Value);
}

// Draws the thumb and the rectangle around the strokes.


rotateHandle.Arrange(handleRect);
outline.Data = new RectangleGeometry(strokeBounds);
outline.Arrange(new Rect(finalSize));
return finalSize;
}

/// <summary>
/// Rotates the rectangle representing the
/// strokes' bounds as the user drags the
/// Thumb.
/// </summary>
void rotateHandle_DragDelta(object sender, DragDeltaEventArgs e)
{
// Find the angle of which to rotate the shape. Use the right
// triangle that uses the center and the mouse's position
// as vertices for the hypotenuse.

Point pos = Mouse.GetPosition(this);


double deltaX = pos.X - center.X;
double deltaY = pos.Y - center.Y;

if (deltaY.Equals(0))
{

return;
}

double tan = deltaX / deltaY;


double angle = Math.Atan(tan);

// Convert to degrees.
angle = angle * 180 / Math.PI;

// If the mouse crosses the vertical center,


// find the complementary angle.
if (deltaY > 0)
{
angle = 180 - Math.Abs(angle);
}

// Rotate left if the mouse moves left and right


// if the mouse moves right.
if (deltaX < 0)
{
angle = -Math.Abs(angle);
}
else
{
angle = Math.Abs(angle);
}

if (Double.IsNaN(angle))
{
return;
}

// Apply the rotation to the strokes' outline.


rotation = new RotateTransform(angle, center.X, center.Y);
outline.RenderTransform = rotation;
}

/// <summary>
/// Rotates the strokes to the same angle as outline.
/// </summary>
void rotateHandle_DragCompleted(object sender,
DragCompletedEventArgs e)
{
if (rotation == null)
{
return;
}
// Rotate the strokes to match the new angle.
Matrix mat = new Matrix();
mat.RotateAt(rotation.Angle - lastAngle, center.X, center.Y);
AdornedStrokes.Transform(mat, true);

// Save the angle of the last rotation.


lastAngle = rotation.Angle;

// Redraw rotateHandle.
this.InvalidateArrange();
}

/// <summary>
/// Gets the strokes of the adorned element
/// (in this case, an InkPresenter).
/// </summary>
private StrokeCollection AdornedStrokes
{
get
{
return ((InkPresenter)AdornedElement).Strokes;
}
}

// Override the VisualChildrenCount and


// GetVisualChild properties to interface with
// the adorner's visual collection.
protected override int VisualChildrenCount
{
get { return visualChildren.Count; }
}

protected override Visual GetVisualChild(int index)


{
return visualChildren[index];
}
}

The following example is a Extensible Application Markup Language (XAML) file that
defines an InkPresenter and populates it with ink. The Window_Loaded event handler adds
the custom adorner to the InkPresenter.

XAML

<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Rotating Strokes Adorner" Height="500" Width="500"
Loaded="Window_Loaded"
>
<InkPresenter Name="inkPresenter1" >
<InkPresenter.Strokes>
ALMDAwRIEEU1BQE4GSAyCQD0/wIB6SI6RTMJAPifAgFaIDpFOAgA/gMAAACAfxEAAIA/
HwkRAAAAAAAA8D8KlwE1h/CPd4SB4NA4OicCjcGjcClcDj8Lh8DgUSkUmmU6nUmoUuk
0ukUCQKVyehz+rzuly+bzORx+BReRQ+RTaRCH8JyXhPbgcPicPh8Pg8Oh0qk1SoVGrV
Oo0mi0Xi8rm9Xr9Dqc/p87pc/k8XicHicOj1CoVKtVmv1GqUaiUHlYg8el4akXK7m7T
cSJgQgghEyym5zx6+PACk4dhPwg/fhCbxY8dp4p2tqnqxyvbPO85z1X1aswhvCd94Tq
55DRUGi4+Tk6OLn4KLkoOejo6ig5KTioOPCD9LlHmrzNxMRCCc3ec8+fe4AKQBmE/Cw
9+FkPNvlOdkrYsWa+acp3Z8erOIT8JaX4S6+FbFilbHNvvPXNJbFqluxghKc5DkwrVF
GEEIJ1w5eLKYAKShuF+Dnr4Oa8HVHXNPFFFFho8VFkqsMRYuuvJxiF+F9r4Xx8HFiqs
FNcirnweDw9+LvvvixdV0+GhONmlj3wjNOcSCEYTnfLy4oA
</InkPresenter.Strokes>
</InkPresenter>
</Window>

C#

void Window_Loaded(object sender, RoutedEventArgs e)


{
// Add the rotating strokes adorner to the InkPresenter.
adornerLayer = AdornerLayer.GetAdornerLayer(inkPresenter1);
adorner = new RotatingStrokesAdorner(inkPresenter1);

adornerLayer.Add(adorner);
}
Disable the RealTimeStylus for WPF
Applications
Article • 02/06/2023

Windows Presentation Foundation (WPF) has built in support for processing Windows 7
touch input. The support comes through the tablet platform’s real-time stylus input as
OnStylusDown, OnStylusUp, and OnStylusMove events. Windows 7 also provides multi-
touch input as Win32 WM_TOUCH window messages. These two APIs are mutually
exclusive on the same HWND. Enabling touch input via the tablet platform (the default
for WPF applications) disables WM_TOUCH messages. As a result, to use WM_TOUCH to
receive touch messages from a WPF window, you must disable the built-in stylus
support in WPF. This is applicable in a scenario such as a WPF window hosting a
component that uses WM_TOUCH.

To disable WPF listening to stylus input, remove any tablet support added by the WPF
window.

Example
The following sample code shows how to remove the default tablet platform support by
using reflection.

C#

public static void DisableWPFTabletSupport()


{
// Get a collection of the tablet devices for this window.
TabletDeviceCollection devices =
System.Windows.Input.Tablet.TabletDevices;

if (devices.Count > 0)
{
// Get the Type of InputManager.
Type inputManagerType = typeof(System.Windows.Input.InputManager);

// Call the StylusLogic method on the InputManager.Current instance.


object stylusLogic = inputManagerType.InvokeMember("StylusLogic",
BindingFlags.GetProperty | BindingFlags.Instance |
BindingFlags.NonPublic,
null, InputManager.Current, null);

if (stylusLogic != null)
{
// Get the type of the stylusLogic returned from the call to
StylusLogic.
Type stylusLogicType = stylusLogic.GetType();

// Loop until there are no more devices to remove.


while (devices.Count > 0)
{
// Remove the first tablet device in the devices collection.
stylusLogicType.InvokeMember("OnTabletRemoved",
BindingFlags.InvokeMethod | BindingFlags.Instance |
BindingFlags.NonPublic,
null, stylusLogic, new object[] { (uint)0 });
}
}

}
}

See also
Intercepting Input from the Stylus
Drag and Drop
Article • 08/10/2023

Windows Presentation Foundation (WPF) provides a highly flexible drag and drop
infrastructure which supports dragging and dropping of data within both WPF
applications as well as other Windows applications.

In This Section
Drag and Drop Overview
Data and Data Objects
Walkthrough: Enabling Drag and Drop on a User Control
How-to Topics

Reference
DataFormat
DataObject
DragDrop
DragDropEffects
DragEventHandler
TextDataFormat

Related Sections
Drag and Drop Overview
Article • 02/06/2023

This topic provides an overview of drag-and-drop support in user interface (UI), and
dropping them.

Drag-and-Drop Support in WPF


Drag-and-drop operations typically involve two parties: a drag source from which the
dragged object originates and a drop target which receives the dropped object. The
drag source and drop target may be UI elements in the same application or a different
application.

The type and number of objects that can be manipulated with drag-and-drop is
completely arbitrary. For example, files, folders, and selections of content are some of
the more common objects manipulated through drag-and-drop operations.

The particular actions performed during a drag-and-drop operation are application


specific, and often determined by context. For example, dragging a selection of files
from one folder to another on the same storage device moves the files by default,
whereas dragging files from a Universal Naming Convention (UNC) share to a local
folder copies the files by default.

The drag-and-drop facilities provided by WPF are designed to be highly flexible and
customizable to support a wide variety of drag-and-drop scenarios. Drag-and-drop
supports manipulating objects within a single application, or between different
applications. Dragging-and-dropping between WPF applications and other Windows
applications is also fully supported.

In WPF, any UIElement or ContentElement can participate in drag-and-drop. The events


and methods required for drag-and-drop operations are defined in the DragDrop class.
The UIElement and ContentElement classes contain aliases for the DragDrop attached
events so that the events appear in the class members list when a UIElement or
ContentElement is inherited as a base element. Event handlers that are attached to these
events are attached to the underlying DragDrop attached event and receive the same
event data instance. For more information, see the UIElement.Drop event.

) Important

OLE drag-and-drop does not work while in the Internet zone.


Data Transfer
Drag-and-drop is part of the more general area of data transfer. Data transfer includes
drag-and-drop and copy-and-paste operations. A drag-and-drop operation is
analogous to a copy-and-paste or cut-and-paste operation that is used to transfer data
from one object or application to another by using the system clipboard. Both types of
operations require:

A source object that provides the data.

A way to temporarily store the transferred data.

A target object that receives the data.

In a copy-and-paste operation, the system clipboard is used to temporarily store the


transferred data; in a drag-and-drop operation, a DataObject is used to store the data.
Conceptually, a data object consists of one or more pairs of an Object that contains the
actual data, and a corresponding data format identifier.

The drag source initiates a drag-and-drop operation by calling the static


DragDrop.DoDragDrop method and passing the transferred data to it. The DoDragDrop
method will automatically wrap the data in a DataObject if necessary. For greater control
over the data format, you can wrap the data in a DataObject before passing it to the
DoDragDrop method. The drop target is responsible for extracting the data from the
DataObject. For more information about working with data objects, see Data and Data
Objects.

The source and target of a drag-and-drop operation are UI elements; however, the data
that is actually being transferred typically does not have a visual representation. You can
write code to provide a visual representation of the data that is dragged, such as occurs
when dragging files in Windows Explorer. By default, feedback is provided to the user by
changing the cursor to represent the effect that the drag-and-drop operation will have
on the data, such as whether the data will be moved or copied.

Drag-and-Drop Effects
Drag-and-drop operations can have different effects on the transferred data. For
example, you can copy the data or you can move the data. WPF defines a
DragDropEffects enumeration that you can use to specify the effect of a drag-and-drop
operation. In the drag source, you can specify the effects that the source will allow in the
DoDragDrop method. In the drop target, you can specify the effect that the target
intends in the Effects property of the DragEventArgs class. When the drop target
specifies its intended effect in the DragOver event, that information is passed back to
the drag source in the GiveFeedback event. The drag source uses this information to
inform the user what effect the drop target intends to have on the data. When the data
is dropped, the drop target specifies its actual effect in the Drop event. That information
is passed back to the drag source as the return value of the DoDragDrop method. If the
drop target returns an effect that is not in the drag sources list of allowedEffects , the
drag-and-drop operation is cancelled without any data transfer occurring.

It is important to remember that in WPF, the DragDropEffects values are only used to
provide communication between the drag source and the drop target regarding the
effects of the drag-and-drop operation. The actual effect of the drag-and-drop
operation depends on you to write the appropriate code in your application.

For example, the drop target might specify that the effect of dropping data on it is to
move the data. However, to move the data, it must be both added to the target element
and removed from the source element. The source element might indicate that it allows
moving the data, but if you do not provide the code to remove the data from the source
element, the end result will be that the data is copied, and not moved.

Drag-and-Drop Events
Drag-and-drop operations support an event driven model. Both the drag source and the
drop target use a standard set of events to handle drag-and-drop operations. The
following tables summarize the standard drag-and-drop events. These are attached
events on the DragDrop class. For more information about attached events, see
Attached Events Overview.

Drag Source Events

Event Summary

GiveFeedback This event occurs continuously during a drag-and-drop operation,


and enables the drop source to give feedback information to the
user. This feedback is commonly given by changing the appearance
of the mouse pointer to indicate the effects allowed by the drop
target. This is a bubbling event.

QueryContinueDrag This event occurs when there is a change in the keyboard or mouse
button states during a drag-and-drop operation, and enables the
drop source to cancel the drag-and-drop operation depending on
the key/button states. This is a bubbling event.

PreviewGiveFeedback Tunneling version of GiveFeedback.

PreviewQueryContinueDrag Tunneling version of QueryContinueDrag.


Drop Target Events

Event Summary

DragEnter This event occurs when an object is dragged into the drop target's boundary.
This is a bubbling event.

DragLeave This event occurs when an object is dragged out of the drop target's
boundary. This is a bubbling event.

DragOver This event occurs continuously while an object is dragged (moved) within the
drop target's boundary. This is a bubbling event.

Drop This event occurs when an object is dropped on the drop target. This is a
bubbling event.

PreviewDragEnter Tunneling version of DragEnter.

PreviewDragLeave Tunneling version of DragLeave.

PreviewDragOver Tunneling version of DragOver.

PreviewDrop Tunneling version of Drop.

To handle drag-and-drop events for instances of an object, add handlers for the events
listed in the preceding tables. To handle drag-and-drop events at the class level,
override the corresponding virtual On*Event and On*PreviewEvent methods. For more
information, see Class Handling of Routed Events by Control Base Classes.

Implementing Drag-and-Drop
A UI element can be a drag source, a drop target, or both. To implement basic drag-
and-drop, you write code to initiate the drag-and-drop operation and to process the
dropped data. You can enhance the drag-and-drop experience by handling optional
drag-and-drop events.

To implement basic drag-and-drop, you will complete the following tasks:

Identify the element that will be a drag source. A drag source can be a UIElement
or a ContentElement.

Create an event handler on the drag source that will initiate the drag-and-drop
operation. The event is typically the MouseMove event.

In the drag source event handler, call the DoDragDrop method to initiate the drag-
and-drop operation. In the DoDragDrop call, specify the drag source, the data to
be transferred, and the allowed effects.

Identify the element that will be a drop target. A drop target can be UIElement or a
ContentElement.

On the drop target, set the AllowDrop property to true .

In the drop target, create a Drop event handler to process the dropped data.

In the Drop event handler, extract the data from the DragEventArgs by using the
GetDataPresent and GetData methods.

In the Drop event handler, use the data to perform the desired drag-and-drop
operation.

You can enhance your drag-and-drop implementation by creating a custom DataObject


and by handling optional drag source and drop target events, as shown in the following
tasks:

To transfer custom data or multiple data items, create a DataObject to pass to the
DoDragDrop method.

To perform additional actions during a drag, handle the DragEnter, DragOver, and
DragLeave events on the drop target.

To change the appearance of the mouse pointer, handle the GiveFeedback event
on the drag source.

To change how the drag-and-drop operation is canceled, handle the


QueryContinueDrag event on the drag source.

Drag-and-Drop Example
This section describes how to implement drag-and-drop for an Ellipse element. The
Ellipse is both a drag source and a drop target. The transferred data is the string
representation of the ellipse’s Fill property. The following XAML shows the Ellipse
element and the drag-and-drop related events that it handles. For complete steps on
how to implement drag-and-drop, see Walkthrough: Enabling Drag and Drop on a User
Control.

XAML

<Ellipse Height="50" Width="50" Fill="Green"


MouseMove="ellipse_MouseMove"
GiveFeedback="ellipse_GiveFeedback"
AllowDrop="True"
DragEnter="ellipse_DragEnter" DragLeave="ellipse_DragLeave"
DragOver="ellipse_DragOver" Drop="ellipse_Drop" />

Enabling an Element to be a Drag Source


An object that is a drag source is responsible for:

Identifying when a drag occurs.

Initiating the drag-and-drop operation.

Identifying the data to be transferred.

Specifying the effects that the drag-and-drop operation is allowed to have on the
transferred data.

The drag source may also give feedback to the user regarding the allowed actions
(move, copy, none), and can cancel the drag-and-drop operation based on additional
user input, such as pressing the ESC key during the drag.

It is the responsibility of your application to determine when a drag occurs, and then
initiate the drag-and-drop operation by calling the DoDragDrop method. Typically, this
is when a MouseMove event occurs over the element to be dragged while a mouse
button is pressed. The following example shows how to initiate a drag-and-drop
operation from the MouseMove event handler of an Ellipse element to make it a drag
source. The transferred data is the string representation of the ellipse’s Fill property.

C#

private void ellipse_MouseMove(object sender, MouseEventArgs e)


{
Ellipse ellipse = sender as Ellipse;
if (ellipse != null && e.LeftButton == MouseButtonState.Pressed)
{
DragDrop.DoDragDrop( ellipse,
ellipse.Fill.ToString(),
DragDropEffects.Copy);
}
}

Inside of the MouseMove event handler, call the DoDragDrop method to initiate the
drag-and-drop operation. The DoDragDrop method takes three parameters:

dragSource – A reference to the dependency object that is the source of the


transferred data; this is typically the source of the MouseMove event.
data - An object that contains the transferred data, wrapped in a DataObject.

allowedEffects - One of the DragDropEffects enumeration values that specifies


the permitted effects of the drag-and-drop operation.

Any serializable object can be passed in the data parameter. If the data is not already
wrapped in a DataObject, it will automatically be wrapped in a new DataObject. To pass
multiple data items, you must create the DataObject yourself, and pass it to the
DoDragDrop method. For more information, see Data and Data Objects.

The allowedEffects parameter is used to specify what the drag source will allow the
drop target to do with the transferred data. The common values for a drag source are
Copy, Move, and All.

7 Note

The drop target is also able to specify what effects it intends in response to the
dropped data. For example, if the drop target does not recognize the data type to
be dropped, it can refuse the data by setting its allowed effects to None. It typically
does this in its DragOver event handler.

A drag source can optionally handle the GiveFeedback and QueryContinueDrag events.
These events have default handlers that are used unless you mark the events as
handled. You will typically ignore these events unless you have a specific need to change
their default behavior.

The GiveFeedback event is raised continuously while the drag source is being dragged.
The default handler for this event checks whether the drag source is over a valid drop
target. If it is, it checks the allowed effects of the drop target. It then gives feedback to
the end user regarding the allowed drop effects. This is typically done by changing the
mouse cursor to a no-drop, copy, or move cursor. You should only handle this event if
you need to use custom cursors to provide feedback to the user. If you handle this
event, be sure to mark it as handled so that the default handler does not override your
handler.

The QueryContinueDrag event is raised continuously while the drag source is being
dragged. You can handle this event to determine what action ends the drag-and-drop
operation based on the state of the ESC, SHIFT, CTRL, and ALT keys, as well as the state
of the mouse buttons. The default handler for this event cancels the drag-and-drop
operation if the ESC key is pressed, and drops the data if the mouse button is released.

U Caution
These events are raised continuously during the drag-and-drop operation.
Therefore, you should avoid resource-intensive tasks in the event handlers. For
example, use a cached cursor instead of creating a new cursor each time the
GiveFeedback event is raised.

Enabling an Element to be a Drop Target


An object that is a drop target is responsible for:

Specifying that it is a valid drop target.

Responding to the drag source when it drags over the target.

Checking that the transferred data is in a format that it can receive.

Processing the dropped data.

To specify that an element is a drop target, you set its AllowDrop property to true . The
drop target events will then be raised on the element so that you can handle them.
During a drag-and-drop operation, the following sequence of events occurs on the drop
target:

1. DragEnter

2. DragOver

3. DragLeave or Drop

The DragEnter event occurs when the data is dragged into the drop target's boundary.
You typically handle this event to provide a preview of the effects of the drag-and-drop
operation, if appropriate for your application. Do not set the DragEventArgs.Effects
property in the DragEnter event, as it will be overwritten in the DragOver event.

The following example shows the DragEnter event handler for an Ellipse element. This
code previews the effects of the drag-and-drop operation by saving the current Fill
brush. It then uses the GetDataPresent method to check whether the DataObject being
dragged over the ellipse contains string data that can be converted to a Brush. If so, the
data is extracted using the GetData method. It is then converted to a Brush and applied
to the ellipse. The change is reverted in the DragLeave event handler. If the data cannot
be converted to a Brush, no action is performed.

C#
private Brush _previousFill = null;
private void ellipse_DragEnter(object sender, DragEventArgs e)
{
Ellipse ellipse = sender as Ellipse;
if (ellipse != null)
{
// Save the current Fill brush so that you can revert back to this
value in DragLeave.
_previousFill = ellipse.Fill;

// If the DataObject contains string data, extract it.


if (e.Data.GetDataPresent(DataFormats.StringFormat))
{
string dataString =
(string)e.Data.GetData(DataFormats.StringFormat);

// If the string can be converted into a Brush, convert it.


BrushConverter converter = new BrushConverter();
if (converter.IsValid(dataString))
{
Brush newFill =
(Brush)converter.ConvertFromString(dataString);
ellipse.Fill = newFill;
}
}
}
}

The DragOver event occurs continuously while the data is dragged over the drop target.
This event is paired with the GiveFeedback event on the drag source. In the DragOver
event handler, you typically use the GetDataPresent and GetData methods to check
whether the transferred data is in a format that the drop target can process. You can
also check whether any modifier keys are pressed, which will typically indicate whether
the user intends a move or copy action. After these checks are performed, you set the
DragEventArgs.Effects property to notify the drag source what effect dropping the data
will have. The drag source receives this information in the GiveFeedback event args, and
can set an appropriate cursor to give feedback to the user.

The following example shows the DragOver event handler for an Ellipse element. This
code checks to see if the DataObject being dragged over the ellipse contains string data
that can be converted to a Brush. If so, it sets the DragEventArgs.Effects property to
Copy. This indicates to the drag source that the data can be copied to the ellipse. If the
data cannot be converted to a Brush, the DragEventArgs.Effects property is set to None.
This indicates to the drag source that the ellipse is not a valid drop target for the data.

C#
private void ellipse_DragOver(object sender, DragEventArgs e)
{
e.Effects = DragDropEffects.None;

// If the DataObject contains string data, extract it.


if (e.Data.GetDataPresent(DataFormats.StringFormat))
{
string dataString =
(string)e.Data.GetData(DataFormats.StringFormat);

// If the string can be converted into a Brush, allow copying.


BrushConverter converter = new BrushConverter();
if (converter.IsValid(dataString))
{
e.Effects = DragDropEffects.Copy | DragDropEffects.Move;
}
}
}

The DragLeave event occurs when the data is dragged out of the target's boundary
without being dropped. You handle this event to undo anything that you did in the
DragEnter event handler.

The following example shows the DragLeave event handler for an Ellipse element. This
code undoes the preview performed in the DragEnter event handler by applying the
saved Brush to the ellipse.

C#

private void ellipse_DragLeave(object sender, DragEventArgs e)


{
Ellipse ellipse = sender as Ellipse;
if (ellipse != null)
{
ellipse.Fill = _previousFill;
}
}

The Drop event occurs when the data is dropped over the drop target; by default, this
happens when the mouse button is released. In the Drop event handler, you use the
GetData method to extract the transferred data from the DataObject and perform any
data processing that your application requires. The Drop event ends the drag-and-drop
operation.

The following example shows the Drop event handler for an Ellipse element. This code
applies the effects of the drag-and-drop operation, and is similar to the code in the
DragEnter event handler. It checks to see if the DataObject being dragged over the
ellipse contains string data that can be converted to a Brush. If so, the Brush is applied
to the ellipse. If the data cannot be converted to a Brush, no action is performed.

C#

private void ellipse_Drop(object sender, DragEventArgs e)


{
Ellipse ellipse = sender as Ellipse;
if (ellipse != null)
{
// If the DataObject contains string data, extract it.
if (e.Data.GetDataPresent(DataFormats.StringFormat))
{
string dataString =
(string)e.Data.GetData(DataFormats.StringFormat);

// If the string can be converted into a Brush,


// convert it and apply it to the ellipse.
BrushConverter converter = new BrushConverter();
if (converter.IsValid(dataString))
{
Brush newFill =
(Brush)converter.ConvertFromString(dataString);
ellipse.Fill = newFill;
}
}
}
}

See also
Clipboard
Walkthrough: Enabling Drag and Drop on a User Control
How-to Topics
Drag and Drop
Data and Data Objects
Article • 02/06/2023

Data that is transferred as part of a drag-and-drop operation is stored in a data object.


Conceptually, a data object consists of one or more of the following pairs:

An Object that contains the actual data.

A corresponding data format identifier.

The data itself can consist of anything that can be represented as a base Object. The
corresponding data format is a string or Type that provides a hint about what format the
data is in. Data objects support hosting multiple data/data format pairs; this enables a
single data object to provide data in multiple formats.

Data Objects
All data objects must implement the IDataObject interface, which provides the following
standard set of methods that enable and facilitate data transfer.

Method Summary

GetData Retrieves a data object in a specified data format.

GetDataPresent Checks to see whether the data is available in, or can be converted to, a
specified format.

GetFormats Returns a list of formats that the data in this data object is stored in, or can be
converted to.

SetData Stores the specified data in this data object.

WPF provides a basic implementation of IDataObject in the DataObject class. The stock
DataObject class is sufficient for many common data transfer scenarios.

There are several pre-defined formats, such as bitmap, CSV, file, HTML, RTF, string, text,
and audio. For information about pre-defined data formats provided with WPF, see the
DataFormats class reference topic.

Data objects commonly include a facility for automatically converting data stored in one
format to a different format while extracting data; this facility is referred to as auto-
convert. When querying for the data formats available in a data object, auto-convertible
data formats can be filtered from native data formats by calling the
GetFormats(Boolean) or GetDataPresent(String, Boolean) method and specifying the
autoConvert parameter as false . When adding data to a data object with the

SetData(String, Object, Boolean) method, auto-conversion of data can be prohibited by


setting the autoConvert parameter to false .

Working with Data Objects


This section describes common techniques for creating and working with data objects.

Creating New Data Objects


The DataObject class provides several overloaded constructors that facilitate populating
a new DataObject instance with a single data/data format pair.

The following example code creates a new data object and uses one of the overloaded
constructors DataObject(DataObject(String, Object)) to initialize the data object with a
string and a specified data format. In this case, the data format is specified by a string;
the DataFormats class provides a set of pre-defined type strings. Auto-conversion of the
stored data is allowed by default.

C#

string stringData = "Some string data to store...";


string dataFormat = DataFormats.UnicodeText;
DataObject dataObject = new DataObject(dataFormat, stringData);

For more examples of code that creates a data object, see Create a Data Object.

Storing Data in Multiple Formats


A single data object is able to store data in multiple formats. Strategic use of multiple
data formats within a single data object potentially makes the data object consumable
by a wider variety of drop targets than if only a single data format could be represented.
Note that, in general, a drag source must be agnostic about the data formats that are
consumable by potential drop targets.

The following example shows how to use the SetData(String, Object) method to add
data to a data object in multiple formats.

C#

DataObject dataObject = new DataObject();


string sourceData = "Some string data to store...";
// Encode the source string into Unicode byte arrays.
byte[] unicodeText = Encoding.Unicode.GetBytes(sourceData); // UTF-16
byte[] utf8Text = Encoding.UTF8.GetBytes(sourceData);
byte[] utf32Text = Encoding.UTF32.GetBytes(sourceData);

// The DataFormats class does not provide data format fields for denoting
// UTF-32 and UTF-8, which are seldom used in practice; the following
strings
// will be used to identify these "custom" data formats.
string utf32DataFormat = "UTF-32";
string utf8DataFormat = "UTF-8";

// Store the text in the data object, letting the data object choose
// the data format (which will be DataFormats.Text in this case).
dataObject.SetData(sourceData);
// Store the Unicode text in the data object. Text data can be
automatically
// converted to Unicode (UTF-16 / UCS-2) format on extraction from the data
object;
// Therefore, explicitly converting the source text to Unicode is generally
unnecessary, and
// is done here as an exercise only.
dataObject.SetData(DataFormats.UnicodeText, unicodeText);
// Store the UTF-8 text in the data object...
dataObject.SetData(utf8DataFormat, utf8Text);
// Store the UTF-32 text in the data object...
dataObject.SetData(utf32DataFormat, utf32Text);

Querying a Data Object for Available Formats


Because a single data object can contain an arbitrary number of data formats, data
objects include facilities for retrieving a list of available data formats.

The following example code uses the GetFormats overload to get an array of strings
denoting all data formats available in a data object (both native and by auto-convert).

C#

DataObject dataObject = new DataObject("Some string data to store...");

// Get an array of strings, each string denoting a data format


// that is available in the data object. This overload of GetDataFormats
// returns all available data formats, native and auto-convertible.
string[] dataFormats = dataObject.GetFormats();

// Get the number of data formats present in the data object, including both
// auto-convertible and native data formats.
int numberOfDataFormats = dataFormats.Length;

// To enumerate the resulting array of data formats, and take some action
when
// a particular data format is found, use a code structure similar to the
following.
foreach (string dataFormat in dataFormats)
{
if (dataFormat == DataFormats.Text)
{
// Take some action if/when data in the Text data format is found.
break;
}
else if(dataFormat == DataFormats.StringFormat)
{
// Take some action if/when data in the string data format is found.
break;
}
}

For more examples of code that queries a data object for available data formats, see List
the Data Formats in a Data Object. For examples of querying a data object for the
presence of a particular data format, see Determine if a Data Format is Present in a Data
Object.

Retrieving Data from a Data Object


Retrieving data from a data object in a particular format simply involves calling one of
the GetData methods and specifying the desired data format. One of the
GetDataPresent methods can be used to check for the presence of a particular data
format. GetData returns the data in an Object; depending on the data format, this object
can be cast to a type-specific container.

The following example code uses the GetDataPresent(String) overload to check if a


specified data format is available (native or by auto-convert). If the specified format is
available, the example retrieves the data by using the GetData(String) method.

C#

DataObject dataObject = new DataObject("Some string data to store...");

string desiredFormat = DataFormats.UnicodeText;


byte[] data = null;

// Use the GetDataPresent method to check for the presence of a desired data
format.
// This particular overload of GetDataPresent looks for both native and
auto-convertible
// data formats.
if (dataObject.GetDataPresent(desiredFormat))
{
// If the desired data format is present, use one of the GetData methods
to retrieve the
// data from the data object.
data = dataObject.GetData(desiredFormat) as byte[];
}

For more examples of code that retrieves data from a data object, see Retrieve Data in a
Particular Data Format.

Removing Data From a Data Object


Data cannot be directly removed from a data object. To effectively remove data from a
data object, follow these steps:

1. Create a new data object that will contain only the data you want to retain.

2. "Copy" the desired data from the old data object to the new data object. To copy
the data, use one of the GetData methods to retrieve an Object that contains the
raw data, and then use one of the SetData methods to add the data to the new
data object.

3. Replace the old data object with the new one.

7 Note

The SetData methods only add data to a data object; they do not replace data,
even if the data and data format are exactly the same as a previous call. Calling
SetData twice for the same data and data format will result in the data/data format
being present twice in the data object.
Walkthrough: Enabling Drag and Drop
on a User Control
Article • 02/06/2023

This walkthrough demonstrates how to create a custom user control that can participate
in drag-and-drop data transfer in Windows Presentation Foundation (WPF).

In this walkthrough, you will create a custom WPF UserControl that represents a circle
shape. You will implement functionality on the control to enable data transfer through
drag-and-drop. For example, if you drag from one Circle control to another, the Fill
color data is copied from the source Circle to the target. If you drag from a Circle
control to a TextBox, the string representation of the Fill color is copied to the TextBox.
You will also create a small application that contains two panel controls and a TextBox to
test the drag-and-drop functionality. You will write code that enables the panels to
process dropped Circle data, which will enable you to move or copy Circles from the
Children collection of one panel to the other.

This walkthrough illustrates the following tasks:

Create a custom user control.

Enable the user control to be a drag source.

Enable the user control to be a drop target.

Enable a panel to receive data dropped from the user control.

Prerequisites
You need Visual Studio to complete this walkthrough.

Create the Application Project


In this section, you will create the application infrastructure, which includes a main page
with two panels and a TextBox.

1. Create a new WPF Application project in Visual Basic or Visual C# named


DragDropExample . For more information, see Walkthrough: My first WPF desktop
application.

2. Open MainWindow.xaml.
3. Add the following markup between the opening and closing Grid tags.

This markup creates the user interface for the test application.

XAML

<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"
Background="Beige">
<TextBox Width="Auto" Margin="2"
Text="green"/>
</StackPanel>
<StackPanel Grid.Column="1"
Background="Bisque">
</StackPanel>

Add a New User Control to the Project


In this section, you will add a new user control to the project.

1. On the Project menu, select Add User Control.

2. In the Add New Item dialog box, change the name to Circle.xaml , and click Add.

Circle.xaml and its code-behind is added to the project.

3. Open Circle.xaml.

This file will contain the user interface elements of the user control.

4. Add the following markup to the root Grid to create a simple user control that has
a blue circle as its UI.

XAML

<Ellipse x:Name="circleUI"
Height="100" Width="100"
Fill="Blue" />

5. Open Circle.xaml.cs or Circle.xaml.vb.

6. In C#, add the following code after the parameterless constructor to create a copy
constructor. In Visual Basic, add the following code to create both a parameterless
constructor and a copy constructor.
In order to allow the user control to be copied, you add a copy constructor
method in the code-behind file. In the simplified Circle user control, you will only
copy the Fill and the size of the of the user control.

C#

public Circle(Circle c)
{
InitializeComponent();
this.circleUI.Height = c.circleUI.Height;
this.circleUI.Width = c.circleUI.Height;
this.circleUI.Fill = c.circleUI.Fill;
}

Add the user control to the main window


1. Open MainWindow.xaml.

2. Add the following XAML to the opening Window tag to create an XML namespace
reference to the current application.

XAML

xmlns:local="clr-namespace:DragDropExample"

3. In the first StackPanel, add the following XAML to create two instances of the Circle
user control in the first panel.

XAML

<local:Circle Margin="2" />


<local:Circle Margin="2" />

The full XAML for the panel looks like the following.

XAML

<StackPanel Grid.Column="0"
Background="Beige">
<TextBox Width="Auto" Margin="2"
Text="green"/>
<local:Circle Margin="2" />
<local:Circle Margin="2" />
</StackPanel>
<StackPanel Grid.Column="1"
Background="Bisque">
</StackPanel>

Implement Drag Source Events in the User


Control
In this section, you will override the OnMouseMove method and initiate the drag-and-
drop operation.

If a drag is started (a mouse button is pressed and the mouse is moved), you will
package the data to be transferred into a DataObject. In this case, the Circle control will
package three data items; a string representation of its Fill color, a double
representation of its height, and a copy of itself.

To initiate a drag-and-drop operation


1. Open Circle.xaml.cs or Circle.xaml.vb.

2. Add the following OnMouseMove override to provide class handling for the
MouseMove event.

C#

protected override void OnMouseMove(MouseEventArgs e)


{
base.OnMouseMove(e);
if (e.LeftButton == MouseButtonState.Pressed)
{
// Package the data.
DataObject data = new DataObject();
data.SetData(DataFormats.StringFormat,
circleUI.Fill.ToString());
data.SetData("Double", circleUI.Height);
data.SetData("Object", this);

// Initiate the drag-and-drop operation.


DragDrop.DoDragDrop(this, data, DragDropEffects.Copy |
DragDropEffects.Move);
}
}

This OnMouseMove override performs the following tasks:

Checks whether the left mouse button is pressed while the mouse is moving.
Packages the Circle data into a DataObject. In this case, the Circle control
packages three data items; a string representation of its Fill color, a double
representation of its height, and a copy of itself.

Calls the static DragDrop.DoDragDrop method to initiate the drag-and-drop


operation. You pass the following three parameters to the DoDragDrop
method:

dragSource – A reference to this control.

data – The DataObject created in the previous code.

allowedEffects – The allowed drag-and-drop operations, which are Copy


or Move.

3. Press F5 to build and run the application.

4. Click one of the Circle controls and drag it over the panels, the other Circle, and
the TextBox. When dragging over the TextBox, the cursor changes to indicate a
move.

5. While dragging a Circle over the TextBox, press the Ctrl key. Notice how the cursor
changes to indicate a copy.

6. Drag and drop a Circle onto the TextBox. The string representation of the Circle’s
fill color is appended to the TextBox.

By default, the cursor will change during a drag-and-drop operation to indicate what
effect dropping the data will have. You can customize the feedback given to the user by
handling the GiveFeedback event and setting a different cursor.
Give feedback to the user
1. Open Circle.xaml.cs or Circle.xaml.vb.

2. Add the following OnGiveFeedback override to provide class handling for the
GiveFeedback event.

C#

protected override void OnGiveFeedback(GiveFeedbackEventArgs e)


{
base.OnGiveFeedback(e);
// These Effects values are set in the drop target's
// DragOver event handler.
if (e.Effects.HasFlag(DragDropEffects.Copy))
{
Mouse.SetCursor(Cursors.Cross);
}
else if (e.Effects.HasFlag(DragDropEffects.Move))
{
Mouse.SetCursor(Cursors.Pen);
}
else
{
Mouse.SetCursor(Cursors.No);
}
e.Handled = true;
}

This OnGiveFeedback override performs the following tasks:

Checks the Effects values that are set in the drop target's DragOver event
handler.

Sets a custom cursor based on the Effects value. The cursor is intended to
give visual feedback to the user about what effect dropping the data will
have.

3. Press F5 to build and run the application.

4. Drag one of the Circle controls over the panels, the other Circle, and the TextBox.
Notice that the cursors are now the custom cursors that you specified in the
OnGiveFeedback override.
5. Select the text green from the TextBox.

6. Drag the green text to a Circle control. Notice that the default cursors are shown
to indicate the effects of the drag-and-drop operation. The feedback cursor is
always set by the drag source.

Implement Drop Target Events in the User


Control
In this section, you will specify that the user control is a drop target, override the
methods that enable the user control to be a drop target, and process the data that is
dropped on it.

To enable the user control to be a drop target


1. Open Circle.xaml.

2. In the opening UserControl tag, add the AllowDrop property and set it to true .

XAML

<UserControl x:Class="DragDropWalkthrough.Circle"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"

xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
AllowDrop="True">

The OnDrop method is called when the AllowDrop property is set to true and data
from the drag source is dropped on the Circle user control. In this method, you will
process the data that was dropped and apply the data to the Circle.

To process the dropped data


1. Open Circle.xaml.cs or Circle.xaml.vb.

2. Add the following OnDrop override to provide class handling for the Drop event.

C#

protected override void OnDrop(DragEventArgs e)


{
base.OnDrop(e);

// If the DataObject contains string data, extract it.


if (e.Data.GetDataPresent(DataFormats.StringFormat))
{
string dataString =
(string)e.Data.GetData(DataFormats.StringFormat);

// If the string can be converted into a Brush,


// convert it and apply it to the ellipse.
BrushConverter converter = new BrushConverter();
if (converter.IsValid(dataString))
{
Brush newFill =
(Brush)converter.ConvertFromString(dataString);
circleUI.Fill = newFill;

// Set Effects to notify the drag source what effect


// the drag-and-drop operation had.
// (Copy if CTRL is pressed; otherwise, move.)
if (e.KeyStates.HasFlag(DragDropKeyStates.ControlKey))
{
e.Effects = DragDropEffects.Copy;
}
else
{
e.Effects = DragDropEffects.Move;
}
}
}
e.Handled = true;
}
This OnDrop override performs the following tasks:

Uses the GetDataPresent method to check if the dragged data contains a


string object.

Uses the GetData method to extract the string data if it is present.

Uses a BrushConverter to try to convert the string to a Brush.

If the conversion is successful, applies the brush to the Fill of the Ellipse that
provides the UI of the Circle control.

Marks the Drop event as handled. You should mark the drop event as
handled so that other elements that receive this event know that the Circle
user control handled it.

3. Press F5 to build and run the application.

4. Select the text green in the TextBox.

5. Drag the text to a Circle control and drop it. The Circle changes from blue to green.

6. Type the text green in the TextBox.

7. Select the text gre in the TextBox.

8. Drag it to a Circle control and drop it. Notice that the cursor changes to indicate
that the drop is allowed, but the color of the Circle does not change because gre
is not a valid color.

9. Drag from the green Circle control and drop on the blue Circle control. The Circle
changes from blue to green. Notice that which cursor is shown depends on
whether the TextBox or the Circle is the drag source.

Setting the AllowDrop property to true and processing the dropped data is all that is
required to enable an element to be a drop target. However, to provide a better user
experience, you should also handle the DragEnter, DragLeave, and DragOver events. In
these events, you can perform checks and provide additional feedback to the user
before the data is dropped.

When data is dragged over the Circle user control, the control should notify the drag
source whether it can process the data that is being dragged. If the control does not
know how to process the data, it should refuse the drop. To do this, you will handle the
DragOver event and set the Effects property.

To verify that the data drop is allowed


1. Open Circle.xaml.cs or Circle.xaml.vb.

2. Add the following OnDragOver override to provide class handling for the
DragOver event.

C#

protected override void OnDragOver(DragEventArgs e)


{
base.OnDragOver(e);
e.Effects = DragDropEffects.None;

// If the DataObject contains string data, extract it.


if (e.Data.GetDataPresent(DataFormats.StringFormat))
{
string dataString =
(string)e.Data.GetData(DataFormats.StringFormat);

// If the string can be converted into a Brush, allow copying


or moving.
BrushConverter converter = new BrushConverter();
if (converter.IsValid(dataString))
{
// Set Effects to notify the drag source what effect
// the drag-and-drop operation will have. These values are
// used by the drag source's GiveFeedback event handler.
// (Copy if CTRL is pressed; otherwise, move.)
if (e.KeyStates.HasFlag(DragDropKeyStates.ControlKey))
{
e.Effects = DragDropEffects.Copy;
}
else
{
e.Effects = DragDropEffects.Move;
}
}
}
e.Handled = true;
}

This OnDragOver override performs the following tasks:

Sets the Effects property to None.

Performs the same checks that are performed in the OnDrop method to
determine whether the Circle user control can process the dragged data.

If the user control can process the data, sets the Effects property to Copy or
Move.

3. Press F5 to build and run the application.

4. Select the text gre in the TextBox.

5. Drag the text to a Circle control. Notice that the cursor now changes to indicate
that the drop is not allowed because gre is not a valid color.

You can further enhance the user experience by applying a preview of the drop
operation. For the Circle user control, you will override the OnDragEnter and
OnDragLeave methods. When the data is dragged over the control, the current
background Fill is saved in a placeholder variable. The string is then converted to a
brush and applied to the Ellipse that provides the Circle's UI. If the data is dragged out
of the Circle without being dropped, the original Fill value is re-applied to the Circle.

To preview the effects of the drag-and-drop operation


1. Open Circle.xaml.cs or Circle.xaml.vb.

2. In the Circle class, declare a private Brush variable named _previousFill and
initialize it to null .

C#

public partial class Circle : UserControl


{
private Brush _previousFill = null;

3. Add the following OnDragEnter override to provide class handling for the
DragEnter event.
C#

protected override void OnDragEnter(DragEventArgs e)


{
base.OnDragEnter(e);
// Save the current Fill brush so that you can revert back to this
value in DragLeave.
_previousFill = circleUI.Fill;

// If the DataObject contains string data, extract it.


if (e.Data.GetDataPresent(DataFormats.StringFormat))
{
string dataString =
(string)e.Data.GetData(DataFormats.StringFormat);

// If the string can be converted into a Brush, convert it.


BrushConverter converter = new BrushConverter();
if (converter.IsValid(dataString))
{
Brush newFill =
(Brush)converter.ConvertFromString(dataString.ToString());
circleUI.Fill = newFill;
}
}
}

This OnDragEnter override performs the following tasks:

Saves the Fill property of the Ellipse in the _previousFill variable.

Performs the same checks that are performed in the OnDrop method to
determine whether the data can be converted to a Brush.

If the data is converted to a valid Brush, applies it to the Fill of the Ellipse.

4. Add the following OnDragLeave override to provide class handling for the
DragLeave event.

C#

protected override void OnDragLeave(DragEventArgs e)


{
base.OnDragLeave(e);
// Undo the preview that was applied in OnDragEnter.
circleUI.Fill = _previousFill;
}

This OnDragLeave override performs the following tasks:


Applies the Brush saved in the _previousFill variable to the Fill of the Ellipse
that provides the UI of the Circle user control.

5. Press F5 to build and run the application.

6. Select the text green in the TextBox.

7. Drag the text over a Circle control without dropping it. The Circle changes from
blue to green.

8. Drag the text away from the Circle control. The Circle changes from green back to
blue.

Enable a Panel to Receive Dropped Data


In this section, you enable the panels that host the Circle user controls to act as drop
targets for dragged Circle data. You will implement code that enables you to move a
Circle from one panel to another, or to make a copy of a Circle control by holding down
the Ctrl key while dragging and dropping a Circle.

1. Open MainWindow.xaml.

2. As shown in the following XAML, in each of the StackPanel controls, add handlers
for the DragOver and Drop events. Name the DragOver event handler,
panel_DragOver , and name the Drop event handler, panel_Drop .

By default, the panels aren't drop targets. To enable them, add the AllowDrop
property to both panels and set the value to true .

XAML
<StackPanel Grid.Column="0"
Background="Beige"
AllowDrop="True"
DragOver="panel_DragOver"
Drop="panel_Drop">
<TextBox Width="Auto" Margin="2"
Text="green"/>
<local:Circle Margin="2" />
<local:Circle Margin="2" />
</StackPanel>
<StackPanel Grid.Column="1"
Background="Bisque"
AllowDrop="True"
DragOver="panel_DragOver"
Drop="panel_Drop">
</StackPanel>

3. Open MainWindows.xaml.cs or MainWindow.xaml.vb.

4. Add the following code for the DragOver event handler.

C#

private void panel_DragOver(object sender, DragEventArgs e)


{
if (e.Data.GetDataPresent("Object"))
{
// These Effects values are used in the drag source's
// GiveFeedback event handler to determine which cursor to
display.
if (e.KeyStates == DragDropKeyStates.ControlKey)
{
e.Effects = DragDropEffects.Copy;
}
else
{
e.Effects = DragDropEffects.Move;
}
}
}

This DragOver event handler performs the following tasks:

Checks that the dragged data contains the "Object" data that was packaged
in the DataObject by the Circle user control and passed in the call to
DoDragDrop.

If the "Object" data is present, checks whether the Ctrl key is pressed.
If the Ctrl key is pressed, sets the Effects property to Copy. Otherwise, set the
Effects property to Move.

5. Add the following code for the Drop event handler.

C#

private void panel_Drop(object sender, DragEventArgs e)


{
// If an element in the panel has already handled the drop,
// the panel should not also handle it.
if (e.Handled == false)
{
Panel _panel = (Panel)sender;
UIElement _element = (UIElement)e.Data.GetData("Object");

if (_panel != null && _element != null)


{
// Get the panel that the element currently belongs to,
// then remove it from that panel and add it the Children
of
// the panel that its been dropped on.
Panel _parent =
(Panel)VisualTreeHelper.GetParent(_element);

if (_parent != null)
{
if (e.KeyStates == DragDropKeyStates.ControlKey &&
e.AllowedEffects.HasFlag(DragDropEffects.Copy))
{
Circle _circle = new Circle((Circle)_element);
_panel.Children.Add(_circle);
// set the value to return to the DoDragDrop call
e.Effects = DragDropEffects.Copy;
}
else if
(e.AllowedEffects.HasFlag(DragDropEffects.Move))
{
_parent.Children.Remove(_element);
_panel.Children.Add(_element);
// set the value to return to the DoDragDrop call
e.Effects = DragDropEffects.Move;
}
}
}
}
}

This Drop event handler performs the following tasks:

Checks whether the Drop event has already been handled. For instance, if a
Circle is dropped on another Circle which handles the Drop event, you do not
want the panel that contains the Circle to also handle it.

If the Drop event is not handled, checks whether the Ctrl key is pressed.

If the Ctrl key is pressed when the Drop happens, makes a copy of the Circle
control and add it to the Children collection of the StackPanel.

If the Ctrl key is not pressed, moves the Circle from the Children collection of
its parent panel to the Children collection of the panel that it was dropped
on.

Sets the Effects property to notify the DoDragDrop method whether a move
or copy operation was performed.

6. Press F5 to build and run the application.

7. Select the text green from the TextBox.

8. Drag the text over a Circle control and drop it.

9. Drag a Circle control from the left panel to the right panel and drop it. The Circle is
removed from the Children collection of the left panel and added to the Children
collection of the right panel.

10. Drag a Circle control from the panel it is in to the other panel and drop it while
pressing the Ctrl key. The Circle is copied and the copy is added to the Children
collection of the receiving panel.

See also
Drag and Drop Overview
Drag and Drop How-to Topics
Article • 02/06/2023

The following examples demonstrate how to accomplish common tasks using the
Windows Presentation Foundation (WPF) drag-and-drop framework.

In This Section
Open a File That is Dropped on a RichTextBox Control
Create a Data Object
Determine if a Data Format is Present in a Data Object
List the Data Formats in a Data Object
Retrieve Data in a Particular Data Format
Store Multiple Data Formats in a Data Object

See also
Drag and Drop Overview
How to: Open a File That is Dropped on
a RichTextBox Control
Article • 07/27/2022

In Windows Presentation Foundation (WPF), the TextBox, RichTextBox, and


FlowDocument controls all have built-in drag-and-drop functionality. The built-in
functionality enables drag-and-drop of text within and between the controls. However,
it does not enable opening a file by dropping the file on the control. These controls also
mark the drag-and-drop events as handled. As a result, by default, you cannot add your
own event handlers to provide functionality to open dropped files.

To add additional handling for drag-and-drop events in these controls, use the
AddHandler(RoutedEvent, Delegate, Boolean) method to add your event handlers for
the drag-and-drop events. Set the handledEventsToo parameter to true to have the
specified handler be invoked for a routed event that has already been marked as
handled by another element along the event route.

 Tip

You can replace the built-in drag-and-drop functionality of TextBox, RichTextBox,


and FlowDocument by handling the preview versions of the drag-and-drop events
and marking the preview events as handled. However, this will disable the built-in
drag-and-drop functionality, and is not recommended.

Example
The following example demonstrates how to add handlers for the DragOver and Drop
events on a RichTextBox. This example uses the AddHandler(RoutedEvent, Delegate,
Boolean) method and sets the handledEventsToo parameter to true so that the events
handlers will be invoked even though the RichTextBox marks these events as handled.
The code in the event handlers adds functionality to open a text file that is dropped on
the RichTextBox.

To test this example, drag a text file or a rich text format (RTF) file from Windows
Explorer to the RichTextBox. The file will be opened in the RichTextBox. If you press the
SHIFT key before the dropping the file, the file will be opened as plain text.

XAML
<RichTextBox x:Name="richTextBox1"
AllowDrop="True" />

C#

public MainWindow()
{
InitializeComponent();

// Add using System.Windows.Controls;


richTextBox1.AddHandler(RichTextBox.DragOverEvent, new
DragEventHandler(RichTextBox_DragOver), true);
richTextBox1.AddHandler(RichTextBox.DropEvent, new
DragEventHandler(RichTextBox_Drop), true);
}

private void RichTextBox_DragOver(object sender, DragEventArgs e)


{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effects = DragDropEffects.All;
}
else
{
e.Effects = DragDropEffects.None;
}
e.Handled = false;
}

private void RichTextBox_Drop(object sender, DragEventArgs e)


{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] docPath = (string[])e.Data.GetData(DataFormats.FileDrop);

// By default, open as Rich Text (RTF).


var dataFormat = DataFormats.Rtf;

// If the Shift key is pressed, open as plain text.


if (e.KeyStates == DragDropKeyStates.ShiftKey)
{
dataFormat = DataFormats.Text;
}

System.Windows.Documents.TextRange range;
System.IO.FileStream fStream;
if (System.IO.File.Exists(docPath[0]))
{
try
{
// Open the document in the RichTextBox.
range = new
System.Windows.Documents.TextRange(richTextBox1.Document.ContentStart,
richTextBox1.Document.ContentEnd);
fStream = new System.IO.FileStream(docPath[0],
System.IO.FileMode.OpenOrCreate);
range.Load(fStream, dataFormat);
fStream.Close();
}
catch (System.Exception)
{
MessageBox.Show("File could not be opened. Make sure the
file is a text file.");
}
}
}
}
How to: Create a Data Object
Article • 02/06/2023

The following examples show various ways to create a data object using the
constructors provided by the DataObject class.

DataObject(Object) constructor

Description
The following example code creates a new data object and uses one of the overloaded
constructors (DataObject(Object)) to initialize the data object with a string. In this case,
an appropriate data format is determined automatically according to the stored data's
type, and auto-converting of the stored data is allowed by default.

Code
C#

string stringData = "Some string data to store...";


DataObject dataObject = new DataObject(stringData);

Description
The following example code is a condensed version of the code shown above.

Code
C#

DataObject dataObject = new DataObject("Some string data to store...");

DataObject(String, Object) constructor

Description
The following example code creates a new data object and uses one of the overloaded
constructors (DataObject(String, Object)) to initialize the data object with a string and a
specified data format. In this case the data format is specified by a string; the
DataFormats class provides a set of pre-defined type strings. Auto-converting of the
stored data is allowed by default.

Code
C#

string stringData = "Some string data to store...";


string dataFormat = DataFormats.UnicodeText;
DataObject dataObject = new DataObject(dataFormat, stringData);

Description
The following example code is a condensed version of the code shown above.

Code
C#

DataObject dataObject = new DataObject(DataFormats.UnicodeText, "Some string


data to store...");

DataObject() constructor

Description
The following example code creates a new data object and uses one of the overloaded
constructors (DataObject) to initialize the data object with a string and a specified data
format. In this case the data format is specified by a Type parameter. Auto-converting of
the stored data is allowed by default.

Code
C#

string stringData = "Some string data to store...";


Type dataFormat = stringData.GetType();
DataObject dataObject = new DataObject(dataFormat, stringData);

Description
The following example code is a condensed version of the code shown above.

Code
C#

DataObject dataObject = new DataObject("".GetType(), "Some string data to


store...");

DataObject(String, Object, Boolean)


constructor

Description
The following example code creates a new data object and uses one of the overloaded
constructors (DataObject(String, Object, Boolean)) to initialize the data object with a
string and a specified data format. In this case the data format is specified by a string;
the DataFormats class provides a set of pre-defined type strings. This particular
constructor overload enables the caller to specify whether auto-converting is allowed.

Code
C#

string stringData = "Some string data to store...";


string dataFormat = DataFormats.Text;
bool autoConvert = false;
DataObject dataObject = new DataObject(dataFormat, stringData, autoConvert);

Description
The following example code is a condensed version of the code shown above.

Code
C#

DataObject dataObject = new DataObject(DataFormats.Text, "Some string data


to store...", false);

See also
IDataObject
How to: Determine if a Data Format is
Present in a Data Object
Article • 02/06/2023

The following examples show how to use the various GetDataPresent method overloads
to query whether a particular data format is present in a data object.

GetDataPresent(String) overload

Description
The following example code uses the GetDataPresent(String) overload to query for the
presence of a particular data format by descriptor string.

Code
C#

DataObject dataObject = new DataObject("Some string data to store...");

// Query for the presence of Text data in the data object, by a data format
descriptor string.
// In this overload of GetDataPresent, the method will return true both for
native data formats
// and when the data can automatically be converted to the specifed format.

// In this case, string data is present natively, so GetDataPresent returns


"true".
string textData = null;
if (dataObject.GetDataPresent(DataFormats.StringFormat))
{
textData = dataObject.GetData(DataFormats.StringFormat) as string;
}

// In this case, the Text data in the data object can be autoconverted to
// Unicode text, so GetDataPresent returns "true".
byte[] unicodeData = null;
if (dataObject.GetDataPresent(DataFormats.UnicodeText))
{
unicodeData = dataObject.GetData(DataFormats.UnicodeText) as byte[];
}

GetDataPresent(Type) overload
Description
The following example code uses the GetDataPresent(Type) overload to query for the
presence of a particular data format by type.

Code
C#

DataObject dataObject = new DataObject("Some string data to store...");

// Query for the presence of String data in the data object, by type. In
this overload
// of GetDataPresent, the method will return true both for native data
formats
// and when the data can automatically be converted to the specifed format.

// In this case, the Text data present in the data object can be
autoconverted
// to type string (also represented by DataFormats.String), so
GetDataPresent returns "true".
string stringData = null;
if (dataObject.GetDataPresent(typeof(string)))
{
stringData = dataObject.GetData(DataFormats.Text) as string;
}

GetDataPresent(String, Boolean) overload

Description
The following example code uses the GetDataPresent(String, Boolean) overload to query
for data by descriptor string, and specifying how to treat auto-convertible data formats.

Code
C#

DataObject dataObject = new DataObject("Some string data to store...");

// Query for the presence of Text data in the data object, by data format
descriptor string,
// and specifying whether auto-convertible data formats are acceptable.

// In this case, Text data is present natively, so GetDataPresent returns


"true".
string textData = null;
if (dataObject.GetDataPresent(DataFormats.Text, false /* Auto-convert? */))
{
textData = dataObject.GetData(DataFormats.Text) as string;
}

// In this case, the Text data in the data object can be autoconverted to
// Unicode text, but it is not available natively, so GetDataPresent returns
"false".
byte[] unicodeData = null;
if (dataObject.GetDataPresent(DataFormats.UnicodeText, false /* Auto-
convert? */))
{
unicodeData = dataObject.GetData(DataFormats.UnicodeText) as byte[];
}

// In this case, the Text data in the data object can be autoconverted to
// Unicode text, so GetDataPresent returns "true".
if (dataObject.GetDataPresent(DataFormats.UnicodeText, true /* Auto-convert?
*/))
{
unicodeData = dataObject.GetData(DataFormats.UnicodeText) as byte[];
}

See also
IDataObject
How to: List the Data Formats in a Data
Object
Article • 02/06/2023

The following examples show how to use the GetFormats method overloads get an
array of strings denoting each data format that is available in a data object.

GetFormats() overload for all Data Formats

Description
The following example code uses the GetFormats overload to get an array of strings
denoting all data formats available in a data object (both native and auto-convertible).

Code
C#

DataObject dataObject = new DataObject("Some string data to store...");

// Get an array of strings, each string denoting a data format


// that is available in the data object. This overload of GetDataFormats
// returns all available data formats, native and auto-convertible.
string[] dataFormats = dataObject.GetFormats();

// Get the number of data formats present in the data object, including both
// auto-convertible and native data formats.
int numberOfDataFormats = dataFormats.Length;

// To enumerate the resulting array of data formats, and take some action
when
// a particular data format is found, use a code structure similar to the
following.
foreach (string dataFormat in dataFormats)
{
if (dataFormat == DataFormats.Text)
{
// Take some action if/when data in the Text data format is found.
break;
}
else if(dataFormat == DataFormats.StringFormat)
{
// Take some action if/when data in the string data format is found.
break;
}
}

GetFormats() overload for native Data Formats

Description
The following example code uses the GetFormats overload to get an array of strings
denoting only data formats available in a data object (auto-convertible data formats are
filtered).

Code
C#

DataObject dataObject = new DataObject("Some string data to store...");

// Get an array of strings, each string denoting a data format


// that is available in the data object. This overload of GetDataFormats
// accepts a Boolean parameter inidcating whether to include auto-
convertible
// data formats, or only return native data formats.
string[] dataFormats = dataObject.GetFormats(false /* Include auto-
convertible? */);

// Get the number of native data formats present in the data object.
int numberOfDataFormats = dataFormats.Length;

// To enumerate the resulting array of data formats, and take some action
when
// a particular data format is found, use a code structure similar to the
following.
foreach (string dataFormat in dataFormats)
{
if (dataFormat == DataFormats.Text)
{
// Take some action if/when data in the Text data format is found.
break;
}
}

See also
IDataObject
Drag and Drop Overview
How to: Retrieve Data in a Particular
Data Format
Article • 02/06/2023

The following examples show how to retrieve data from a data object in a specified
format.

Use the GetDataPresent(String) overload to


retrieve the data

Description
The following example code uses the GetDataPresent(String) overload to first check if a
specified data format is available (natively or by auto-convert); if the specified format is
available, the example retrieves the data by using the GetData(String) method.

Code
C#

DataObject dataObject = new DataObject("Some string data to store...");

string desiredFormat = DataFormats.UnicodeText;


byte[] data = null;

// Use the GetDataPresent method to check for the presence of a desired data
format.
// This particular overload of GetDataPresent looks for both native and
auto-convertible
// data formats.
if (dataObject.GetDataPresent(desiredFormat))
{
// If the desired data format is present, use one of the GetData methods
to retrieve the
// data from the data object.
data = dataObject.GetData(desiredFormat) as byte[];
}

Use the GetDataPresent(String, Boolean)


overload to retrieve the data
Description
The following example code uses the GetDataPresent(String, Boolean) overload to first
check if a specified data format is available natively (auto-convertible data formats are
filtered); if the specified format is available, the example retrieves the data by using the
GetData(String) method.

Code
C#

DataObject dataObject = new DataObject("Some string data to store...");

string desiredFormat = DataFormats.UnicodeText;


bool noAutoConvert = false;
byte[] data = null;

// Use the GetDataPresent method to check for the presence of a desired data
format.
// The autoconvert parameter is set to false to filter out auto-convertible
data formats,
// returning true only if the specified data format is available natively.
if (dataObject.GetDataPresent(desiredFormat, noAutoConvert))
{
// If the desired data format is present, use one of the GetData methods
to retrieve the
// data from the data object.
data = dataObject.GetData(desiredFormat) as byte[];
}

See also
IDataObject
Drag and Drop Overview
How to: Store Multiple Data Formats in
a Data Object
Article • 02/06/2023

The following example shows how to use the SetData(String, Object) method to add
data to a data object in multiple formats.

Example

Description

Code
C#

DataObject dataObject = new DataObject();


string sourceData = "Some string data to store...";

// Encode the source string into Unicode byte arrays.


byte[] unicodeText = Encoding.Unicode.GetBytes(sourceData); // UTF-16
byte[] utf8Text = Encoding.UTF8.GetBytes(sourceData);
byte[] utf32Text = Encoding.UTF32.GetBytes(sourceData);

// The DataFormats class does not provide data format fields for denoting
// UTF-32 and UTF-8, which are seldom used in practice; the following
strings
// will be used to identify these "custom" data formats.
string utf32DataFormat = "UTF-32";
string utf8DataFormat = "UTF-8";

// Store the text in the data object, letting the data object choose
// the data format (which will be DataFormats.Text in this case).
dataObject.SetData(sourceData);
// Store the Unicode text in the data object. Text data can be
automatically
// converted to Unicode (UTF-16 / UCS-2) format on extraction from the data
object;
// Therefore, explicitly converting the source text to Unicode is generally
unnecessary, and
// is done here as an exercise only.
dataObject.SetData(DataFormats.UnicodeText, unicodeText);
// Store the UTF-8 text in the data object...
dataObject.SetData(utf8DataFormat, utf8Text);
// Store the UTF-32 text in the data object...
dataObject.SetData(utf32DataFormat, utf32Text);
See also
IDataObject
Drag and Drop Overview
Resources (WPF)
Article • 02/06/2023

A resource is an object that can be reused in different places in your application. WPF
supports different types of resources. These resources are primarily two types of
resources: XAML resources and resource data files. Examples of XAML resources include
brushes and styles. Resource data files are non-executable data files that an application
needs.

In This Section
XAML Resources
WPF Application Resource, Content, and Data Files
Pack URIs in WPF

Reference
ResourceDictionary

StaticResource Markup Extension

DynamicResource Markup Extension

x:Key Directive

Related Sections
XAML in WPF
Overview of XAML resources
Article • 12/08/2020

A resource is an object that can be reused in different places in your app. Examples of
resources include brushes and styles. This overview describes how to use resources in
Extensible Application Markup Language (XAML). You can also create and access
resources by using code.

7 Note

XAML resources described in this article are different from app resources which are
generally files added to an app, such as content, data, or embedded files.

Using resources in XAML


The following example defines a SolidColorBrush as a resource on the root element of a
page. The example then references the resource and uses it to set properties of several
child elements, including an Ellipse, a TextBlock, and a Button.

XAML

<Page Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Page.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
<Style TargetType="Border" x:Key="PageBackground">
<Setter Property="Background" Value="Blue"/>
</Style>
<Style TargetType="TextBlock" x:Key="TitleText">
<Setter Property="Background" Value="Blue"/>
<Setter Property="DockPanel.Dock" Value="Top"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Foreground" Value="#4E87D4"/>
<Setter Property="FontFamily" Value="Trebuchet MS"/>
<Setter Property="Margin" Value="0,40,10,10"/>
</Style>
<Style TargetType="TextBlock" x:Key="Label">
<Setter Property="DockPanel.Dock" Value="Right"/>
<Setter Property="FontSize" Value="8"/>
<Setter Property="Foreground" Value="{StaticResource MyBrush}"/>
<Setter Property="FontFamily" Value="Arial"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Margin" Value="0,3,10,0"/>
</Style>
</Page.Resources>
<StackPanel>
<Border Style="{StaticResource PageBackground}">
<DockPanel>
<TextBlock Style="{StaticResource TitleText}">Title</TextBlock>
<TextBlock Style="{StaticResource Label}">Label</TextBlock>
<TextBlock DockPanel.Dock="Top" HorizontalAlignment="Left"
FontSize="36" Foreground="{StaticResource MyBrush}" Text="Text" Margin="20"
/>
<Button DockPanel.Dock="Top" HorizontalAlignment="Left" Height="30"
Background="{StaticResource MyBrush}" Margin="40">Button</Button>
<Ellipse DockPanel.Dock="Top" HorizontalAlignment="Left" Width="100"
Height="100" Fill="{StaticResource MyBrush}" Margin="40" />
</DockPanel>
</Border>
</StackPanel>
</Page>

Every framework-level element (FrameworkElement or FrameworkContentElement) has a


Resources property, which is a ResourceDictionary type that contains defined resources.
You can define resources on any element, such as a Button. However, resources are most
often defined on the root element, which is Page in the example.

Each resource in a resource dictionary must have a unique key. When you define
resources in markup, you assign the unique key through the x:Key Directive. Typically,
the key is a string; however, you can also set it to other object types by using the
appropriate markup extensions. Non-string keys for resources are used by certain
feature areas in WPF, notably for styles, component resources, and data styling.

You can use a defined resource with the resource markup extension syntax that specifies
the key name of the resource. For example, use the resource as the value of a property
on another element.

XAML

<Button Background="{StaticResource MyBrush}"/>


<Ellipse Fill="{StaticResource MyBrush}"/>

In the preceding example, when the XAML loader processes the value {StaticResource
MyBrush} for the Background property on Button, the resource lookup logic first checks

the resource dictionary for the Button element. If Button doesn't have a definition of the
resource key MyBrush (in that example it doesn't; its resource collection is empty), the
lookup next checks the parent element of Button, which is Page. If you define a resource
on the Page root element, all the elements in the logical tree of the Page can access it.
And you can reuse the same resource for setting the value of any property that accepts
the same type that the resource represents. In the previous example, the same MyBrush
resource sets two different properties: the Background of a Button, and the Fill of a
Rectangle.

Static and dynamic resources


A resource can be referenced as either static or dynamic. References are created by
using either the StaticResource Markup Extension or the DynamicResource Markup
Extension. A markup extension is a XAML feature that lets you specify an object
reference by having the markup extension process the attribute string and return the
object to a XAML loader. For more information about markup extension behavior, see
Markup Extensions and WPF XAML.

When you use a markup extension, you typically provide one or more parameters in
string form that are processed by that particular markup extension. The StaticResource
Markup Extension processes a key by looking up the value for that key in all available
resource dictionaries. Processing happens during load, which is when the loading
process needs to assign the property value. The DynamicResource Markup Extension
instead processes a key by creating an expression, and that expression remains
unevaluated until the app runs, at which time the expression is evaluated and provides a
value.

When you reference a resource, the following considerations can influence whether you
use a static resource reference or a dynamic resource reference:

When determining the overall design of how you create the resources for your app
(per page, in the app, in loose XAML, or in a resource-only assembly), consider the
following:

The app's functionality. Are updating resources in real-time part of your app
requirements?

The respective lookup behavior of that resource reference type.

The particular property or resource type, and the native behavior of those types.

Static resources
Static resource references work best for the following circumstances:
Your app design concentrates most of its resources into page or application-level
resource dictionaries. Static resource references aren't reevaluated based on
runtime behaviors, such as reloading a page. So there can be some performance
benefit to avoiding large numbers of dynamic resource references when they
aren't necessary based on your resource and app design.

You're setting the value of a property that isn't on a DependencyObject or a


Freezable.

You're creating a resource dictionary that will be compiled into a DLL and
packaged as part of the app or shared between apps.

You're creating a theme for a custom control and are defining resources that are
used within the themes. For this case, you typically do not want the dynamic
resource reference lookup behavior; you instead want the static resource reference
behavior so that the lookup is predictable and self-contained to the theme. With a
dynamic resource reference, even a reference within a theme is left unevaluated
until run-time. and there is a chance that when the theme is applied, some local
element will redefine a key that your theme is trying to reference, and the local
element will fall prior to the theme itself in the lookup. If that happens, your theme
will not behave as expected.

You're using resources to set large numbers of dependency properties.


Dependency properties have effective value caching as enabled by the property
system, so if you provide a value for a dependency property that can be evaluated
at load time, the dependency property doesn't have to check for a reevaluated
expression and can return the last effective value. This technique can be a
performance benefit.

You want to change the underlying resource for all consumers, or you want to
maintain separate writable instances for each consumer by using the x:Shared
Attribute.

Static resource lookup behavior


The following describes the lookup process that automatically happens when a static
resource is referenced by a property or element:

1. The lookup process checks for the requested key within the resource dictionary
defined by the element that sets the property.

2. The lookup process then traverses the logical tree upward to the parent element
and its resource dictionary. This process continues until the root element is
reached.

3. App resources are checked. App resources are those resources within the resource
dictionary that is defined by the Application object for your WPF app.

Static resource references from within a resource dictionary must reference a resource
that has already been defined lexically before the resource reference. Forward references
cannot be resolved by a static resource reference. For this reason, design your resource
dictionary structure such that resources are defined at or near the beginning of each
respective resource dictionary.

Static resource lookup can extend into themes or into system resources, but this lookup
is supported only because the XAML loader defers the request. The deferral is necessary
so that the runtime theme at the time the page loads applies properly to the app.
However, static resource references to keys that are known to only exist in themes or as
system resources aren't recommended, because such references aren't reevaluated if the
theme is changed by the user in real time. A dynamic resource reference is more reliable
when you request theme or system resources. The exception is when a theme element
itself requests another resource. These references should be static resource references,
for the reasons mentioned earlier.

The exception behavior if a static resource reference isn't found varies. If the resource
was deferred, then the exception occurs at runtime. If the resource was not deferred, the
exception occurs at load time.

Dynamic resources
Dynamic resources work best when:

The value of the resource, including system resources, or resources that are
otherwise user settable, depends on conditions that aren't known until runtime.
For example, you can create setter values that refer to system properties as
exposed by SystemColors, SystemFonts, or SystemParameters. These values are
truly dynamic because they ultimately come from the runtime environment of the
user and operating system. You might also have application-level themes that can
change, where page-level resource access must also capture the change.

You're creating or referencing theme styles for a custom control.

You intend to adjust the contents of a ResourceDictionary during an app lifetime.

You have a complicated resource structure that has interdependencies, where a


forward reference may be required. Static resource references do not support
forward references, but dynamic resource references do support them because the
resource doesn't need to be evaluated until runtime, and forward references are
therefore not a relevant concept.

You're referencing a resource that is large from the perspective of a compile or


working set, and the resource might not be used immediately when the page
loads. Static resource references always load from XAML when the page loads.
However, a dynamic resource reference doesn't load until it's used.

You're creating a style where setter values might come from other values that are
influenced by themes or other user settings.

You're applying resources to elements that might be reparented in the logical tree
during app lifetime. Changing the parent also potentially changes the resource
lookup scope, so if you want the resource for a reparented element to be
reevaluated based on the new scope, always use a dynamic resource reference.

Dynamic resource lookup behavior


Resource lookup behavior for a dynamic resource reference parallels the lookup
behavior in your code if you call FindResource or SetResourceReference:

1. The lookup checks for the requested key within the resource dictionary defined by
the element that sets the property:

If the element defines a Style property, the


System.Windows.FrameworkElement.Style of the element has its Resources
dictionary checked.

If the element defines a Template property, the


System.Windows.FrameworkTemplate.Resources dictionary of the element is
checked.

2. The lookup traverses the logical tree upward to the parent element and its
resource dictionary. This process continues until the root element is reached.

3. App resources are checked. App resources are those resources within the resource
dictionary that are defined by the Application object for your WPF app.

4. The theme resource dictionary is checked for the currently active theme. If the
theme changes at runtime, the value is reevaluated.

5. System resources are checked.

Exception behavior (if any) varies:


If a resource was requested by a FindResource call and was not found, an
exception is thrown.

If a resource was requested by a TryFindResource call and was not found, no


exception is thrown, and the returned value is null . If the property being set
doesn't accept null , then it's still possible that a deeper exception will be thrown,
depending on the individual property being set.

If a resource was requested by a dynamic resource reference in XAML and was not
found, then the behavior depends on the general property system. The general
behavior is as if no property setting operation occurred at the level where the
resource exists. For instance, if you attempt to set the background on an individual
button element using a resource that could not be evaluated, then no value set
results, but the effective value can still come from other participants in the
property system and value precedence. For instance, the background value might
still come from a locally defined button style or from the theme style. For
properties that aren't defined by theme styles, the effective value after a failed
resource evaluation might come from the default value in the property metadata.

Restrictions
Dynamic resource references have some notable restrictions. At least one of the
following conditions must be true:

The property being set must be a property on a FrameworkElement or


FrameworkContentElement. That property must be backed by a
DependencyProperty.

The reference is for a value within a StyleSetter .

The property being set must be a property on a Freezable that is provided as a


value of either a FrameworkElement or FrameworkContentElement property, or a
Setter value.

Because the property being set must be a DependencyProperty or Freezable property,


most property changes can propagate to the UI because a property change (the
changed dynamic resource value) is acknowledged by the property system. Most
controls include logic that will force another layout of a control if a DependencyProperty
changes and that property might affect layout. However, not all properties that have a
DynamicResource Markup Extension as their value are guaranteed to provide real time
updates in the UI. That functionality still might vary depending on the property, as well
as depending on the type that owns the property, or even the logical structure of your
app.

Styles, DataTemplates, and implicit keys


Although all items in a ResourceDictionary must have a key, that doesn't mean that all
resources must have an explicit x:Key . Several object types support an implicit key when
defined as a resource, where the key value is tied to the value of another property. This
type of key is known as an implicit key, whereas an x:Key attribute is an explicit key. You
can overwrite any implicit key by specifying an explicit key.

One important scenario for resources is when you define a Style. In fact, a Style is almost
always defined as an entry in a resource dictionary, because styles are inherently
intended for reuse. For more information about styles, see Styling and Templating.

Styles for controls can be both created with and referenced with an implicit key. The
theme styles that define the default appearance of a control rely on this implicit key.
From the standpoint of requesting it, the implicit key is the Type of the control itself.
From the standpoint of defining the resources, the implicit key is the TargetType of the
style. Therefore, if you're creating themes for custom controls or creating styles that
interact with existing theme styles, you do not need to specify an x:Key Directive for that
Style. And if you want to use the themed styles, you do not need to specify any style at
all. For instance, the following style definition works, even though the Style resource
doesn't appear to have a key:

XAML

<Style TargetType="Button">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush>
<GradientStop Offset="0.0" Color="AliceBlue"/>
<GradientStop Offset="1.0" Color="Salmon"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="FontSize" Value="18"/>
</Style>

That style really does have a key: the implicit key


typeof(System.Windows.Controls.Button) . In markup, you can specify a TargetType

directly as the type name (or you can optionally use {x:Type...} to return a Type.
Through the default theme style mechanisms used by WPF, that style is applied as the
runtime style of a Button on the page, even though the Button itself doesn't attempt to
specify its Style property or a specific resource reference to the style. Your style defined
in the page is found earlier in the lookup sequence than the theme dictionary style,
using the same key that the theme dictionary style has. You could just specify
<Button>Hello</Button> anywhere in the page, and the style you defined with

TargetType of Button would apply to that button. If you want, you can still explicitly key
the style with the same type value as TargetType for clarity in your markup, but that is
optional.

Implicit keys for styles do not apply on a control if OverridesDefaultStyle is true . (Also
note that OverridesDefaultStyle might be set as part of native behavior for the control
class, rather than explicitly on an instance of the control.) Also, in order to support
implicit keys for derived class scenarios, the control must override DefaultStyleKey (all
existing controls provided as part of WPF include this override). For more information
about styles, themes, and control design, see Guidelines for Designing Stylable Controls.

DataTemplate also has an implicit key. The implicit key for a DataTemplate is the
DataType property value. DataType can also be specified as the name of the type rather
than explicitly using {x:Type...}. For details, see Data Templating Overview.

See also
ResourceDictionary
Application resources
Resources and code
Define and reference a resource
Application management overview
x:Type markup extension
StaticResource markup extension
DynamicResource markup extension
Resources and Code
Article • 08/10/2023

This overview concentrates on how Windows Presentation Foundation (WPF) resources


can be accessed or created using code rather than Extensible Application Markup
Language (XAML) syntax. For more information on general resource usage and
resources from a XAML syntax perspective, see XAML Resources.

Accessing Resources from Code


The keys that identify resources if they are defined through XAML are also used to
retrieve specific resources if you request the resource in code. The simplest way to
retrieve a resource from code is to call either the FindResource or the TryFindResource
method from framework-level objects in your application. The behavioral difference
between these methods is what happens if the requested key is not found. FindResource
raises an exception; TryFindResource will not raise an exception but returns null . Each
method takes the resource key as an input parameter, and returns a loosely typed
object. Typically, a resource key is a string, but there are occasional nonstring usages;
see the Using Objects as Keys section for details. Typically you would cast the returned
object to the type required by the property that you are setting when requesting the
resource. The lookup logic for code resource resolution is the same as the dynamic
resource reference XAML case. The search for resources starts from the calling element,
then continues to successive parent elements in the logical tree. The lookup continues
onwards into application resources, themes, and system resources if necessary. A code
request for a resource will properly account for runtime changes in resource dictionaries
that might have been made subsequent to that resource dictionary being loaded from
XAML, and also for realtime system resource changes.

The following is a brief code example that finds a resource by key and uses the returned
value to set a property, implemented as a Click event handler.

C#

void SetBGByResource(object sender, RoutedEventArgs e)


{
Button b = sender as Button;
b.Background = (Brush)this.FindResource("RainbowBrush");
}

An alternative method for assigning a resource reference is SetResourceReference. This


method takes two parameters: the key of the resource, and the identifier for a particular
dependency property that is present on the element instance to which the resource
value should be assigned. Functionally, this method is the same and has the advantage
of not requiring any casting of return values.

Still another way to access resources programmatically is to access the contents of the
Resources property as a dictionary. Accessing the dictionary contained by this property
is also how you can add new resources to existing collections, check to see if a given key
name is already taken in the collection, and other dictionary/collection operations. If you
are writing a WPF application entirely in code, you can also create the entire collection
in code, assign keys to it, and then assign the finished collection to the Resources
property of an established element. This will be described in the next section.

You can index within any given Resources collection, using a specific key as the index,
but you should be aware that accessing the resource in this way does not follow the
normal runtime rules of resource resolution. You are only accessing that particular
collection. Resource lookup will not be traversing the scope to the root or the
application if no valid object was found at the requested key. However, this approach
may have performance advantages in some cases precisely because the scope of the
search for the key is more constrained. See the ResourceDictionary class for more details
on how to work with the resource dictionary directly.

Creating Resources with Code


If you want to create an entire WPF application in code, you might also want to create
any resources in that application in code. To achieve this, create a new
ResourceDictionary instance, and then add all the resources to the dictionary using
successive calls to ResourceDictionary.Add. Then, use the ResourceDictionary thus
created to set the Resources property on an element that is present in a page scope, or
the Application.Resources. You could also maintain the ResourceDictionary as a
standalone object without adding it to an element. However, if you do this, you must
access the resources within it by item key, as if it were a generic dictionary. A
ResourceDictionary that is not attached to an element Resources property would not
exist as part of the element tree and has no scope in a lookup sequence that can be
used by FindResource and related methods.

Using Objects as Keys


Most resource usages will set the key of the resource to be a string. However, various
WPF features deliberately do not use a string type to specify keys, instead this
parameter is an object. The capability of having the resource be keyed by an object is
used by the WPF style and theming support. The styles in themes which become the
default style for an otherwise non-styled control are each keyed by the Type of the
control that they should apply to. Being keyed by type provides a reliable lookup
mechanism that works on default instances of each control type, and type can be
detected by reflection and used for styling derived classes even though the derived type
otherwise has no default style. You can specify a Type key for a resource defined in
XAML by using the x:Type Markup Extension. Similar extensions exist for other nonstring
key usages that support WPF features, such as ComponentResourceKey Markup
Extension.

See also
XAML Resources
Styling and Templating
Merged Resource Dictionaries
Article • 02/06/2023

WPF application outside of the compiled XAML application. Resources can then be
shared across applications and are also more conveniently isolated for localization.

Introducing a Merged Resource Dictionary


In markup, you use the following syntax to introduce a merged resource dictionary into
a page:

XAML

<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="myresourcedictionary.xaml"/>
<ResourceDictionary Source="myresourcedictionary2.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>

Note that the ResourceDictionary element does not have an x:Key Directive, which is
generally required for all items in a resource collection. But another ResourceDictionary
reference within the MergedDictionaries collection is a special case, reserved for this
merged resource dictionary scenario. The ResourceDictionary that introduces a merged
resource dictionary cannot have an x:Key Directive. Typically, each ResourceDictionary
within the MergedDictionaries collection specifies a Source attribute. The value of
Source should be a uniform resource identifier (URI) that resolves to the location of the
resources file to be merged. The destination of that URI must be another XAML file, with
ResourceDictionary as its root element.

7 Note

It is legal to define resources within a ResourceDictionary that is specified as a


merged dictionary, either as an alternative to specifying Source, or in addition to
whatever resources are included from the specified source. However, this is not a
common scenario; the main scenario for merged dictionaries is to merge resources
from external file locations. If you want to specify resources within the markup for a
page, you should typically define these in the main ResourceDictionary and not in
the merged dictionaries.
Merged Dictionary Behavior
Resources in a merged dictionary occupy a location in the resource lookup scope that is
just after the scope of the main resource dictionary they are merged into. Although a
resource key must be unique within any individual dictionary, a key can exist multiple
times in a set of merged dictionaries. In this case, the resource that is returned will come
from the last dictionary found sequentially in the MergedDictionaries collection. If the
MergedDictionaries collection was defined in XAML, then the order of the merged
dictionaries in the collection is the order of the elements as provided in the markup. If a
key is defined in the primary dictionary and also in a dictionary that was merged, then
the resource that is returned will come from the primary dictionary. These scoping rules
apply equally for both static resource references and dynamic resource references.

Merged Dictionaries and Code


Merged dictionaries can be added to a Resources dictionary through code. The default,
initially empty ResourceDictionary that exists for any Resources property also has a
default, initially empty MergedDictionaries collection property. To add a merged
dictionary through code, you obtain a reference to the desired primary
ResourceDictionary, get its MergedDictionaries property value, and call Add on the
generic Collection that is contained in MergedDictionaries. The object you add must
be a new ResourceDictionary. In code, you do not set the Source property. Instead, you
must obtain a ResourceDictionary object by either creating one or loading one. One way
to load an existing ResourceDictionary to call XamlReader.Load on an existing XAML file
stream that has a ResourceDictionary root, then casting the XamlReader.Load return
value to ResourceDictionary.

Merged Resource Dictionary URIs


There are several techniques for how to include a merged resource dictionary, which are
indicated by the uniform resource identifier (URI) format that you will use. Broadly
speaking, these techniques can be divided into two categories: resources that are
compiled as part of the project, and resources that are not compiled as part of the
project.

For resources that are compiled as part of the project, you can use a relative path that
refers to the resource location. The relative path is evaluated during compilation. Your
resource must be defined as part of the project as a Resource build action. If you include
a resource .xaml file in the project as Resource, you do not need to copy the resource
file to the output directory, the resource is already included within the compiled
application. You can also use Content build action, but you must then copy the files to
the output directory and also deploy the resource files in the same path relationship to
the executable.

7 Note

Do not use the Embedded Resource build action. The build action itself is
supported for WPF applications, but the resolution of Source does not incorporate
ResourceManager, and thus cannot separate the individual resource out of the
stream. You could still use Embedded Resource for other purposes so long as you
also used ResourceManager to access the resources.

A related technique is to use a Pack URI to a XAML file, and refer to it as Source. Pack
URI enables references to components of referenced assemblies and other techniques.
For more information on Pack URIs, see WPF Application Resource, Content, and Data
Files.

For resources that are not compiled as part of the project, the URI is evaluated at run
time. You can use a common URI transport such as file: or http: to refer to the resource
file. The disadvantage of using the noncompiled resource approach is that file: access
requires additional deployment steps, and http: access implies the Internet security
zone.

Reusing Merged Dictionaries


You can reuse or share merged resource dictionaries between applications, because the
resource dictionary to merge can be referenced through any valid uniform resource
identifier (URI). Exactly how you do this will depend on your application deployment
strategy and which application model you follow. The aforementioned Pack URI strategy
provides a way to commonly source a merged resource across multiple projects during
development by sharing an assembly reference. In this scenario the resources are still
distributed by the client, and at least one of the applications must deploy the referenced
assembly. It is also possible to reference merged resources through a distributed URI
that uses the http protocol.

Writing merged dictionaries as local application files or to local shared storage is


another possible merged dictionary / application deployment scenario.

Localization
If resources that need to be localized are isolated to dictionaries that are merged into
primary dictionaries, and kept as loose XAML, these files can be localized separately.
This technique is a lightweight alternative to localizing the satellite resource assemblies.
For details, see WPF Globalization and Localization Overview.

See also
ResourceDictionary
XAML Resources
Resources and Code
WPF Application Resource, Content, and Data Files
Resources How-to Topics
Article • 02/06/2023

The topics in this section describe how to use Windows Presentation Foundation (WPF)
resources.

In This Section
Define and Reference a Resource
Use Application Resources
Use SystemFonts
Use System Fonts Keys
Use SystemParameters
Use System Parameters Keys

Reference
Resources

SystemColors

SystemParameters

SystemFonts

Related Sections
XAML Resources
How to: Define and Reference a
Resource
Article • 07/27/2022

This example shows how to define a resource and reference it by using an attribute in
Extensible Application Markup Language (XAML).

Example
The following example defines two types of resources: a SolidColorBrush resource, and
several Style resources. The SolidColorBrush resource MyBrush is used to provide the
value of several properties that each take a Brush type value. The Style resources
PageBackground , TitleText and Label each target a particular control type. The styles

set a variety of different properties on the targeted controls, when that style resource is
referenced by resource key and is used to set the Style property of several specific
control elements defined in XAML.

Note that one of the properties within the setters of the Label style also references the
MyBrush resource defined earlier. This is a common technique, but it is important to

remember that resources are parsed and entered into a resource dictionary in the order
that they are given. Resources are also requested by the order found within the
dictionary if you use the StaticResource Markup Extension to reference them from within
another resource. Make sure that any resource that you reference is defined earlier
within the resources collection than where that resource is then requested. If necessary,
you can work around the strict creation order of resource references by using a
DynamicResource Markup Extension to reference the resource at runtime instead, but
you should be aware that this DynamicResource technique has performance
consequences. For details, see XAML Resources.

XAML

<Page Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
<Style TargetType="Border" x:Key="PageBackground">
<Setter Property="Background" Value="Blue"/>
</Style>
<Style TargetType="TextBlock" x:Key="TitleText">
<Setter Property="Background" Value="Blue"/>
<Setter Property="DockPanel.Dock" Value="Top"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Foreground" Value="#4E87D4"/>
<Setter Property="FontFamily" Value="Trebuchet MS"/>
<Setter Property="Margin" Value="0,40,10,10"/>
</Style>
<Style TargetType="TextBlock" x:Key="Label">
<Setter Property="DockPanel.Dock" Value="Right"/>
<Setter Property="FontSize" Value="8"/>
<Setter Property="Foreground" Value="{StaticResource MyBrush}"/>
<Setter Property="FontFamily" Value="Arial"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Margin" Value="0,3,10,0"/>
</Style>
</Page.Resources>
<StackPanel>
<Border Style="{StaticResource PageBackground}">
<DockPanel>
<TextBlock Style="{StaticResource TitleText}">Title</TextBlock>
<TextBlock Style="{StaticResource Label}">Label</TextBlock>
<TextBlock DockPanel.Dock="Top" HorizontalAlignment="Left"
FontSize="36" Foreground="{StaticResource MyBrush}" Text="Text" Margin="20"
/>
<Button DockPanel.Dock="Top" HorizontalAlignment="Left" Height="30"
Background="{StaticResource MyBrush}" Margin="40">Button</Button>
<Ellipse DockPanel.Dock="Top" HorizontalAlignment="Left" Width="100"
Height="100" Fill="{StaticResource MyBrush}" Margin="40" />
</DockPanel>
</Border>
</StackPanel>
</Page>

See also
XAML Resources
Styling and Templating
How to: Use Application Resources
Article • 02/06/2023

This example shows how to use application resources.

Example
The following example shows an application definition file. The application definition file
defines a resource section (a value for the Resources property). Resources defined at the
application level can be accessed by all other pages that are part of the application. In
this case, the resource is a declared style. Because a complete style that includes a
control template can be lengthy, this example omits the control template that is defined
within the ContentTemplate property setter of the style.

XAML

<Application.Resources>
<Style TargetType="Button" x:Key="GelButton" >
<Setter Property="Margin" Value="1,2,1,2"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Template">
<Setter.Value>

XAML

</Setter.Value>
</Setter>
</Style>
</Application.Resources>

The following example shows a XAML page that references the application-level
resource that the previous example defined. The resource is referenced by using a
StaticResource Markup Extension that specifies the unique resource key for the
requested resource. No resource with key of "GelButton" is found in the current page, so
the resource lookup scope for the requested resource continues beyond the current
page and into the defined application-level resources.

XAML

<StackPanel
Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Button Height="50" Width="250" Style="{StaticResource GelButton}"
Content="Button 1" />
<Button Height="50" Width="250" Style="{StaticResource GelButton}"
Content="Button 2" />
</StackPanel>

See also
XAML Resources
Application Management Overview
How-to Topics
How to: Use SystemFonts
Article • 02/06/2023

This example shows how to use the static resources of the SystemFonts class in order to
style or customize a button.

Example
System resources expose several system-determined values as both resources and
properties in order to help you create visuals that are consistent with system settings.
SystemFonts is a class that contains both system font values as static properties, and
properties that reference resource keys that can be used to access those values
dynamically at run time. For example, CaptionFontFamily is a SystemFonts value, and
CaptionFontFamilyKey is a corresponding resource key.

In XAML, you can use the members of SystemFonts as either static properties or
dynamic resource references (with the static property value as the key). Use a dynamic
resource reference if you want the font metric to automatically update while the
application runs; otherwise, use a static value reference.

7 Note

The resource keys have the suffix "Key" appended to the property name.

The following example shows how to access and use the properties of SystemFonts as
static values in order to style or customize a button. This markup example assigns
SystemFonts values to a button.

XAML

<Button Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="3"


FontSize="{x:Static SystemFonts.IconFontSize}"
FontWeight="{x:Static SystemFonts.MessageFontWeight}"
FontFamily="{x:Static SystemFonts.CaptionFontFamily}">
SystemFonts
</Button>

To use the values of SystemFonts in code, you do not have to use either a static value or
a dynamic resource reference. Instead, use the non-key properties of the SystemFonts
class. Although the non-key properties are apparently defined as static properties, the
run-time behavior of WPF as hosted by the system will reevaluate the properties in real
time and will properly account for user-driven changes to system values. The following
example shows how to specify the font settings of a button.

C#

Button btncsharp = new Button();


btncsharp.Content = "SystemFonts";
btncsharp.Background = SystemColors.ControlDarkDarkBrush;
btncsharp.FontSize = SystemFonts.IconFontSize;
btncsharp.FontWeight = SystemFonts.MessageFontWeight;
btncsharp.FontFamily = SystemFonts.CaptionFontFamily;
cv1.Children.Add(btncsharp);

See also
SystemFonts
Paint an Area with a System Brush
Use SystemParameters
Use System Fonts Keys
How-to Topics
x:Static Markup Extension
XAML Resources
DynamicResource Markup Extension
How to: Use System Fonts Keys
Article • 02/06/2023

System resources expose a number of system metrics as resources to help developers


create visuals that are consistent with system settings. SystemFonts is a class that
contains both system font values and system font resources that bind to the values—for
example, CaptionFontFamily and CaptionFontFamilyKey.

System font metrics can be used as either static or dynamic resources. Use a dynamic
resource if you want the font metric to update automatically while the application runs;
otherwise use a static resource.

7 Note

Dynamic resources have the keyword Key appended to the property name.

The following example shows how to access and use system font dynamic resources to
style or customize a button. This XAML example creates a button style that assigns
SystemFonts values to a button.

Example
XAML

<Style x:Key="SimpleFont" TargetType="{x:Type Button}">


<Setter Property = "FontSize" Value= "{DynamicResource {x:Static
SystemFonts.IconFontSizeKey}}"/>
<Setter Property = "FontWeight" Value= "{DynamicResource {x:Static
SystemFonts.MessageFontWeightKey}}"/>
<Setter Property = "FontFamily" Value= "{DynamicResource {x:Static
SystemFonts.CaptionFontFamilyKey}}"/>
</Style>

See also
Paint an Area with a System Brush
Use SystemParameters
Use SystemFonts
How to: Use SystemParameters
Article • 02/06/2023

This example shows how to access and use the properties of SystemParameters in order
to style or customize a button.

Example
System resources expose several system based settings as resources in order to help you
create visuals that are consistent with system settings. SystemParameters is a class that
contains both system parameter value properties, and resource keys that bind to the
values. For example, FullPrimaryScreenHeight is a SystemParameters property value and
FullPrimaryScreenHeightKey is the corresponding resource key.

In XAML, you can use the members of SystemParameters as either a static property
usage, or a dynamic resource references (with the static property value as the key). Use a
dynamic resource reference if you want the system based value to update automatically
while the application runs; otherwise, use a static reference. Resource keys have the
suffix Key appended to the property name.

The following example shows how to access and use the static values of
SystemParameters to style or customize a button. This markup example sizes a button
by applying SystemParameters values to a button.

XAML

<Button FontSize="8" Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="5"


HorizontalAlignment="Left"
Height="{x:Static SystemParameters.CaptionHeight}"
Width="{x:Static SystemParameters.IconGridWidth}">
SystemParameters
</Button>

To use the values of SystemParameters in code, you do not have to use either static
references or dynamic resource references. Instead, use the values of the
SystemParameters class. Although the non-key properties are apparently defined as
static properties, the runtime behavior of WPF as hosted by the system will reevaluate
the properties in realtime, and will properly account for user-driven changes to system
values. The following example shows how to set the width and height of a button by
using SystemParameters values.

C#
Button btncsharp = new Button();
btncsharp.Content = "SystemParameters";
btncsharp.FontSize = 8;
btncsharp.Background = SystemColors.ControlDarkDarkBrush;
btncsharp.Height = SystemParameters.CaptionHeight;
btncsharp.Width = SystemParameters.IconGridWidth;
cv2.Children.Add(btncsharp);

See also
SystemParameters
Paint an Area with a System Brush
Use SystemFonts
Use System Parameters Keys
How-to Topics
How to: Use System Parameters Keys
Article • 02/06/2023

System resources expose a number of system metrics as resources to help developers


create visuals that are consistent with system settings. SystemParameters is a class that
contains both system parameter values and resource keys that bind to the values—for
example, FullPrimaryScreenHeight and FullPrimaryScreenHeightKey. System parameter
metrics can be used as either static or dynamic resources. Use a dynamic resource if you
want the parameter metric to update automatically while the application runs; otherwise
use a static resource.

7 Note

Dynamic resources have the keyword Key appended to the property name.

The following example shows how to access and use system parameter dynamic
resources to style or customize a button. This XAML example sizes a button by assigning
SystemParameters values to the button's width and height.

Example
XAML

<Style x:Key="SimpleParam" TargetType="{x:Type Button}">


<Setter Property = "Height" Value= "{DynamicResource {x:Static
SystemParameters.CaptionHeightKey}}"/>
<Setter Property = "Width" Value= "{DynamicResource {x:Static
SystemParameters.IconGridWidthKey}}"/>
</Style>

See also
Paint an Area with a System Brush
Use SystemFonts
Use SystemParameters
Documents
Article • 07/26/2022

Windows Presentation Foundation (WPF) provides a versatile set of components that


enable developers to build applications with advanced document features and an
improved reading experience. In addition to enhanced capabilities and quality, Windows
Presentation Foundation (WPF) also provides simplified management services for
document packaging, security, and storage.

In This Section
Documents in WPF
Document Serialization and Storage
Annotations
Flow Content
Typography
Printing and Print System Management

See also
DocumentViewer
FlowDocument
System.Windows.Xps
isXPS.exe (isXPS Conformance Tool)
Documents in WPF
Article • 02/06/2023

WPF also provides integrated services for document display, packaging, and security.
This topic provides an introduction to WPF document types and document packaging.

Types of Documents
WPF divides documents into two broad categories based on their intended use; these
document categories are termed "fixed documents" and "flow documents."

Fixed documents are intended for applications that require a precise "what you see is
what you get" (WYSIWYG) presentation, independent of the display or printer hardware
used. Typical uses for fixed documents include desktop publishing, word processing, and
form layout, where adherence to the original page design is critical. As part of its layout,
a fixed document maintains the precise positional placement of content elements
independent of the display or print device in use. For example, a fixed document page
viewed on 96 dpi display will appear exactly the same when it is output to a 600 dpi
laser printer as when it is output to a 4800 dpi phototypesetter. The page layout remains
the same in all cases, while the document quality maximizes to the capabilities of each
device.

By comparison, flow documents are designed to optimize viewing and readability and
are best utilized when ease of reading is the primary document consumption scenario.
Rather than being set to one predefined layout, flow documents dynamically adjust and
reflow their content based on run-time variables such as window size, device resolution,
and optional user preferences. A Web page is a simple example of a flow document
where the page content is dynamically formatted to fit the current window. Flow
documents optimize the viewing and reading experience for the user, based on the
runtime environment. For example, the same flow document will dynamically reformat
for optimal readability on either high-resolution 19-inch display or a small 2x3-inch PDA
screen. In addition, flow documents have a number of built in features including search,
viewing modes that optimize readability, and the ability to change the size and
appearance of fonts. See Flow Document Overview for illustrations, examples, and in-
depth information on flow documents.

Document Controls and Text Layout


The .NET Framework provides a set of pre-built controls that simplify using fixed
documents, flow documents, and general text within your application. The display of
fixed document content is supported using the DocumentViewer control. Display of flow
document content is supported by three different controls: FlowDocumentReader,
FlowDocumentPageViewer, and FlowDocumentScrollViewer which map to different user
scenarios (see sections below). Other WPF controls provide simplified layout to support
general text uses (see Text in the User Interface, below).

Fixed Document Control - DocumentViewer


The DocumentViewer control is designed to display FixedDocument content. The
DocumentViewer control provides an intuitive user interface that provides built-in
support for common operations including print output, copy to clipboard, zoom, and
text search features. The control provides access to pages of content through a familiar
scrolling mechanism. Like all WPF controls, DocumentViewer supports complete or
partial restyling, which enables the control to be visually integrated into virtually any
application or environment.

DocumentViewer is designed to display content in a read-only manner; editing or


modification of content is not available and is not supported.

Flow Document Controls

7 Note

For more detailed information on flow document features and how to create them,
see Flow Document Overview.

Display of flow document content is supported by three controls: FlowDocumentReader,


FlowDocumentPageViewer, and FlowDocumentScrollViewer.

FlowDocumentReader
FlowDocumentReader includes features that enable the user to dynamically choose
between various viewing modes, including a single-page (page-at-a-time) viewing
mode, a two-page-at-a-time (book reading format) viewing mode, and a continuous
scrolling (bottomless) viewing mode. For more information about these viewing modes,
see FlowDocumentReaderViewingMode. If you do not need the ability to dynamically
switch between different viewing modes, FlowDocumentPageViewer and
FlowDocumentScrollViewer provide lighter-weight flow content viewers that are fixed in
a particular viewing mode.
FlowDocumentPageViewer and FlowDocumentScrollViewer
FlowDocumentPageViewer shows content in page-at-a-time viewing mode, while
FlowDocumentScrollViewer shows content in continuous scrolling mode. Both
FlowDocumentPageViewer and FlowDocumentScrollViewer are fixed to a particular
viewing mode. Compare to FlowDocumentReader, which includes features that enable
the user to dynamically choose between various viewing modes (as provided by the
FlowDocumentReaderViewingMode enumeration), at the cost of being more resource
intensive than FlowDocumentPageViewer or FlowDocumentScrollViewer.

By default, a vertical scrollbar is always shown, and a horizontal scrollbar becomes


visible if needed. The default UI for FlowDocumentScrollViewer does not include a
toolbar; however, the IsToolBarVisible property can be used to enable a built-in toolbar.

Text in the User Interface


Besides adding text to documents, text can obviously be used in application UI such as
forms. WPF includes multiple controls for drawing text to the screen. Each control is
targeted to a different scenario and has its own list of features and limitations. In
general, the TextBlock element should be used when limited text support is required,
such as a brief sentence in a user interface (UI). Label can be used when minimal text
support is required. For more information, see TextBlock Overview.

Document Packaging
The System.IO.Packaging APIs provide an efficient means to organize application data,
document content, and related resources in a single container that is simple to access,
portable, and easy to distribute. A ZIP file is an example of a Package type capable of
holding multiple objects as a single unit. The packaging APIs provide a default
ZipPackage implementation designed using an Open Packaging Conventions standard
with XML and ZIP file architecture. The WPF packaging APIs make it simple to create
packages, and to store and access objects within them. An object stored in a Package is
referred to as a PackagePart ("part"). Packages can also include signed digital certificates
that can be used to identify the originator of a part and to validate that the contents of
a package have not been modified. Packages also include a PackageRelationship feature
that allows additional information to be added to a package or associated with specific
parts without actually modifying the content of existing parts. Package services also
support Microsoft Windows Rights Management (RM).

The WPF Package architecture serves as the foundation for a number of key
technologies:
XPS documents conforming to the XML Paper Specification (XPS).

Microsoft Office "12" open XML format documents (.docx).

Custom storage formats for your own application design.

Based on the packaging APIs, an XpsDocument is specifically designed for storing WPF
fixed content documents. An XpsDocument is a self-contained document that can be
opened in a viewer, displayed in a DocumentViewer control, routed to a print spool, or
output directly to an XPS-compatible printer.

The following sections provide additional information on the Package and XpsDocument
APIs provided with WPF.

Package Components
The WPF packaging APIs allow application data and documents to be organized into a
single portable unit. A ZIP file is one of the most common types of packages and is the
default package type provided with WPF. Package itself is an abstract class from which
ZipPackage is implemented using an open standard XML and ZIP file architecture. The
Open method uses ZipPackage to create and use ZIP files by default. A package can
contain three basic types of items:

Item Description

PackagePart Application content, data, documents, and resource files.

PackageDigitalSignature [X.509 Certificate] for identification, authentication and validation.

PackageRelationship Added information related to the package or a specific part.

PackageParts
A PackagePart ("part") is an abstract class that refers to an object stored in a Package. In
a ZIP file, the package parts correspond to the individual files stored within the ZIP file.
ZipPackagePart provides the default implementation for serializable objects stored in a
ZipPackage. Like a file system, parts contained in the package are stored in hierarchical
directory or "folder-style" organization. Using the WPF packaging APIs, applications can
write, store, and read multiple PackagePart objects using a single ZIP file container.

PackageDigitalSignatures
For security, a PackageDigitalSignature ("digital signature") can be associated with parts
within a package. A PackageDigitalSignature incorporates a [509] that provides two
features:

1. Identifies and authenticates the originator of the part.

2. Validates that the part has not been modified.

The digital signature does not preclude a part from being modified, but a validation
check against the digital signature will fail if the part is altered in any way. The
application can then take appropriate action—for example, block opening the part or
notify the user that the part has been modified and is not secure.

PackageRelationships

A PackageRelationship ("relationship") provides a mechanism for associating additional


information with the package or a part within the package. A relationship is a package-
level facility that can associate additional information with a part without modifying the
actual part content. Inserting new data directly into the part content of is usually not
practical in many cases:

The actual type of the part and its content schema is not known.

Even if known, the content schema might not provide a means for adding new
information.

The part might be digitally signed or encrypted, precluding any modification.

Package relationships provide a discoverable means for adding and associating


additional information with individual parts or with the entire package. Package
relationships are used for two primary functions:

1. Defining dependency relationships from one part to another part.

2. Defining information relationships that add notes or other data related to the part.

A PackageRelationship provides a quick, discoverable means to define dependencies


and add other information associated with a part of the package or the package as a
whole.

Dependency Relationships

Dependency relationships are used to describe dependencies that one part makes to
other parts. For example, a package might contain an HTML part that includes one or
more <img> image tags. The image tags refer to images that are located either as other
parts internal to the package or external to the package (such as accessible over the
Internet). Creating a PackageRelationship associated with HTML file makes discovering
and accessing the dependent resources quick and easy. A browser or viewer application
can directly access the part relationships and immediately begin assembling the
dependent resources without knowing the schema or parsing the document.

Information Relationships

Similar to a note or annotation, a PackageRelationship can also be used to store other


types of information to be associated with a part without having to actually modify the
part content itself.

XPS Documents
XML Paper Specification (XPS) document is a package that contains one or more fixed-
documents along with all the resources and information required for rendering. XPS is
also the native Windows Vista print spool file format. An XpsDocument is stored in
standard ZIP dataset, and can include a combination of XML and binary components,
such as image and font files. PackageRelationships are used to define the dependencies
between the content and the resources required to fully render the document. The
XpsDocument design provides a single, high-fidelity document solution that supports
multiple uses:

Reading, writing, and storing fixed-document content and resources as a single,


portable, and easy-to-distribute file.

Displaying documents with the XPS Viewer application.

Outputting documents in the native print spool output format of Windows Vista.

Routing documents directly to an XPS-compatible printer.

See also
FixedDocument
FlowDocument
XpsDocument
ZipPackage
ZipPackagePart
PackageRelationship
DocumentViewer
Text
Flow Document Overview
Printing Overview
Document Serialization and Storage
Document Serialization and Storage
Article • 07/26/2022

Microsoft .NET Framework provides a powerful environment for creating and displaying
high quality documents. Enhanced features that support both fixed-documents and
flow-documents, advanced viewing controls, combined with powerful 2D and 3D
graphic capabilities take .NET Framework applications to a new level of quality and user
experience. Being able to flexibly manage an in-memory representation of a document
is a key feature of .NET Framework, and being able to efficiently save and load
documents from a data store is a need of almost every application. The process of
converting a document from an internal in-memory representation to an external data
store is termed serialization. The reverse process of reading a data store and recreating
the original in-memory instance is termed deserialization.

About Document Serialization


Ideally the process of serializing and deserializing a document from and then back into
memory is transparent to the application. The application calls a serializer "write"
method to save the document, while a deserializer "read" method accesses the data
store and recreates the original instance in memory. The specific format that the data is
stored in is generally not a concern of the application as long as the serialize and
deserialize process recreates the document back to its original form.

Applications often provide multiple serialization options which allow the user to save
documents to different medium or to a different format. For example, an application
might offer "Save As" options to store a document to a disk file, database, or web
service. Similarly, different serializers could store the document in different formats such
as in HTML, RTF, XML, XPS, or alternately to a third-party format. To the application,
serialization defines an interface that isolates the details of the storage medium within
the implementation of each specific serializer. In addition to the benefits of
encapsulating storage details, the .NET Framework
System.Windows.Documents.Serialization APIs provide several other important features.

Features of .NET Framework 3.0 Document Serializers


Direct access to the high-level document objects (logical tree and visuals) enable
efficient storage of paginated content, 2D/3D elements, images, media, hyperlinks,
annotations, and other support content.

Synchronous and asynchronous operation.


Support for plug-in serializers with enhanced capabilities:

System-wide access for use by all .NET Framework applications.

Simple application plug-in discoverability.

Simple deployment, installation, and update for custom third-party plug-ins.

User interface support for custom run-time settings and options.

XPS Print Path


The Microsoft .NET Framework XPS print path also provides an extensible mechanism
for writing documents through print output. XPS serves as both a document file format
and is the native print spool format for Windows Vista. XPS documents can be sent
directly to XPS-compatible printers without the need for conversion to an intermediate
format. See the Printing Overview for additional information on print path output
options and capabilities.

Plug-in Serializers
The System.Windows.Documents.Serialization APIs provide support for both plug-in
serializers and linked serializers that are installed separately from the application, bind at
run time, and are accessed by using the SerializerProvider discovery mechanism. Plug-in
serializers offer enhanced benefits for ease of deployment and system-wide use. Linked
serializers can also be implemented for partial trust environments such as XAML browser
applications (XBAPs) where plug-in serializers are not accessible. Linked serializers,
which are based on a derived implementation of the SerializerWriter class, are compiled
and linked directly into the application. Both plug-in serializers and linked serializers
operate through identical public methods and events which make it easy to use either or
both types of serializers in the same application.

Plug-in serializers aid application developers by providing extensibility to new storage


designs and file formats without having to code directly for every potential format at
build time. Plug-in serializers also benefit third-party developers by providing a
standardized means to deploy, install, and update system accessible plug-ins for custom
or proprietary file formats.

Using a Plug-in Serializer


Plug-in serializers are simple to use. The SerializerProvider class enumerates a
SerializerDescriptor object for each plug-in installed on the system. The IsLoadable
property filters the installed plug-ins based on the current configuration and verifies
that the serializer can be loaded and used by the application. The SerializerDescriptor
also provides other properties, such as DisplayName and DefaultFileExtension, which the
application can use to prompt the user in selecting a serializer for an available output
format. A default plug-in serializer for XPS is provided with .NET Framework and is
always enumerated. After the user selects an output format, the CreateSerializerWriter
method is used to create a SerializerWriter for the specific format. The
SerializerWriter.Write method can then be called to output the document stream to the
data store.

The following example illustrates an application that uses the SerializerProvider method
in a "PlugInFileFilter" property. PlugInFileFilter enumerates the installed plug-ins and
builds a filter string with the available file options for a SaveFileDialog.

C#

// ------------------------ PlugInFileFilter --------------------------


/// <summary>
/// Gets a filter string for installed plug-in serializers.</summary>
/// <remark>
/// PlugInFileFilter is used to set the SaveFileDialog or
/// OpenFileDialog "Filter" property when saving or opening files
/// using plug-in serializers.</remark>
private string PlugInFileFilter
{
get
{ // Create a SerializerProvider for accessing plug-in serializers.
SerializerProvider serializerProvider = new SerializerProvider();
string filter = "";

// For each loadable serializer, add its display


// name and extension to the filter string.
foreach (SerializerDescriptor serializerDescriptor in
serializerProvider.InstalledSerializers)
{
if (serializerDescriptor.IsLoadable)
{
// After the first, separate entries with a "|".
if (filter.Length > 0) filter += "|";

// Add an entry with the plug-in name and extension.


filter += serializerDescriptor.DisplayName + " (*" +
serializerDescriptor.DefaultFileExtension + ")|*" +
serializerDescriptor.DefaultFileExtension;
}
}

// Return the filter string of installed plug-in serializers.


return filter;
}
}

After an output file name has been selected by the user, the following example
illustrates use of the CreateSerializerWriter method to store a given document in a
specified format.

C#

// Create a SerializerProvider for accessing plug-in serializers.


SerializerProvider serializerProvider = new SerializerProvider();

// Locate the serializer that matches the fileName extension.


SerializerDescriptor selectedPlugIn = null;
foreach ( SerializerDescriptor serializerDescriptor in
serializerProvider.InstalledSerializers )
{
if ( serializerDescriptor.IsLoadable &&
fileName.EndsWith(serializerDescriptor.DefaultFileExtension) )
{ // The plug-in serializer and fileName extensions match.
selectedPlugIn = serializerDescriptor;
break; // foreach
}
}

// If a match for a plug-in serializer was found,


// use it to output and store the document.
if (selectedPlugIn != null)
{
Stream package = File.Create(fileName);
SerializerWriter serializerWriter =
serializerProvider.CreateSerializerWriter(selectedPlugIn,
package);
IDocumentPaginatorSource idoc =
flowDocument as IDocumentPaginatorSource;
serializerWriter.Write(idoc.DocumentPaginator, null);
package.Close();
return true;
}

Installing Plug-in Serializers


The SerializerProvider class supplies the upper-level application interface for plug-in
serializer discovery and access. SerializerProvider locates and provides the application a
list of the serializers that are installed and accessible on the system. The specifics of the
installed serializers are defined through registry settings. Plug-in serializers can be
added to the registry by using the RegisterSerializer method; or if .NET Framework is not
yet installed, the plug-in installation script can directly set the registry values itself. The
UnregisterSerializer method can be used to remove a previously installed plug-in, or the
registry settings can be reset similarly by an uninstall script.

Creating a Plug-in Serializer


Both plug-in serializers and linked serializers use the same exposed public methods and
events, and similarly can be designed to operate either synchronously or
asynchronously. There are three basic steps normally followed to create a plug-in
serializer:

1. Implement and debug the serializer first as a linked serializer. Initially creating the
serializer compiled and linked directly in a test application provides full access to
breakpoints and other debug services helpful for testing.

2. After the serializer is fully tested, an ISerializerFactory interface is added to create a


plug-in. The ISerializerFactory interface permits full access to all .NET Framework
objects which includes the logical tree, UIElement objects,
IDocumentPaginatorSource, and Visual elements. Additionally ISerializerFactory
provides the same synchronous and asynchronous methods and events used by
linked serializers. Since large documents can take time to output, asynchronous
operations are recommended to maintain responsive user interaction and offer a
"Cancel" option if some problem occurs with the data store.

3. After the plug-in serializer is created, an installation script is implemented for


distributing and installing (and uninstalling) the plug-in (see above, "Installing
Plug-in Serializers").

See also
System.Windows.Documents.Serialization
XpsDocumentWriter
XpsDocument
Documents in WPF
Printing Overview
XML Paper Specification
Annotations
Article • 02/06/2023

Windows Presentation Foundation (WPF) provides document viewing controls that


support annotating document content.

In This Section
Annotations Overview
Annotations Schema

Reference
Annotation
AnnotationService
DocumentViewer

Related Sections
Documents in WPF
Flow Document Overview
Annotations Overview
Article • 07/19/2022

Writing notes or comments on paper documents is such a commonplace activity that we


almost take it for granted. These notes or comments are "annotations" that we add to a
document to flag information or to highlight items of interest for later reference.
Although writing notes on printed documents is easy and commonplace, the ability to
add personal comments to electronic documents is typically very limited, if available at
all.

This topic reviews several common types of annotations, specifically sticky notes and
highlights, and illustrates how the Microsoft Annotations Framework facilitates these
types of annotations in applications through the Windows Presentation Foundation
(WPF) document viewing controls. WPF document viewing controls that support
annotations include FlowDocumentReader and FlowDocumentScrollViewer, as well as
controls derived from DocumentViewerBase such as DocumentViewer and
FlowDocumentPageViewer.

Sticky Notes
A typical sticky note contains information written on a small piece of colored paper that
is then "stuck" to a document. Digital sticky notes provide similar functionality for
electronic documents, but with the added flexibility to include many other types of
content such as typed text, handwritten notes (for example, Tablet PC "ink" strokes), or
Web links.

The following illustration shows some examples of highlight, text sticky note, and ink
sticky note annotations.
The following example shows the method that you can use to enable annotation
support in your application.

C#

// ------------------------ StartAnnotations --------------------------


/// <summary>
/// Enables annotations and displays all that are viewable.</summary>
private void StartAnnotations()
{
// If there is no AnnotationService yet, create one.
if (_annotService == null)
// docViewer is a document viewing control named in Window1.xaml.
_annotService = new AnnotationService(docViewer);

// If the AnnotationService is currently enabled, disable it.


if (_annotService.IsEnabled == true)
_annotService.Disable();

// Open a stream to the file for storing annotations.


_annotStream = new FileStream(
_annotStorePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);

// Create an AnnotationStore using the file stream.


_annotStore = new XmlStreamStore(_annotStream);

// Enable the AnnotationService using the new store.


_annotService.Enable(_annotStore);
}// end:StartAnnotations()

Highlights
People use creative methods to draw attention to items of interest when they mark up a
paper document, such as underlining, highlighting, circling words in a sentence, or
drawing marks or notations in the margin. Highlight annotations in Microsoft
Annotations Framework provide a similar feature for marking up information displayed
in WPF document viewing controls.

The following illustration shows an example of a highlight annotation.

Users typically create annotations by first selecting some text or an item of interest, and
then right-clicking to display a ContextMenu of annotation options. The following
example shows the Extensible Application Markup Language (XAML) you can use to
declare a ContextMenu with routed commands that users can access to create and
manage annotations.

XAML

<DocumentViewer.ContextMenu>
<ContextMenu>
<MenuItem Command="ApplicationCommands.Copy" />
<Separator />
<!-- Add a Highlight annotation to a user selection. -->
<MenuItem Command="ann:AnnotationService.CreateHighlightCommand"
Header="Add Highlight" />
<!-- Add a Text Note annotation to a user selection. -->
<MenuItem Command="ann:AnnotationService.CreateTextStickyNoteCommand"
Header="Add Text Note" />
<!-- Add an Ink Note annotation to a user selection. -->
<MenuItem Command="ann:AnnotationService.CreateInkStickyNoteCommand"
Header="Add Ink Note" />
<Separator />
<!-- Remove Highlights from a user selection. -->
<MenuItem Command="ann:AnnotationService.ClearHighlightsCommand"
Header="Remove Highlights" />
<!-- Remove Text Notes and Ink Notes from a user selection. -->
<MenuItem Command="ann:AnnotationService.DeleteStickyNotesCommand"
Header="Remove Notes" />
<!-- Remove Highlights, Text Notes, Ink Notes from a selection. -->
<MenuItem Command="ann:AnnotationService.DeleteAnnotationsCommand"
Header="Remove Highlights &amp; Notes" />
</ContextMenu>
</DocumentViewer.ContextMenu>

Data Anchoring
The Annotations Framework binds annotations to the data that the user selects, not just
to a position on the display view. Therefore, if the document view changes, such as
when the user scrolls or resizes the display window, the annotation stays with the data
selection to which it is bound. For example, the following graphic illustrates an
annotation that the user has made on a text selection. When the document view
changes (scrolls, resizes, scales, or otherwise moves), the highlight annotation moves
with the original data selection.

Matching Annotations with Annotated Objects


You can match annotations with the corresponding annotated objects. For example,
consider a simple document reader application that has a comments pane. The
comments pane might be a list box that displays the text from a list of annotations that
are anchored to a document. If the user selects an item in the list box, then the
application brings into view the paragraph in the document that the corresponding
annotation object is anchored to.

The following example demonstrates how to implement the event handler of such a list
box that serves as the comments pane.

C#

void annotationsListBox_SelectionChanged(object sender,


SelectionChangedEventArgs e)
{

Annotation comment = (sender as ListBox).SelectedItem as Annotation;


if (comment != null)
{
// IAnchorInfo info;
// service is an AnnotationService object
// comment is an Annotation object
info = AnnotationHelper.GetAnchorInfo(this.service, comment);
TextAnchor resolvedAnchor = info.ResolvedAnchor as TextAnchor;
TextPointer textPointer = (TextPointer)resolvedAnchor.BoundingStart;
textPointer.Paragraph.BringIntoView();
}
}
Another example scenario involves applications that enable the exchange of annotations
and sticky notes between document readers through email. This feature enables these
applications to navigate the reader to the page that contains the annotation that is
being exchanged.

See also
DocumentViewerBase
DocumentViewer
FlowDocumentPageViewer
FlowDocumentScrollViewer
FlowDocumentReader
IAnchorInfo
Annotations Schema
ContextMenu Overview
Commanding Overview
Flow Document Overview
How to: Add a Command to a MenuItem
Annotations Schema
Article • 07/19/2022

This topic describes the XML schema definition (XSD) used by the Microsoft Annotations
Framework to save and retrieve user annotation data.

The Annotations Framework serializes annotation data from an internal representation


to an XML format. The XML format used for this conversion is described by the
Annotations Framework XSD Schema. The schema defines the implementation-
independent XML format that can be used to exchange annotation data between
applications.

The Annotations Framework XML schema definition consists of two subschemas

The Annotations XML Core Schema (Core Schema).

The Annotations XML Base Schema (Base Schema).

The Core Schema defines the primary XML structure of an Annotation. The majority of
XML elements defined in the Core Schema correspond to types in the
System.Windows.Annotations namespace. The Core Schema exposes three extension
points where applications can add their own XML data. These extension points include
the Authors, ContentLocatorPart, and "Content". (Content elements are provided in the
form of an XmlElement list.)

The Base Schema described in this topic defines the extensions for the Authors,
ContentLocatorPart, and Content types included with the initial Windows Presentation
Foundation (WPF) release.

Annotations XML Core Schema


The Annotations XML Core Schema defines the XML structure that is used to store
Annotation objects.

XML

<xsd:schema elementFormDefault="qualified"
attributeFormDefault="unqualified"
blockDefault="#all"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"

targetNamespace="http://schemas.microsoft.com/windows/annotations/2003/11/co
re"
xmlns:anc="http://schemas.microsoft.com/windows/annotations/2003/11/core">

<!-- The Annotations element groups a number of annotations. -->


<xsd:element name="Annotations" type="anc:AnnotationsType" />

<xsd:complexType name="AnnotationsType">
<xsd:sequence>
<xsd:element name="Annotation" minOccurs="0" maxOccurs="unbounded"
type="anc:AnnotationType" />
</xsd:sequence>
</xsd:complexType>

<!-- AnnotationType defines the structure of the Annotation element. -->


<xsd:complexType name="AnnotationType">
<xsd:sequence>

<!-- List of 0 or more authors. -->


<xsd:element name="Authors" minOccurs="0" maxOccurs="1"
type="anc:AuthorListType" />

<!-- List of 0 or more anchors. -->


<xsd:element name="Anchors" minOccurs="0" maxOccurs="1"
type="anc:ResourceListType" />

<!-- List of 0 or more cargos. -->


<xsd:element name="Cargos" minOccurs="0" maxOccurs="1"
type="anc:ResourceListType" />

</xsd:sequence>

<!-- Unique annotation ID. -->


<xsd:attribute name="Id" type="xsd:string" use="required" />

<!-- Annotation "Type" is used to map the annotation to an annotation


component that takes care of the visual representation of the
annotation. WPF V1 recognizes three annotation types:
http://schemas.microsoft.com/windows/annotations/2003/11/base:Highlight

http://schemas.microsoft.com/windows/annotations/2003/11/base:TextStickyNote

http://schemas.microsoft.com/windows/annotations/2003/11/base:InkStickyNote
-->
<xsd:attribute name="Type" type="xsd:QName" use="required" />

<!-- Time when the annotation was last modified. -->


<xsd:attribute name="LastModificationTime" use="optional"
type="xsd:dateTime" />

<!-- Time when the annotation was created. -->


<xsd:attribute name="CreationTime" use="optional"
type="xsd:dateTime" />
</xsd:complexType>

<!-- "Authors" consists of 0 or more elements that represent an author. --


>
<xsd:complexType name="AuthorListType">
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="anc:Author" />
</xsd:sequence>
</xsd:complexType>

<!-- The core schema allows any author type. Supported author types
in version 1 (V1) are described in the base schema. -->
<xsd:element name="Author" abstract="true" block="extension restriction"/>

<!-- Both annotation anchor and annotation cargo are represented by the
ResourceListType which contains 0 or more "Resource" elements. -->
<xsd:complexType name="ResourceListType">
<xsd:sequence>
<xsd:element name="Resource" minOccurs="0" maxOccurs="unbounded"
type="anc:ResourceType" />
</xsd:sequence>
</xsd:complexType>

<!-- Resource groups identification, location


and/or content of some information. -->
<xsd:complexType name="ResourceType">
<xsd:choice minOccurs="0" maxOccurs="unbounded" >
<xsd:choice>
<xsd:element name="ContentLocator" type="anc:ContentLocatorType" />
<xsd:element name="ContentLocatorGroup"
type="anc:ContentLocatorGroupType" />
</xsd:choice>
<xsd:element ref="anc:Content"/>
</xsd:choice>

<!-- Unique resource identifier. -->


<xsd:attribute name="Id" type="xsd:string" use="required" />

<!-- Optional resource name. -->


<xsd:attribute name="Name" type="xsd:string" use="optional" />
</xsd:complexType>

<!-- ContentLocatorGroup contains a set of ContentLocators -->


<xsd:complexType name="ContentLocatorGroupType">
<xsd:sequence>
<xsd:element name="ContentLocator" minOccurs="1" maxOccurs="unbounded"
type="anc:ContentLocatorType" />
</xsd:sequence>
</xsd:complexType>

<!-- A ContentLocator describes the location or the identification


of particular data within some context. The ContentLocator consists
of one or more ContentLocatorParts. Each ContentLocatorPart needs to
be successively applied to the context to arrive at the data. What
"applying", "context", and "data" mean is application dependent.
-->
<xsd:complexType name="ContentLocatorType">
<xsd:sequence minOccurs="1" maxOccurs="unbounded">
<xsd:element ref="anc:ContentLocatorPart" />
</xsd:sequence>
</xsd:complexType>

<!-- A ContentLocatorPart is a set of "Item" elements. Each "Item"


element
has "Name" and "Value" attributes that define a name/value pair.
ContentLocatorPart is an abstract type that must be restricted for
each
concrete ContentLocatorPart definition. This restriction should
define
allowed names and values for the concrete ContentLocatorPart type.
That
way the application can define its own way of locating information.
The
ContentLocatorPartTypes that are allowed in version 1 (V1) of WPF are
defined in the Annotations Base Schema.
-->
<xsd:element name="ContentLocatorPart" type="anc:ContentLocatorPartType"
abstract="true" />

<xsd:complexType name="ContentLocatorPartType" abstract="true"


block="restriction">
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element name="Item" type="anc:ItemType" />
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="ItemType" abstract="true" >


<xsd:attribute name="Name" type='xsd:string' use="required" />
<xsd:attribute name="Value" type='xsd:string' use="optional" />
</xsd:complexType>

<!-- Content describes the underlying content of a resource. This is an


abstract type that should be redefined for each concrete content type
through restriction. Allowed content types in WPF version 1 are
defined in the Annotations Base Schema.
-->
<xsd:element name="Content" abstract="true" block="extension
restriction"/>

</xsd:schema>

Annotations XML Base Schema


The Base Schema defines the XML structure for the three abstract elements defined in
the Core Schema – Authors, ContentLocatorPart, and Contents.

XML

<xsd:schema elementFormDefault="qualified"
attributeFormDefault="unqualified"
blockDefault="#all"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"

targetNamespace="http://schemas.microsoft.com/windows/annotations/2003/11/ba
se"

xmlns:anb="http://schemas.microsoft.com/windows/annotations/2003/11/base"

xmlns:anc="http://schemas.microsoft.com/windows/annotations/2003/11/core">

<xsd:import schemaLocation="AnnotationCoreV1.xsd"

namespace="http://schemas.microsoft.com/windows/annotations/2003/11/core"/>

<!-- ***** Author ***** -->


<!-- Simple DisplayName Author -->
<xsd:complexType name="StringAuthorType">
<xsd:simpleContent >
<xsd:extension base='xsd:string' />
</xsd:simpleContent>
</xsd:complexType>
<xsd:element name="StringAuthor" type="anb:StringAuthorType"
substitutionGroup="anc:Author"/>

<!-- ***** LocatorParts ***** -->

<!-- Helper types -->

<!-- CountItemNameType - helper type to define count item -->


<xsd:simpleType name="CountItemNameType">
<xsd:restriction base='xsd:string'>
<xsd:pattern value="Count" />
</xsd:restriction>
</xsd:simpleType>

<!-- NumberType - helper type to define segment count item -->


<xsd:simpleType name="NumberType">
<xsd:restriction base='xsd:string'>
<xsd:pattern value="\d*" />
</xsd:restriction>
</xsd:simpleType>

<!-- SegmentNameType: helper type to define possible segment name types --


>
<xsd:simpleType name="SegmentItemNameType">
<xsd:restriction base='xsd:string'>
<xsd:pattern value="Segment\d*" />
</xsd:restriction>
</xsd:simpleType>

<!-- Flow Locator Part -->

<!-- FlowSegmentValueItemType: helper type to define flow segment values -


->
<xsd:simpleType name="FlowSegmentItemValueType">
<xsd:restriction base='xsd:string'>
<xsd:pattern value=" \d*,\d*" />
</xsd:restriction>
</xsd:simpleType>

<!-- FlowItemType -->


<xsd:complexType name="FlowItemType" abstract = "true">
<xsd:complexContent>
<xsd:restriction base="anc:ItemType">
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>

<!-- FlowSegmentItemType -->


<xsd:complexType name="FlowSegmentItemType">
<xsd:complexContent>
<xsd:restriction base="anb:FlowItemType">
<xsd:attribute name="Name" use="required"
type="anb:SegmentItemNameType"/>
<xsd:attribute name="Value" use="required"
type="anb:FlowSegmentItemValueType"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>

<!-- FlowCountItemType -->


<xsd:complexType name="FlowCountItemType">
<xsd:complexContent>
<xsd:restriction base="anb:FlowItemType">
<xsd:attribute name="Name" type="anb:CountItemNameType"
use="required"/>
<xsd:attribute name="Value" type="anb:NumberType" use="required"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>

<!-- CharacterRangeType is an extension of ContentLocatorPartType that


locates
* part of the content within a FlowDocument. CharacterRangeType
contains one
* "Item" element with name "Count" and value the number(N) of
"SegmentXX"
* elements that this ContentLocatorPart has. It also contains N "Item"
* elements with name "SegmentXX" where XX is a number from 0 to N-1.
The
* value of each "SegmentXX" element is a string in the form "offset,
length"
* which locates one sequence of symbols in the FlowDocument. Example:

* <anb:CharacterRange>
* <anc:Item Name="Count" Value="2" />
* <anc:Item Name="Segment0" Value="5,10" />
* <anc:Item Name="Segment1" Value="25,2" />
* </anb:CharacterRange>
-->
<xsd:complexType name="CharacterRangeType">
<xsd:complexContent>
<xsd:extension base="anc:ContentLocatorPartType">
<xsd:sequence minOccurs="1" maxOccurs="unbounded">
<xsd:element name="Item" type="anb:FlowItemType" />
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>

<!-- CharacterRange element substitutes ContentLocatorPart element -->


<xsd:element name="CharacterRange" type="anb:CharacterRangeType"
substitutionGroup="anc:ContentLocatorPart"/>

<!-- Fixed LocatorPart -->

<!-- Helper type – FixedItemType -->


<xsd:complexType name="FixedItemType" abstract = "true">
<xsd:complexContent>
<xsd:restriction base="anc:ItemType">
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>

<!-- Helper type – FixedCountItemType: ContentLocatorPart items count -->


<xsd:complexType name="FixedCountItemType">
<xsd:complexContent>
<xsd:restriction base="anb:FixedItemType">
<xsd:attribute name="Name" type="anb:CountItemNameType"
use="required"/>
<xsd:attribute name="Value" type="anb:NumberType" use="required"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>

<!-- Helper type -FixedSegmentValue: Defines possible fixed segment values


-->
<xsd:simpleType name="FixedSegmentItemValueType">
<xsd:restriction base='xsd:string'>
<xsd:pattern value="\d*,\d*,\d*,\d*" />
</xsd:restriction>
</xsd:simpleType>

<!-- Helper type - FixedSegmentItemType -->


<xsd:complexType name="FixedSegmentItemType">
<xsd:complexContent>
<xsd:restriction base="anb:FixedItemType">
<xsd:attribute name="Name" use="required"
type="anb:SegmentItemNameType"/>
<xsd:attribute name="Value" use="required"
type="anb:FixedSegmentItemValueType "/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<!-- FixedTextRangeType is an extension of ContentLocatorPartType that
locates
* content within a FixedDocument. It contains one "Item" element with
name
* "Count" and value the number (N) of "Item" elements with name
"SegmentXX"
* that this ContentLocatorPart has. FixedTextRange locator part also
* contains N "Item" elements with one attribute Name="SegmentXX" where
XX is
* a number from 0 to N-1 and one attribute "Value" in the form "X1, Y1,
X2,
* Y2". Here X1,Y1 are the coordinates of the start symbol in this
segment,
* X2,Y2 are the coordinates of the end symbol in this segment.
Example:
*
* <anb:FixedTextRange>
* <anc:Item Name="Count" Value="2" />
* <anc:Item Name="Segment0" Value="10,5,20,5" />
* <anc:Item Name="Segment1" Value="25,15, 25,20" />
* </anb:FixedTextRange>
-->
<xsd:complexType name="FixedTextRangeType">
<xsd:complexContent>
<xsd:extension base="anc:ContentLocatorPartType">
<xsd:sequence minOccurs="1" maxOccurs="unbounded">
<xsd:element name="Item" type="anb:FixedItemType" />
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>

<!-- FixedTextRange element substitutes ContentLocatorPart element -->


<xsd:element name="FixedTextRange" type="anb:FixedTextRangeType"
substitutionGroup="anc:ContentLocatorPart"/>

<!-- DataId -->

<!-- ValueItemNameType: helper type to define value item -->


<xsd:simpleType name="ValueItemNameType">
<xsd:restriction base='xsd:string'>
<xsd:pattern value="Value" />
</xsd:restriction>
</xsd:simpleType>

<!-- StringValueItemType -->


<xsd:complexType name="StringValueItemType">
<xsd:complexContent>
<xsd:restriction base="anc:ItemType">
<xsd:attribute name="Name" type="anb:ValueItemNameType"
use="required"/>
<xsd:attribute name="Value" type="xsd:string" use="required"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="StringValueLocatorPartType">
<xsd:complexContent>
<xsd:extension base="anc:ContentLocatorPartType">
<xsd:sequence minOccurs="1" maxOccurs="1">
<xsd:element name="Item" type="anb:ValueItemType" />
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>

<!-- DataId element substitutes ContentLocatorPart and is used to locate a


* subtree in the logical tree. Including DataId locator part in a
* ContentLocator helps to narrow down the search for a particular
content.
* Example of DataId ContentLocatorPart:
*
* <anb:DataId>
* <anc:Item Name="Value" Value="FlowDocument" />
* </anb:DataId>
-->

<xsd:element name="DataId" type="anb: StringValueLocatorPartType "


substitutionGroup="anc:ContentLocatorPart"/>

<!-- PageNumber -->

<!-- NumberValueItemType -->


<xsd:complexType name="NumberValueItemType">
<xsd:complexContent>
<xsd:restriction base="anc:ItemType">
<xsd:attribute name="Name" type="anb:ValueItemNameType"
use="required"/>
<xsd:attribute name="Value" type="anb:NumberType" use="required"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>

<xsd:complexType name="NumberValueLocatorPartType">
<xsd:complexContent>
<xsd:extension base="anc:ContentLocatorPartType">
<xsd:sequence minOccurs="1" maxOccurs="1">
<xsd:element name="Item" type="anb:ValueItemType" />
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>

<!-- PageNumber element substitutes ContentLocatorPart and is used to


locate a
* page in a FixedDocument. PageNumber ContentLocatorPart is used in
* conjunction with the FixedTextRange ContentLocatorPart and it shows
on with
* page are the coordinates defined in the FixedTextRange.
* Example of a PageNumber ContentLocatorPart:
*
* <anb:PageNumber>
* <anc:Item Name="Value" Value="1" />
* </anb:PageNumber>
-->
<xsd:element name="PageNumber" type="anb:NumberValueLocatorPartType"
substitutionGroup="anc:ContentLocatorPart"/>

<!-- ***** Content ***** -->


<!-- Highlight colors – defines highlight color for annotations of type
* Highlight or normal and active anchor colors for annotations of type
* TextStickyNote and InkStickyNote.
-->
<xsd:complexType name="ColorsContentType">
<xsd:attribute name="Background" type='xsd:string' use="required" />
<xsd:attribute name="ActiveBackground" type='xsd:string' use="optional"
/>
</xsd:complexType>

<xsd:element name="Colors" type="anb:ColorsContentType"


substitutionGroup="anc:Content"/>

<!-- RTB Text –contains XAML representing StickyNote Reach Text Box text.
* Used in annotations of type TextStickyNote. -->
<xsd:complexType name="TextContentType">
<!-- See XAML schema for RTB content -->
</xsd:complexType>

<xsd:element name="Text" type="anb:TextContentType"


substitutionGroup="anc:Content"/>

<!-- Ink – contains XAML representing Sticky Note ink.


* Used in annotations of type InkStickyNote. -->
<xsd:complexType name="InkContentType">
<!-- See XAML schema for Ink content -->
</xsd:complexType>

<xsd:element name="Ink" type="anb:InkContentType"


substitutionGroup="anc:Content"/>

<!-- SN Metadata – defines StickyNote attributes as position width,


height,
* etc. Used in annotations of type TextStickyNote and InkStickyNote. -
->
<xsd:complexType name="MetadataContentType">
<xsd:attribute name="Left" type='xsd:decimal' use="optional" />
<xsd:attribute name="Top" type='xsd:decimal' use="optional" />
<xsd:attribute name="Width" type='xsd:decimal' use="optional" />
<xsd:attribute name="Height" type='xsd:decimal' use="optional" />
<xsd:attribute name="XOffset" type='xsd:decimal' use="optional" />
<xsd:attribute name="YOffset" type='xsd:decimal' use="optional" />
<xsd:attribute name="ZOrder" type='xsd:decimal' use="optional" />
</xsd:complexType>

<xsd:element name="Metadata" type="anb:MetadataContentType"


substitutionGroup="anc:Content"/>

</xsd:schema>

Sample XML Produced by Annotations


XmlStreamStore
The XML that follows shows the output of an Annotations XmlStreamStore and the
organization of a sample file that contains three annotations - a highlight, a text sticky-
note, and an ink stick-note.

XML

<?xml version="1.0" encoding="utf-8"?>


<anc:Annotations

xmlns:anc="http://schemas.microsoft.com/windows/annotations/2003/11/core"

xmlns:anb="http://schemas.microsoft.com/windows/annotations/2003/11/base">

<anc:Annotation Id="d308ea9b-36eb-4cc4-94d0-97634f10f7a2"
CreationTime="2006-09-13T18:28:51.4465702-07:00"
LastModificationTime="2006-09-13T18:28:51.4465702-07:00"
Type="anb:Highlight">
<anc:Anchors>
<anc:Resource Id="4f53661b-7328-4673-8e3f-c53f08b9cd94">
<anc:ContentLocator>
<anb:DataId>
<anc:Item Name="Value" Value="FlowDocument" />
</anb:DataId>
<anb:CharacterRange>
<anc:Item Name="Segment0" Value="600,609" />
<anc:Item Name="Count" Value="1" />
</anb:CharacterRange>
</anc:ContentLocator>
</anc:Resource>
</anc:Anchors>
</anc:Annotation>

<anc:Annotation Id="d7a8d271-387e-4144-9f8b-bc3c97816e5f"
CreationTime="2006-09-13T18:28:56.7903202-07:00"
LastModificationTime="2006-09-13T18:28:56.8996952-07:00"
Type="anb:TextStickyNote">
<anc:Authors>
<anb:StringAuthor>Denise Smith</anb:StringAuthor>
</anc:Authors>

<anc:Anchors>
<anc:Resource Id="dab2560e-6ebd-4ad0-80f9-483356a3be0b">
<anc:ContentLocator>
<anb:DataId>
<anc:Item Name="Value" Value="FlowDocument" />
</anb:DataId>
<anb:CharacterRange>
<anc:Item Name="Segment0" Value="787,801" />
<anc:Item Name="Count" Value="1" />
</anb:CharacterRange>
</anc:ContentLocator>
</anc:Resource>
</anc:Anchors>

<anc:Cargos>
<anc:Resource Id="ea4dbabd-b400-4cf9-8908-5716b410f9e4" Name="Meta
Data">
<anb:MetaData anb:ZOrder="0" />
</anc:Resource>
</anc:Cargos>
</anc:Annotation>

<anc:Annotation Id="66803c69-b0d7-4cc3-bdff-cacc1955e806"
CreationTime="2006-09-13T18:29:03.6653202-07:00"
LastModificationTime="2006-09-13T18:29:03.7121952-07:00"
Type="anb:InkStickyNote">
<anc:Authors>
<anb:StringAuthor>Mike Nash</anb:StringAuthor>
</anc:Authors>

<anc:Anchors>
<anc:Resource Id="52251c53-8eeb-4fd7-b8f3-94e78dfc25fa">
<anc:ContentLocator>
<anb:DataId>
<anc:Item Name="Value" Value="FlowDocument" />
</anb:DataId>
<anb:CharacterRange>
<anc:Item Name="Segment0" Value="880,884" />
<anc:Item Name="Count" Value="1" />
</anb:CharacterRange>
</anc:ContentLocator>
</anc:Resource>
</anc:Anchors>

<anc:Cargos>
<anc:Resource Id="11e50b97-8d91-4ff9-82c3-16607b2b552b" Name="Meta
Data">
<anb:MetaData anb:ZOrder="1" />
</anc:Resource>
</anc:Cargos>
</anc:Annotation>

</anc:Annotations>

See also
System.Windows.Annotations
System.Windows.Annotations.Storage
Annotation
AnnotationStore
XmlStreamStore
Annotations Overview
Flow Content
Article • 02/06/2023

Flow content elements provide the building blocks for creating flow content suitable for
hosting in a FlowDocument.

In This Section
Flow Document Overview
TextElement Content Model Overview
Table Overview
How-to Topics

Reference
FlowDocument
Block
List
Paragraph
Section
Table
Figure
Floater
Hyperlink
Inline
Run
Span
ListItem

Related Sections
Documents in WPF
Flow Document Overview
Article • 07/26/2022

Flow documents are designed to optimize viewing and readability. Rather than being set
to one predefined layout, flow documents dynamically adjust and reflow their content
based on run-time variables such as window size, device resolution, and optional user
preferences. In addition, flow documents offer advanced document features, such as
pagination and columns. This topic provides an overview of flow documents and how to
create them.

What is a Flow Document


A flow document is designed to "reflow content" depending on window size, device
resolution, and other environment variables. In addition, flow documents have a number
of built in features including search, viewing modes that optimize readability, and the
ability to change the size and appearance of fonts. Flow Documents are best utilized
when ease of reading is the primary document consumption scenario. In contrast, Fixed
Documents are designed to have a static presentation. Fixed Documents are useful
when fidelity of the source content is essential. See Documents in WPF for more
information on different types of documents.

The following illustration shows a sample flow document viewed in several windows of
different sizes. As the display area changes, the content reflows to make the best use of
the available space.
As seen in the image above, flow content can include many components including
paragraphs, lists, images, and more. These components correspond to elements in
markup and objects in procedural code. We will go over these classes in detail later in
the Flow Related Classes section of this overview. For now, here is a simple code
example that creates a flow document consisting of a paragraph with some bold text
and a list.

XAML

<!-- This simple flow document includes a paragraph with some


bold text in it and a list. -->
<FlowDocumentReader
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<FlowDocument>
<Paragraph>
<Bold>Some bold text in the paragraph.</Bold>
Some text that is not bold.
</Paragraph>

<List>
<ListItem>
<Paragraph>ListItem 1</Paragraph>
</ListItem>
<ListItem>
<Paragraph>ListItem 2</Paragraph>
</ListItem>
<ListItem>
<Paragraph>ListItem 3</Paragraph>
</ListItem>
</List>

</FlowDocument>
</FlowDocumentReader>

C#

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace SDKSample
{
public partial class SimpleFlowExample : Page
{
public SimpleFlowExample()
{

Paragraph myParagraph = new Paragraph();

// Add some Bold text to the paragraph


myParagraph.Inlines.Add(new Bold(new Run("Some bold text in the
paragraph.")));

// Add some plain text to the paragraph


myParagraph.Inlines.Add(new Run(" Some text that is not
bold."));

// Create a List and populate with three list items.


List myList = new List();

// First create paragraphs to go into the list item.


Paragraph paragraphListItem1 = new Paragraph(new Run("ListItem
1"));
Paragraph paragraphListItem2 = new Paragraph(new Run("ListItem
2"));
Paragraph paragraphListItem3 = new Paragraph(new Run("ListItem
3"));

// Add ListItems with paragraphs in them.


myList.ListItems.Add(new ListItem(paragraphListItem1));
myList.ListItems.Add(new ListItem(paragraphListItem2));
myList.ListItems.Add(new ListItem(paragraphListItem3));

// Create a FlowDocument with the paragraph and list.


FlowDocument myFlowDocument = new FlowDocument();
myFlowDocument.Blocks.Add(myParagraph);
myFlowDocument.Blocks.Add(myList);

// Add the FlowDocument to a FlowDocumentReader Control


FlowDocumentReader myFlowDocumentReader = new
FlowDocumentReader();
myFlowDocumentReader.Document = myFlowDocument;

this.Content = myFlowDocumentReader;
}
}
}

The illustration below shows what this code snippet looks like.

In this example, the FlowDocumentReader control is used to host the flow content. See
Flow Document Types for more information on flow content hosting controls.
Paragraph, List, ListItem, and Bold elements are used to control content formatting,
based on their order in markup. For example, the Bold element spans across only part of
the text in the paragraph; as a result, only that part of the text is bold. If you have used
HTML, this will be familiar to you.

As highlighted in the illustration above, there are several features built into Flow
Documents:
Search: Allows the user to perform a full text search of an entire document.

Viewing Mode: The user can select their preferred viewing mode including a
single-page (page-at-a-time) viewing mode, a two-page-at-a-time (book reading
format) viewing mode, and a continuous scrolling (bottomless) viewing mode. For
more information about these viewing modes, see
FlowDocumentReaderViewingMode.

Page Navigation Controls: If the viewing mode of the document uses pages, the
page navigation controls include a button to jump to the next page (the down
arrow) or previous page (the up arrow), as well as indicators for the current page
number and total number of pages. Flipping through pages can also be
accomplished using the keyboard arrow keys.

Zoom: The zoom controls enable the user to increase or decrease the zoom level
by clicking the plus or minus buttons, respectively. The zoom controls also include
a slider for adjusting the zoom level. For more information, see Zoom.

These features can be modified based upon the control used to host the flow content.
The next section describes the different controls.

Flow Document Types


Display of flow document content and how it appears is dependent upon what object is
used to host the flow content. There are four controls that support viewing of flow
content: FlowDocumentReader, FlowDocumentPageViewer, RichTextBox, and
FlowDocumentScrollViewer. These controls are briefly described below.

7 Note

FlowDocument is required to directly host flow content, so all of these viewing


controls consume a FlowDocument to enable flow content hosting.

FlowDocumentReader
FlowDocumentReader includes features that enable the user to dynamically choose
between various viewing modes, including a single-page (page-at-a-time) viewing
mode, a two-page-at-a-time (book reading format) viewing mode, and a continuous
scrolling (bottomless) viewing mode. For more information about these viewing modes,
see FlowDocumentReaderViewingMode. If you do not need the ability to dynamically
switch between different viewing modes, FlowDocumentPageViewer and
FlowDocumentScrollViewer provide lighter-weight flow content viewers that are fixed in
a particular viewing mode.

FlowDocumentPageViewer and
FlowDocumentScrollViewer
FlowDocumentPageViewer shows content in page-at-a-time viewing mode, while
FlowDocumentScrollViewer shows content in continuous scrolling mode. Both
FlowDocumentPageViewer and FlowDocumentScrollViewer are fixed to a particular
viewing mode. Compare to FlowDocumentReader, which includes features that enable
the user to dynamically choose between various viewing modes (as provided by the
FlowDocumentReaderViewingMode enumeration), at the cost of being more resource
intensive than FlowDocumentPageViewer or FlowDocumentScrollViewer.

By default, a vertical scrollbar is always shown, and a horizontal scrollbar becomes


visible if needed. The default UI for FlowDocumentScrollViewer does not include a
toolbar; however, the IsToolBarVisible property can be used to enable a built-in toolbar.

RichTextBox
You use a RichTextBox when you want to allow the user to edit flow content. For
example, if you wanted to create an editor that allowed a user to manipulate things like
tables, italic and bold formatting, etc, you would use a RichTextBox. See RichTextBox
Overview for more information.

7 Note

Flow content inside a RichTextBox does not behave exactly like flow content
contained in other controls. For example, there are no columns in a RichTextBox
and hence no automatic resizing behavior. Also, the typically built in features of
flow content like search, viewing mode, page navigation, and zoom are not
available within a RichTextBox.

Creating Flow Content


Flow content can be complex, consisting of various elements including text, images,
tables, and even UIElement derived classes like controls. To understand how to create
complex flow content, the following points are critical:
Flow-related Classes: Each class used in flow content has a specific purpose. In
addition, the hierarchical relation between flow classes helps you understand how
they are used. For example, classes derived from the Block class are used to
contain other objects while classes derived from Inline contain objects that are
displayed.

Content Schema: A flow document can require a substantial number of nested


elements. The content schema specifies possible parent/child relationships
between elements.

The following sections will go over each of these areas in more detail.

Flow Related Classes


The diagram below shows the objects most typically used with flow content:

For the purposes of flow content, there are two important categories:

1. Block-derived classes: Also called "Block content elements" or just "Block


Elements". Elements that inherit from Block can be used to group elements under
a common parent or to apply common attributes to a group.

2. Inline-derived classes: Also called "Inline content elements" or just "Inline


Elements". Elements that inherit from Inline are either contained within a Block
Element or another Inline Element. Inline Elements are often used as the direct
container of content that is rendered to the screen. For example, a Paragraph
(Block Element) can contain a Run (Inline Element) but the Run actually contains
the text that is rendered on the screen.
Each class in these two categories is briefly described below.

Block-derived Classes
Paragraph

Paragraph is typically used to group content into a paragraph. The simplest and most
common use of Paragraph is to create a paragraph of text.

XAML

<FlowDocument
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Paragraph>
Some paragraph text.
</Paragraph>
</FlowDocument>

C#

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace SDKSample
{
public partial class ParagraphExample : Page
{
public ParagraphExample()
{

// Create paragraph with some text.


Paragraph myParagraph = new Paragraph();
myParagraph.Inlines.Add(new Run("Some paragraph text."));

// Create a FlowDocument and add the paragraph to it.


FlowDocument myFlowDocument = new FlowDocument();
myFlowDocument.Blocks.Add(myParagraph);

this.Content = myFlowDocument;
}
}
}

However, you can also contain other inline-derived elements as you will see below.

Section
Section is used only to contain other Block-derived elements. It does not apply any
default formatting to the elements it contains. However, any property values set on a
Section applies to its child elements. A section also enables you to programmatically
iterate through its child collection. Section is used in a similar manner to the <DIV> tag
in HTML.

In the example below, three paragraphs are defined under one Section. The section has
a Background property value of Red, therefore the background color of the paragraphs
is also red.

XAML

<FlowDocument
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- By default, Section applies no formatting to elements contained
within it. However, in this example, the section has a Background
property value of "Red", therefore, the three paragraphs (the block)
inside the section also have a red background. -->
<Section Background="Red">
<Paragraph>
Paragraph 1
</Paragraph>
<Paragraph>
Paragraph 2
</Paragraph>
<Paragraph>
Paragraph 3
</Paragraph>
</Section>
</FlowDocument>

C#

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Documents;

namespace SDKSample
{
public partial class SectionExample : Page
{
public SectionExample()
{

// Create three paragraphs


Paragraph myParagraph1 = new Paragraph(new Run("Paragraph 1"));
Paragraph myParagraph2 = new Paragraph(new Run("Paragraph 2"));
Paragraph myParagraph3 = new Paragraph(new Run("Paragraph 3"));

// Create a Section and add the three paragraphs to it.


Section mySection = new Section();
mySection.Background = Brushes.Red;

mySection.Blocks.Add(myParagraph1);
mySection.Blocks.Add(myParagraph2);
mySection.Blocks.Add(myParagraph3);

// Create a FlowDocument and add the section to it.


FlowDocument myFlowDocument = new FlowDocument();
myFlowDocument.Blocks.Add(mySection);

this.Content = myFlowDocument;
}
}
}

BlockUIContainer

BlockUIContainer enables UIElement elements (i.e. a Button) to be embedded in block-


derived flow content. InlineUIContainer (see below) is used to embed UIElement
elements in inline-derived flow content. BlockUIContainer and InlineUIContainer are
important because there is no other way to use a UIElement in flow content unless it is
contained within one of these two elements.

The following example shows how to use the BlockUIContainer element to host
UIElement objects within flow content.

XAML

<FlowDocument ColumnWidth="400">
<Section Background="GhostWhite">
<Paragraph>
A UIElement element may be embedded directly in flow content
by enclosing it in a BlockUIContainer element.
</Paragraph>
<BlockUIContainer>
<Button>Click me!</Button>
</BlockUIContainer>
<Paragraph>
The BlockUIContainer element may host no more than one top-level
UIElement. However, other UIElements may be nested within the
UIElement contained by an BlockUIContainer element. For example,
a StackPanel can be used to host multiple UIElement elements within
a BlockUIContainer element.
</Paragraph>
<BlockUIContainer>
<StackPanel>
<Label Foreground="Blue">Choose a value:</Label>
<ComboBox>
<ComboBoxItem IsSelected="True">a</ComboBoxItem>
<ComboBoxItem>b</ComboBoxItem>
<ComboBoxItem>c</ComboBoxItem>
</ComboBox>
<Label Foreground ="Red">Choose a value:</Label>
<StackPanel>
<RadioButton>x</RadioButton>
<RadioButton>y</RadioButton>
<RadioButton>z</RadioButton>
</StackPanel>
<Label>Enter a value:</Label>
<TextBox>
A text editor embedded in flow content.
</TextBox>
</StackPanel>
</BlockUIContainer>
</Section>
</FlowDocument>

The following figure shows how this example renders:

List

List is used to create a bulleted or numeric list. Set the MarkerStyle property to a
TextMarkerStyle enumeration value to determine the style of the list. The example below
shows how to create a simple list.

XAML
<FlowDocument
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<List>
<ListItem>
<Paragraph>
List Item 1
</Paragraph>
</ListItem>
<ListItem>
<Paragraph>
List Item 2
</Paragraph>
</ListItem>
<ListItem>
<Paragraph>
List Item 3
</Paragraph>
</ListItem>
</List>
</FlowDocument>

C#

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Documents;

namespace SDKSample
{
public partial class ListExample : Page
{
public ListExample()
{

// Create three paragraphs


Paragraph myParagraph1 = new Paragraph(new Run("List Item 1"));
Paragraph myParagraph2 = new Paragraph(new Run("List Item 2"));
Paragraph myParagraph3 = new Paragraph(new Run("List Item 3"));

// Create the ListItem elements for the List and add the
// paragraphs to them.
ListItem myListItem1 = new ListItem();
myListItem1.Blocks.Add(myParagraph1);
ListItem myListItem2 = new ListItem();
myListItem2.Blocks.Add(myParagraph2);
ListItem myListItem3 = new ListItem();
myListItem3.Blocks.Add(myParagraph3);

// Create a List and add the three ListItems to it.


List myList = new List();

myList.ListItems.Add(myListItem1);
myList.ListItems.Add(myListItem2);
myList.ListItems.Add(myListItem3);

// Create a FlowDocument and add the section to it.


FlowDocument myFlowDocument = new FlowDocument();
myFlowDocument.Blocks.Add(myList);

this.Content = myFlowDocument;
}
}
}

7 Note

List is the only flow element that uses the ListItemCollection to manage child
elements.

Table

Table is used to create a table. Table is similar to the Grid element but it has more
capabilities and, therefore, requires greater resource overhead. Because Grid is a
UIElement, it cannot be used in flow content unless it is contained in a BlockUIContainer
or InlineUIContainer. For more information on Table, see Table Overview.

Inline-derived Classes
Run

Run is used to contain unformatted text. You might expect Run objects to be used
extensively in flow content. However, in markup, Run elements are not required to be
used explicitly. Run is required to be used when creating or manipulating flow
documents by using code. For example, in the markup below, the first Paragraph
specifies the Run element explicitly while the second does not. Both paragraphs
generate identical output.

XAML

<Paragraph>
<Run>Paragraph that explicitly uses the Run element.</Run>
</Paragraph>

<Paragraph>
This Paragraph omits the Run element in markup. It renders
the same as a Paragraph with Run used explicitly.
</Paragraph>

7 Note

Starting in the .NET Framework 4, the Text property of the Run object is a
dependency property. You can bind the Text property to a data source, such as a
TextBlock. The Text property fully supports one-way binding. The Text property
also supports two-way binding, except for RichTextBox. For an example, see
Run.Text.

Span

Span groups other inline content elements together. No inherent rendering is applied to
content within a Span element. However, elements that inherit from Span including
Hyperlink, Bold, Italic and Underline do apply formatting to text.

Below is an example of a Span being used to contain inline content including text, a
Bold element, and a Button.

XAML

<FlowDocument
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Paragraph>
Text before the Span. <Span Background="Red">Text within the Span is
red and <Bold>this text is inside the Span-derived element Bold.</Bold>
A Span can contain more then text, it can contain any inline content.
For
example, it can contain a
<InlineUIContainer>
<Button>Button</Button>
</InlineUIContainer>
or other UIElement, a Floater, a Figure, etc.</Span>
</Paragraph>

</FlowDocument>

The following screenshot shows how this example renders.


InlineUIContainer

InlineUIContainer enables UIElement elements (i.e. a control like Button) to be


embedded in an Inline content element. This element is the inline equivalent to
BlockUIContainer described above. Below is an example that uses InlineUIContainer to
insert a Button inline in a Paragraph.

XAML

<FlowDocument
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Paragraph>
Text to precede the button...

<!-- Set the BaselineAlignment property to "Bottom"


so that the Button aligns properly with the text. -->
<InlineUIContainer BaselineAlignment="Bottom">
<Button>Button</Button>
</InlineUIContainer>
Text to follow the button...
</Paragraph>

</FlowDocument>

C#

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Documents;

namespace SDKSample
{
public partial class InlineUIContainerExample : Page
{
public InlineUIContainerExample()
{
Run run1 = new Run(" Text to precede the button... ");
Run run2 = new Run(" Text to follow the button... ");

// Create a new button to be hosted in the paragraph.


Button myButton = new Button();
myButton.Content = "Click me!";

// Create a new InlineUIContainer to contain the Button.


InlineUIContainer myInlineUIContainer = new InlineUIContainer();

// Set the BaselineAlignment property to "Bottom" so that the


// Button aligns properly with the text.
myInlineUIContainer.BaselineAlignment =
BaselineAlignment.Bottom;

// Asign the button as the UI container's child.


myInlineUIContainer.Child = myButton;

// Create the paragraph and add content to it.


Paragraph myParagraph = new Paragraph();
myParagraph.Inlines.Add(run1);
myParagraph.Inlines.Add(myInlineUIContainer);
myParagraph.Inlines.Add(run2);

// Create a FlowDocument and add the paragraph to it.


FlowDocument myFlowDocument = new FlowDocument();
myFlowDocument.Blocks.Add(myParagraph);

this.Content = myFlowDocument;
}
}
}

7 Note

InlineUIContainer does not need to be used explicitly in markup. If you omit it, an
InlineUIContainer will be created anyway when the code is compiled.

Figure and Floater

Figure and Floater are used to embed content in Flow Documents with placement
properties that can be customized independent of the primary content flow. Figure or
Floater elements are often used to highlight or accentuate portions of content, to host
supporting images or other content within the main content flow, or to inject loosely
related content such as advertisements.

The following example shows how to embed a Figure into a paragraph of text.

XAML

<FlowDocument
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Paragraph>
<Figure
Width="300" Height="100"
Background="GhostWhite" HorizontalAnchor="PageLeft" >
<Paragraph FontStyle="Italic" Background="Beige"
Foreground="DarkGreen" >
A Figure embeds content into flow content with placement properties
that can be customized independently from the primary content flow
</Paragraph>
</Figure>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam
nonummy
nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut
wisi
enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit
lobortis
nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure.
</Paragraph>

</FlowDocument>

C#

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Documents;

namespace SDKSample
{
public partial class FigureExample : Page
{
public FigureExample()
{

// Create strings to use as content.


string strFigure = "A Figure embeds content into flow content
with" +
" placement properties that can be
customized" +
" independently from the primary content
flow";
string strOther = "Lorem ipsum dolor sit amet, consectetuer
adipiscing" +
" elit, sed diam nonummy nibh euismod
tincidunt ut laoreet" +
" dolore magna aliquam erat volutpat. Ut wisi
enim ad" +
" minim veniam, quis nostrud exerci tation
ullamcorper" +
" suscipit lobortis nisl ut aliquip ex ea
commodo consequat." +
" Duis autem vel eum iriure.";

// Create a Figure and assign content and layout properties to


it.
Figure myFigure = new Figure();
myFigure.Width = new FigureLength(300);
myFigure.Height = new FigureLength(100);
myFigure.Background = Brushes.GhostWhite;
myFigure.HorizontalAnchor = FigureHorizontalAnchor.PageLeft;
Paragraph myFigureParagraph = new Paragraph(new Run(strFigure));
myFigureParagraph.FontStyle = FontStyles.Italic;
myFigureParagraph.Background = Brushes.Beige;
myFigureParagraph.Foreground = Brushes.DarkGreen;
myFigure.Blocks.Add(myFigureParagraph);

// Create the paragraph and add content to it.


Paragraph myParagraph = new Paragraph();
myParagraph.Inlines.Add(myFigure);
myParagraph.Inlines.Add(new Run(strOther));

// Create a FlowDocument and add the paragraph to it.


FlowDocument myFlowDocument = new FlowDocument();
myFlowDocument.Blocks.Add(myParagraph);

this.Content = myFlowDocument;
}
}
}

The following illustration shows how this example renders.

Figure and Floater differ in several ways and are used for different scenarios.

Figure:

Can be positioned: You can set its horizontal and vertical anchors to dock it relative
to the page, content, column or paragraph. You can also use its HorizontalOffset
and VerticalOffset properties to specify arbitrary offsets.

Is sizable to more than one column: You can set Figure height and width to
multiples of page, content or column height or width. Note that in the case of
page and content, multiples greater than 1 are not allowed. For example, you can
set the width of a Figure to be "0.5 page" or "0.25 content" or "2 Column". You can
also set height and width to absolute pixel values.

Does not paginate: If the content inside a Figure does not fit inside the Figure, it
will render whatever content does fit and the remaining content is lost

Floater:

Cannot be positioned and will render wherever space can be made available for it.
You cannot set the offset or anchor a Floater.

Cannot be sized to more than one column: By default, Floater sizes at one column.
It has a Width property that can be set to an absolute pixel value, but if this value
is greater than one column width it is ignored and the floater is sized at one
column. You can size it to less than one column by setting the correct pixel width,
but sizing is not column-relative, so "0.5Column" is not a valid expression for
Floater width. Floater has no height property and it's height cannot be set, it’s
height depends on the content

Floater paginates: If its content at its specified width extends to more than 1
column height, floater breaks and paginates to the next column, the next page, etc.

Figure is a good place to put standalone content where you want to control the size and
positioning, and are confident that the content will fit in the specified size. Floater is a
good place to put more free-flowing content that flows similar to the main page
content, but is separated from it.

LineBreak

LineBreak causes a line break to occur in flow content. The following example
demonstrates the use of LineBreak.

XAML

<FlowDocument
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Paragraph>
Before the LineBreak in Paragraph.
<LineBreak />
After the LineBreak in Paragraph.
<LineBreak/><LineBreak/>
After two LineBreaks in Paragraph.
</Paragraph>

<Paragraph>
<LineBreak/>
</Paragraph>
<Paragraph>
After a Paragraph with only a LineBreak in it.
</Paragraph>
</FlowDocument>

The following screenshot shows how this example renders.

Flow Collection Elements


In many of the examples above, the BlockCollection and InlineCollection are used to
construct flow content programmatically. For example, to add elements to a Paragraph,
you can use the syntax:

C#

myParagraph.Inlines.Add(new Run("Some text"));

This adds a Run to the InlineCollection of the Paragraph. This is the same as the implicit
Run found inside a Paragraph in markup:

XML

<Paragraph>
Some Text
</Paragraph>

As an example of using the BlockCollection, the following example creates a new


Section and then uses the Add method to add a new Paragraph to the Section contents.

C#

Section secx = new Section();


secx.Blocks.Add(new Paragraph(new Run("A bit of text content...")));

In addition to adding items to a flow collection, you can remove items as well. The
following example deletes the last Inline element in the Span.
C#

spanx.Inlines.Remove(spanx.Inlines.LastInline);

The following example clears all of the contents (Inline elements) from the Span.

C#

spanx.Inlines.Clear();

When working with flow content programmatically, you will likely make extensive use of
these collections.

Whether a flow element uses an InlineCollection (Inlines) or BlockCollection (Blocks) to


contain its child elements depends on what type of child elements (Block or Inline) can
be contained by the parent. Containment rules for flow content elements are
summarized in the content schema in the next section.

7 Note

There is a third type of collection used with flow content, the ListItemCollection,
but this collection is only used with a List. In addition, there are several collections
used with Table. See Table Overview for more information.

Content Schema
Given the number of different flow content elements, it can be overwhelming to keep
track of what type of child elements an element can contain. The diagram below
summarizes the containment rules for flow elements. The arrows represent the possible
parent/child relationships.
As can be seen from the diagram above, the children allowed for an element are not
necessarily determined by whether it is a Block element or an Inline element. For
example, a Span (an Inline element) can only have Inline child elements while a Figure
(also an Inline element) can only have Block child elements. Therefore, a diagram is
useful for quickly determining what element can be contained in another. As an
example, let's use the diagram to determine how to construct the flow content of a
RichTextBox.

1. A RichTextBox must contain a FlowDocument which in turn must contain a Block-


derived object. Below is the corresponding segment from the diagram above.

Thus far, this is what the markup might look like.

XAML

<RichTextBox>
<FlowDocument>
<!-- One or more Block-derived object… -->
</FlowDocument>
</RichTextBox>
2. According to the diagram, there are several Block elements to choose from including
Paragraph, Section, Table, List, and BlockUIContainer (see Block-derived classes above).
Let's say we want a Table. According to the diagram above, a Table contains a
TableRowGroup containing TableRow elements, which contain TableCell elements which
contain a Block-derived object. Below is the corresponding segment for Table taken
from the diagram above.

Below is the corresponding markup.

XAML

<RichTextBox>
<FlowDocument>
<Table>
<TableRowGroup>
<TableRow>
<TableCell>
<!-- One or more Block-derived object… -->
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</FlowDocument>
</RichTextBox>

3. Again, one or more Block elements are required underneath a TableCell. To make it
simple, let's place some text inside the cell. We can do this using a Paragraph with a Run
element. Below is the corresponding segments from the diagram showing that a
Paragraph can take an Inline element and that a Run (an Inline element) can only take
plain text.

Below is the entire example in markup.

XAML
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<RichTextBox>
<FlowDocument>

<!-- Normally a table would have multiple rows and multiple


cells but this code is for demonstration purposes.-->
<Table>
<TableRowGroup>
<TableRow>
<TableCell>
<Paragraph>

<!-- The schema does not actually require


explicit use of the Run tag in markup. It
is only included here for clarity. -->
<Run>Paragraph in a Table Cell.</Run>
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>

</FlowDocument>
</RichTextBox>
</Page>

Customizing Text
Usually text is the most prevalent type of content in a flow document. Although the
objects introduced above can be used to control most aspects of how text is rendered,
there are some other methods for customizing text that is covered in this section.

Text Decorations
Text decorations allow you to apply the underline, overline, baseline, and strikethrough
effects to text (see pictures below). These decorations are added using the
TextDecorations property that is exposed by a number of objects including Inline,
Paragraph, TextBlock, and TextBox.

The following example shows how to set the TextDecorations property of a Paragraph.

XAML

<FlowDocument ColumnWidth="200">
<Paragraph TextDecorations="Strikethrough">
This text will render with the strikethrough effect.
</Paragraph>
</FlowDocument>

C#

Paragraph parx = new Paragraph(new Run("This text will render with the
strikethrough effect."));
parx.TextDecorations = TextDecorations.Strikethrough;

The following figure shows how this example renders.

The following figures show how the Overline, Baseline, and Underline decorations
render, respectively.

Typography
The Typography property is exposed by most flow-related content including
TextElement, FlowDocument, TextBlock, and TextBox. This property is used to control
typographical characteristics/variations of text (i.e. small or large caps, making
superscripts and subscripts, etc).

The following example shows how to set the Typography attribute, using Paragraph as
the example element.

XAML

<Paragraph
TextAlignment="Left"
FontSize="18"
FontFamily="Palatino Linotype"
Typography.NumeralStyle="OldStyle"
Typography.Fraction="Stacked"
Typography.Variants="Inferior"
>
<Run>
This text has some altered typography characteristics. Note
that use of an open type font is necessary for most typographic
properties to be effective.
</Run>
<LineBreak/><LineBreak/>
<Run>
0123456789 10 11 12 13
</Run>
<LineBreak/><LineBreak/>
<Run>
1/2 2/3 3/4
</Run>
</Paragraph>

The following figure shows how this example renders.

In contrast, the following figure shows how a similar example with default typographic
properties renders.

The following example shows how to set the Typography property programmatically.

C#

Paragraph par = new Paragraph();

Run runText = new Run(


"This text has some altered typography characteristics. Note" +
"that use of an open type font is necessary for most typographic" +
"properties to be effective.");
Run runNumerals = new Run("0123456789 10 11 12 13");
Run runFractions = new Run("1/2 2/3 3/4");

par.Inlines.Add(runText);
par.Inlines.Add(new LineBreak());
par.Inlines.Add(new LineBreak());
par.Inlines.Add(runNumerals);
par.Inlines.Add(new LineBreak());
par.Inlines.Add(new LineBreak());
par.Inlines.Add(runFractions);

par.TextAlignment = TextAlignment.Left;
par.FontSize = 18;
par.FontFamily = new FontFamily("Palatino Linotype");

par.Typography.NumeralStyle = FontNumeralStyle.OldStyle;
par.Typography.Fraction = FontFraction.Stacked;
par.Typography.Variants = FontVariants.Inferior;

See Typography in WPF for more information on typography.

See also
Text
Typography in WPF
How-to Topics
TextElement Content Model Overview
RichTextBox Overview
Documents in WPF
Table Overview
Annotations Overview
TextElement Content Model Overview
Article • 02/06/2023

This content model overview describes the supported content for a TextElement. The
Paragraph class is a type of TextElement. A content model describes what
objects/elements can be contained in others. This overview summarizes the content
model used for objects derived from TextElement. For more information, see Flow
Document Overview.

Content Model Diagram


The following diagram summarizes the content model for classes derived from
TextElement as well as how other non- TextElement classes fit into this model.

As can be seen from the preceding diagram, the children allowed for an element are not
necessarily determined by whether a class is derived from the Block class or an Inline
class. For example, a Span (an Inline-derived class) can only have Inline child elements,
but a Figure (also an Inline-derived class) can only have Block child elements. Therefore,
a diagram is useful for quickly determining what element can be contained in another.
As an example, let's use the diagram to determine how to construct the flow content of
a RichTextBox.

1. A RichTextBox must contain a FlowDocument which in turn must contain a Block-


derived object. The following is the corresponding segment from the preceding
diagram.

Thus far, this is what the markup might look like.

XAML

<RichTextBox>
<FlowDocument>
<!-- One or more Block-derived object… -->
</FlowDocument>
</RichTextBox>

2. According to the diagram, there are several Block elements to choose from
including Paragraph, Section, Table, List, and BlockUIContainer (see Block-derived
classes in the preceding diagram). Let's say we want a Table. According to the
preceding diagram, a Table contains a TableRowGroup containing TableRow
elements, which contain TableCell elements which contain a Block-derived object.
The following is the corresponding segment for Table taken from the preceding
diagram.

The following is the corresponding markup.

XAML

<RichTextBox>
<FlowDocument>
<Table>
<TableRowGroup>
<TableRow>
<TableCell>
<!-- One or more Block-derived object… -->
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</FlowDocument>
</RichTextBox>

3. Again, one or more Block elements are required underneath a TableCell. To make it
simple, let's place some text inside the cell. We can do this using a Paragraph with
a Run element. The following is the corresponding segments from the diagram
showing that a Paragraph can take an Inline element and that a Run (an Inline
element) can only take plain text.

The following is the entire example in markup.

XAML

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<RichTextBox>
<FlowDocument>

<!-- Normally a table would have multiple rows and multiple


cells but this code is for demonstration purposes.-->
<Table>
<TableRowGroup>
<TableRow>
<TableCell>
<Paragraph>

<!-- The schema does not actually require


explicit use of the Run tag in markup. It
is only included here for clarity. -->
<Run>Paragraph in a Table Cell.</Run>
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>

</FlowDocument>
</RichTextBox>
</Page>
Working with TextElement Content
Programmatically
The contents of a TextElement is made up by collections and so programmatically
manipulating the contents of TextElement objects is done by working with these
collections. There are three different collections used by TextElement -derived classes:

InlineCollection: Represents a collection of Inline elements. InlineCollection defines


the allowable child content of the Paragraph, Span, and TextBlock elements.

BlockCollection: Represents a collection of Block elements. BlockCollection defines


the allowable child content of the FlowDocument, Section, ListItem, TableCell,
Floater, and Figure elements.

ListItemCollection: A flow content element that represents a particular content


item in an ordered or unordered List.

You can manipulate (add or remove items) from these collections using the respective
properties of Inlines, Blocks, and ListItems. The following examples show how to
manipulate the contents of a Span using the Inlines property.

7 Note

Table uses several collections to manipulate its contents, but they are not covered
here. For more information, see Table Overview.

The following example creates a new Span object, and then uses the Add method to add
two text runs as content children of the Span.

C#

Span spanx = new Span();


spanx.Inlines.Add(new Run("A bit of text content..."));
spanx.Inlines.Add(new Run("A bit more text content..."));

The following example creates a new Run element and inserts it at the beginning of the
Span.

C#

Run runx = new Run("Text to insert...");


spanx.Inlines.InsertBefore(spanx.Inlines.FirstInline, runx);
The following example deletes the last Inline element in the Span.

C#

spanx.Inlines.Remove(spanx.Inlines.LastInline);

The following example clears all of the contents (Inline elements) from the Span.

C#

spanx.Inlines.Clear();

Types That Share This Content Model


The following types inherit from the TextElement class and may be used to display the
content described in this overview.

Bold, Figure, Floater, Hyperlink, InlineUIContainer, Italic, LineBreak, List, ListItem,


Paragraph, Run, Section, Span, Table, Underline.

Note that this list only includes nonabstract types distributed with the Windows SDK.
You may use other types that inherit from TextElement.

Types That Can Contain TextElement Objects


See WPF Content Model.

See also
Manipulate a FlowDocument through the Blocks Property
Manipulate Flow Content Elements through the Blocks Property
Manipulate a FlowDocument through the Blocks Property
Manipulate a Table's Columns through the Columns Property
Manipulate a Table's Row Groups through the RowGroups Property
Table Overview
Article • 02/06/2023

Table is a block level element that supports grid-based presentation of Flow document
content. The flexibility of this element makes it very useful, but also makes it more
complicated to understand and use correctly.

This topic contains the following sections.

Table Basics

How is Table Different then Grid?

Basic Table Structure

Table Containment

Row Groupings

Background Rendering Precedence

Spanning Rows or Columns

Building a Table With Code

[Related Topics]

Table Basics

How is Table Different then Grid?


Table and Grid share some common functionality, but each is best suited for different
scenarios. A Table is designed for use within flow content (see Flow Document Overview
for more information on flow content). Grids are best used inside of forms (basically
anywhere outside of flow content). Within a FlowDocument, Table supports flow content
behaviors like pagination, column reflow, and content selection while a Grid does not. A
Grid on the other hand is best used outside of a FlowDocument for many reasons
including Grid adds elements based on a row and column index, Table does not. The
Grid element allows layering of child content, allowing more than one element to exist
within a single "cell." Table does not support layering. Child elements of a Grid can be
absolutely positioned relative to the area of their "cell" boundaries. Table does not
support this feature. Finally, a Grid requires less resources then a Table so consider using
a Grid to improve performance.

Basic Table Structure


Table provides a grid-based presentation consisting of columns (represented by
TableColumn elements) and rows (represented by TableRow elements). TableColumn
elements do not host content; they simply define columns and characteristics of
columns. TableRow elements must be hosted in a TableRowGroup element, which
defines a grouping of rows for the table. TableCell elements, which contain the actual
content to be presented by the table, must be hosted in a TableRow element. TableCell
may only contain elements that derive from Block. Valid child elements for a TableCell
include.

BlockUIContainer

List

Paragraph

Section

Table

7 Note

TableCell elements may not directly host text content. For more information about
the containment rules for flow content elements like TableCell, see Flow Document
Overview.

7 Note

Table is similar to the Grid element but has more capabilities and, therefore,
requires greater resource overhead.

The following example defines a simple 2 x 3 table with XAML.

XAML

<!--
Table is a Block element, and as such must be hosted in a container
for Block elements. FlowDocument provides such a container.
-->
<FlowDocument>
<Table>
<!--
This table has 3 columns, each described by a TableColumn
element nested in a Table.Columns collection element.
-->
<Table.Columns>
<TableColumn />
<TableColumn />
<TableColumn />
</Table.Columns>
<!--
This table includes a single TableRowGroup which hosts 2 rows,
each described by a TableRow element.
-->
<TableRowGroup>
<!--
Each of the 2 TableRow elements hosts 3 cells, described by
TableCell elements.
-->
<TableRow>
<TableCell>
<!--
TableCell elements may only host elements derived from Block.
In this example, Paragaph elements serve as the ultimate content
containers for the cells in this table.
-->
<Paragraph>Cell at Row 1 Column 1</Paragraph>
</TableCell>
<TableCell>
<Paragraph>Cell at Row 1 Column 2</Paragraph>
</TableCell>
<TableCell>
<Paragraph>Cell at Row 1 Column 3</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Paragraph>Cell at Row 2 Column 1</Paragraph>
</TableCell>
<TableCell>
<Paragraph>Cell at Row 2 Column 2</Paragraph>
</TableCell>
<TableCell>
<Paragraph>Cell at Row 2 Column 3</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</FlowDocument>

The following figure shows how this example renders.


Table Containment
Table derives from the Block element, and adheres to the common rules for Block level
elements. A Table element may be contained by any of the following elements:

FlowDocument

TableCell

ListBoxItem

ListViewItem

Section

Floater

Figure

Row Groupings
The TableRowGroup element provides a way to arbitrarily group rows within a table;
every row in a table must belong to a row grouping. Rows within a row group often
share a common intent, and may be styled as a group. A common use for row
groupings is to separate special-purpose rows, such as a title, header, and footer rows,
from the primary content contained by the table.

The following example uses XAML to define a table with styled header and footer rows.

XAML

<Table>
<Table.Resources>
<!-- Style for header/footer rows. -->
<Style x:Key="headerFooterRowStyle" TargetType="{x:Type TableRowGroup}">
<Setter Property="FontWeight" Value="DemiBold"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Background" Value="LightGray"/>
</Style>

<!-- Style for data rows. -->


<Style x:Key="dataRowStyle" TargetType="{x:Type TableRowGroup}">
<Setter Property="FontSize" Value="12"/>
<Setter Property="FontStyle" Value="Italic"/>
</Style>
</Table.Resources>

<Table.Columns>
<TableColumn/> <TableColumn/> <TableColumn/> <TableColumn/>
</Table.Columns>

<!-- This TableRowGroup hosts a header row for the table. -->
<TableRowGroup Style="{StaticResource headerFooterRowStyle}">
<TableRow>
<TableCell/>
<TableCell><Paragraph>Gizmos</Paragraph></TableCell>
<TableCell><Paragraph>Thingamajigs</Paragraph></TableCell>
<TableCell><Paragraph>Doohickies</Paragraph></TableCell>
</TableRow>
</TableRowGroup>

<!-- This TableRowGroup hosts the main data rows for the table. -->
<TableRowGroup Style="{StaticResource dataRowStyle}">
<TableRow>
<TableCell><Paragraph Foreground="Blue">Blue</Paragraph></TableCell>
<TableCell><Paragraph>1</Paragraph></TableCell>
<TableCell><Paragraph>2</Paragraph></TableCell>
<TableCell><Paragraph>3</Paragraph> </TableCell>
</TableRow>
<TableRow>
<TableCell><Paragraph Foreground="Red">Red</Paragraph></TableCell>
<TableCell><Paragraph>1</Paragraph></TableCell>
<TableCell><Paragraph>2</Paragraph></TableCell>
<TableCell><Paragraph>3</Paragraph></TableCell>
</TableRow>
<TableRow>
<TableCell><Paragraph Foreground="Green">Green</Paragraph></TableCell>
<TableCell><Paragraph>1</Paragraph></TableCell>
<TableCell><Paragraph>2</Paragraph></TableCell>
<TableCell><Paragraph>3</Paragraph></TableCell>
</TableRow>
</TableRowGroup>

<!-- This TableRowGroup hosts a footer row for the table. -->
<TableRowGroup Style="{StaticResource headerFooterRowStyle}">
<TableRow>
<TableCell><Paragraph>Totals</Paragraph></TableCell>
<TableCell><Paragraph>3</Paragraph></TableCell>
<TableCell><Paragraph>6</Paragraph></TableCell>
<TableCell>
<Table></Table>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
The following figure shows how this example renders.

Background Rendering Precedence


Table elements render in the following order (z-order from lowest to highest). This order
cannot be changed. For example, there is no "Z-order" property for these elements that
you can use to override this established order.

1. Table

2. TableColumn

3. TableRowGroup

4. TableRow

5. TableCell

Consider the following example, which defines background colors for each of these
elements within a table.

XAML

<Table Background="Yellow">
<Table.Columns>
<TableColumn/>
<TableColumn Background="LightGreen"/>
<TableColumn/>
</Table.Columns>
<TableRowGroup>
<TableRow>
<TableCell/><TableCell/><TableCell/>
</TableRow>
</TableRowGroup>
<TableRowGroup Background="Tan">
<TableRow>
<TableCell/><TableCell/><TableCell/>
</TableRow>
<TableRow Background="LightBlue">
<TableCell/><TableCell Background="Purple"/><TableCell/>
</TableRow>
<TableRow>
<TableCell/><TableCell/><TableCell/>
</TableRow>
</TableRowGroup>
<TableRowGroup>
<TableRow>
<TableCell/><TableCell/><TableCell/>
</TableRow>
</TableRowGroup>
</Table>

The following figure shows how this example renders (showing background colors only).

Spanning Rows or Columns


Table cells may be configured to span multiple rows or columns by using the RowSpan
or ColumnSpan attributes, respectively.

Consider the following example, in which a cell spans three columns.

XAML

<Table>
<Table.Columns>
<TableColumn/>
<TableColumn/>
<TableColumn/>
</Table.Columns>

<TableRowGroup>
<TableRow>
<TableCell ColumnSpan="3" Background="Cyan">
<Paragraph>This cell spans all three columns.</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell Background="LightGray"><Paragraph>Cell 1</Paragraph>
</TableCell>
<TableCell Background="LightGray"><Paragraph>Cell 2</Paragraph>
</TableCell>
<TableCell Background="LightGray"><Paragraph>Cell 3</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
The following figure shows how this example renders.

Building a Table With Code


The following examples show how to programmatically create a Table and populate it
with content. The contents of the table are apportioned into five rows (represented by
TableRow objects contained in a RowGroups object) and six columns (represented by
TableColumn objects). The rows are used for different presentation purposes, including a
title row intended to title the entire table, a header row to describe the columns of data
in the table, and a footer row with summary information. Note that the notion of "title",
"header", and "footer" rows are not inherent to the table; these are simply rows with
different characteristics. Table cells contain the actual content, which can be comprised
of text, images, or nearly any other user interface (UI) element.

First, a FlowDocument is created to host the Table, and a new Table is created and added
to the contents of the FlowDocument.

C#

// Create the parent FlowDocument...


flowDoc = new FlowDocument();

// Create the Table...


table1 = new Table();
// ...and add it to the FlowDocument Blocks collection.
flowDoc.Blocks.Add(table1);

// Set some global formatting properties for the table.


table1.CellSpacing = 10;
table1.Background = Brushes.White;

Next, six TableColumn objects are created and added to the table's Columns collection,
with some formatting applied.

7 Note

Note that the table's Columns collection uses standard zero-based indexing.

C#
// Create 6 columns and add them to the table's Columns collection.
int numberOfColumns = 6;
for (int x = 0; x < numberOfColumns; x++)
{
table1.Columns.Add(new TableColumn());

// Set alternating background colors for the middle colums.


if(x%2 == 0)
table1.Columns[x].Background = Brushes.Beige;
else
table1.Columns[x].Background = Brushes.LightSteelBlue;
}

Next, a title row is created and added to the table with some formatting applied. The
title row happens to contain a single cell that spans all six columns in the table.

C#

// Create and add an empty TableRowGroup to hold the table's Rows.


table1.RowGroups.Add(new TableRowGroup());

// Add the first (title) row.


table1.RowGroups[0].Rows.Add(new TableRow());

// Alias the current working row for easy reference.


TableRow currentRow = table1.RowGroups[0].Rows[0];

// Global formatting for the title row.


currentRow.Background = Brushes.Silver;
currentRow.FontSize = 40;
currentRow.FontWeight = System.Windows.FontWeights.Bold;

// Add the header row with content,


currentRow.Cells.Add(new TableCell(new Paragraph(new Run("2004 Sales
Project"))));
// and set the row to span all 6 columns.
currentRow.Cells[0].ColumnSpan = 6;

Next, a header row is created and added to the table, and the cells in the header row are
created and populated with content.

C#

// Add the second (header) row.


table1.RowGroups[0].Rows.Add(new TableRow());
currentRow = table1.RowGroups[0].Rows[1];

// Global formatting for the header row.


currentRow.FontSize = 18;
currentRow.FontWeight = FontWeights.Bold;

// Add cells with content to the second row.


currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Product"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 1"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 2"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 3"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 4"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("TOTAL"))));

Next, a row for data is created and added to the table, and the cells in this row are
created and populated with content. Building this row is similar to building the header
row, with slightly different formatting applied.

C#

// Add the third row.


table1.RowGroups[0].Rows.Add(new TableRow());
currentRow = table1.RowGroups[0].Rows[2];

// Global formatting for the row.


currentRow.FontSize = 12;
currentRow.FontWeight = FontWeights.Normal;

// Add cells with content to the third row.


currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Widgets"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$50,000"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$55,000"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$60,000"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$65,000"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$230,000"))));

// Bold the first cell.


currentRow.Cells[0].FontWeight = FontWeights.Bold;

Finally, a footer row is created, added, and formatted. Like the title row, the footer
contains a single cell that spans all six columns in the table.

C#

table1.RowGroups[0].Rows.Add(new TableRow());
currentRow = table1.RowGroups[0].Rows[3];

// Global formatting for the footer row.


currentRow.Background = Brushes.LightGray;
currentRow.FontSize = 18;
currentRow.FontWeight = System.Windows.FontWeights.Normal;

// Add the header row with content,


currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Projected 2004
Revenue: $810,000"))));
// and set the row to span all 6 columns.
currentRow.Cells[0].ColumnSpan = 6;

See also
Flow Document Overview
Define a Table with XAML
Documents in WPF
Use Flow Content Elements
Flow Content Elements How-to Topics
Article • 02/06/2023

The topics in this section describe how to accomplish common tasks using various flow
content elements and related features.

In This Section
Adjust Spacing Between Paragraphs
Build a Table Programmatically
Change the FlowDirection of Content Programmatically
Change the TextWrapping Property Programmatically
Define a Table with XAML
Alter the Typography of Text
Enable Text Trimming
Insert an Element Into Text Programmatically
Manipulate Flow Content Elements through the Blocks Property
Manipulate Flow Content Elements through the Inlines Property
Manipulate a FlowDocument through the Blocks Property
Manipulate a Table's Columns through the Columns Property
Manipulate a Table's Row Groups through the RowGroups Property
Use Flow Content Elements
Use FlowDocument Column-Separating Attributes

Reference
FlowDocument
Block
Inline

Related Sections
Documents in WPF
How to: Adjust Spacing Between
Paragraphs
Article • 02/06/2023

This example shows how to adjust or eliminate spacing between paragraphs in flow
content.

In flow content, extra space that appears between paragraphs is the result of margins
set on these paragraphs; thus, the spacing between paragraphs can be controlled by
adjusting the margins on those paragraphs. To eliminate extra spacing between two
paragraphs altogether, set the margins for the paragraphs to 0. To achieve uniform
spacing between paragraphs throughout an entire FlowDocument, use styling to set a
uniform margin value for all paragraphs in the FlowDocument.

It is important to note that the margins for two adjacent paragraphs will "collapse" to
the larger of the two margins, rather than doubling up. So, if two adjacent paragraphs
have margins of 20 pixels and 40 pixels respectively, the resulting space between the
paragraphs is 40 pixels, the larger of the two margin values.

Example
The following example uses styling to set the margin for all Paragraph elements in a
FlowDocument to 0, which effectively eliminates extra spacing between paragraphs in
the FlowDocument.

XAML

<FlowDocument>
<FlowDocument.Resources>
<!-- This style is used to set the margins for all paragraphs in the
FlowDocument to 0. -->
<Style TargetType="{x:Type Paragraph}">
<Setter Property="Margin" Value="0"/>
</Style>
</FlowDocument.Resources>

<Paragraph>
Spacing between paragraphs is caused by margins set on the paragraphs.
Two adjacent margins
will "collapse" to the larger of the two margin widths, rather than
doubling up.
</Paragraph>

<Paragraph>
To eliminate extra spacing between two paragraphs, just set the
paragraph margins to 0.
</Paragraph>
</FlowDocument>
How to: Build a Table Programmatically
Article • 02/06/2023

The following examples show how to programmatically create a Table and populate it
with content. The contents of the table are apportioned into five rows (represented by
TableRow objects contained in a RowGroups object) and six columns (represented by
TableColumn objects). The rows are used for different presentation purposes, including a
title row intended to title the entire table, a header row to describe the columns of data
in the table, and a footer row with summary information. Note that the notion of "title",
"header", and "footer" rows are not inherent to the table; these are simply rows with
different characteristics. Table cells contain the actual content, which can be comprised
of text, images, or nearly any other user interface (UI) element.

Create a table
First, a FlowDocument is created to host the Table, and a new Table is created and added
to the contents of the FlowDocument.

C#

// Create the parent FlowDocument...


flowDoc = new FlowDocument();

// Create the Table...


table1 = new Table();
// ...and add it to the FlowDocument Blocks collection.
flowDoc.Blocks.Add(table1);

// Set some global formatting properties for the table.


table1.CellSpacing = 10;
table1.Background = Brushes.White;

Add columns
Next, six TableColumn objects are created and added to the table's Columns collection,
with some formatting applied.

7 Note

Note that the table's Columns collection uses standard zero-based indexing.
C#

// Create 6 columns and add them to the table's Columns collection.


int numberOfColumns = 6;
for (int x = 0; x < numberOfColumns; x++)
{
table1.Columns.Add(new TableColumn());

// Set alternating background colors for the middle colums.


if(x%2 == 0)
table1.Columns[x].Background = Brushes.Beige;
else
table1.Columns[x].Background = Brushes.LightSteelBlue;
}

Add a title row


Next, a title row is created and added to the table with some formatting applied. The
title row happens to contain a single cell that spans all six columns in the table.

C#

// Create and add an empty TableRowGroup to hold the table's Rows.


table1.RowGroups.Add(new TableRowGroup());

// Add the first (title) row.


table1.RowGroups[0].Rows.Add(new TableRow());

// Alias the current working row for easy reference.


TableRow currentRow = table1.RowGroups[0].Rows[0];

// Global formatting for the title row.


currentRow.Background = Brushes.Silver;
currentRow.FontSize = 40;
currentRow.FontWeight = System.Windows.FontWeights.Bold;

// Add the header row with content,


currentRow.Cells.Add(new TableCell(new Paragraph(new Run("2004 Sales
Project"))));
// and set the row to span all 6 columns.
currentRow.Cells[0].ColumnSpan = 6;

Add a header row


Next, a header row is created and added to the table, and the cells in the header row are
created and populated with content.
C#

// Add the second (header) row.


table1.RowGroups[0].Rows.Add(new TableRow());
currentRow = table1.RowGroups[0].Rows[1];

// Global formatting for the header row.


currentRow.FontSize = 18;
currentRow.FontWeight = FontWeights.Bold;

// Add cells with content to the second row.


currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Product"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 1"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 2"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 3"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Quarter 4"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("TOTAL"))));

Add a row
Next, a row for data is created and added to the table, and the cells in this row are
created and populated with content. Building this row is similar to building the header
row, with slightly different formatting applied.

C#

// Add the third row.


table1.RowGroups[0].Rows.Add(new TableRow());
currentRow = table1.RowGroups[0].Rows[2];

// Global formatting for the row.


currentRow.FontSize = 12;
currentRow.FontWeight = FontWeights.Normal;

// Add cells with content to the third row.


currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Widgets"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$50,000"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$55,000"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$60,000"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$65,000"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("$230,000"))));

// Bold the first cell.


currentRow.Cells[0].FontWeight = FontWeights.Bold;

Add a footer row


Finally, a footer row is created, added, and formatted. Like the title row, the footer
contains a single cell that spans all six columns in the table.

C#

table1.RowGroups[0].Rows.Add(new TableRow());
currentRow = table1.RowGroups[0].Rows[3];

// Global formatting for the footer row.


currentRow.Background = Brushes.LightGray;
currentRow.FontSize = 18;
currentRow.FontWeight = System.Windows.FontWeights.Normal;

// Add the header row with content,


currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Projected 2004
Revenue: $810,000"))));
// and set the row to span all 6 columns.
currentRow.Cells[0].ColumnSpan = 6;

See also
Table Overview
How to: Change the FlowDirection of
Content Programmatically
Article • 02/06/2023

This example shows how to programmatically change the FlowDirection property of a


FlowDocumentReader.

Create button elements


Two Button elements are created, each representing one of the possible values of
FlowDirection. When a button is clicked, the associated property value is applied to the
contents of a FlowDocumentReader named tf1 . The property value is also written to a
TextBlock named txt1 .

XAML

<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,0,0,10">


<Button Click="LR">LeftToRight</Button>
<Button Click="RL">RightToLeft</Button>
</StackPanel>

<TextBlock Name="txt1" DockPanel.Dock="Bottom" Margin="0,50,0,0"/>

<FlowDocumentReader>
<FlowDocument FontFamily="Arial" Name="tf1">
<Paragraph>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit,
sed diam nonummy nibh euismod tincidunt ut laoreet dolore
magna aliquam erat volutpat. Ut wisi enim ad minim veniam,
quis nostrud exerci tation ullamcorper suscipit lobortis nisl
ut aliquip ex ea commodo consequat. Duis autem vel eum iriure.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed
diam nonummy nibh euismod tincidunt ut laoreet dolore magna
aliquam erat volutpat. Ut wisi enim ad minim veniam, quis
nostrud exerci tation ullamcorper suscipit lobortis nisl ut
uliquip ex ea commodo consequat. Duis autem vel eum iriure.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed
diam nonummy nibh euismod tincidunt ut laoreet dolore magna
aliquam erat volutpat. Ut wisi enim ad minim veniam, quis
nostrud exerci tation ullamcorper suscipit lobortis nisl ut
aliquip ex ea commodo consequat. Duis autem vel eum iriure.
</Paragraph>
<Paragraph>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed
diam nonummy nibh euismod tincidunt ut laoreet dolore magna
aliquam erat volutpat. Ut wisi enim ad minim veniam, quis
nostrud exerci tation ullamcorper suscipit lobortis nisl ut
aliquip ex ea commodo consequat. Duis autem vel eum iriure.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed
diam nonummy nibh euismod tincidunt ut laoreet dolore magna
aliquam erat volutpat. Ut wisi enim ad minim veniam, quis
nostrud exerci tation ullamcorper suscipit lobortis nisl ut
aliquip ex ea commodo consequat. Duis autem vel eum iriure.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed
diam nonummy nibh euismod tincidunt ut laoreet dolore magna
aliquam erat volutpat. Ut wisi enim ad minim veniam, quis
nostrud exerci tation ullamcorper suscipit lobortis nisl ut
aliquip ex ea commodo consequat. Duis autem vel eum iriure.
</Paragraph>
</FlowDocument>
</FlowDocumentReader>

C# code example
The events associated with the button clicks defined above are handled in a C# code-
behind file.

C#

private void LR(object sender, RoutedEventArgs e)


{
tf1.FlowDirection = FlowDirection.LeftToRight;
txt1.Text = "FlowDirection is now " + tf1.FlowDirection;
}
private void RL(object sender, RoutedEventArgs e)
{
tf1.FlowDirection = FlowDirection.RightToLeft;
txt1.Text = "FlowDirection is now " + tf1.FlowDirection;
}
How to: Change the TextWrapping
Property Programmatically
Article • 02/06/2023

Example
The following code example shows how to change the value of the TextWrapping
property programmatically.

Three Button elements are placed within a StackPanel element in XAML. Each Click event
for a Button corresponds with an event handler in the code. The event handlers use the
same name as the TextWrapping value they will apply to txt2 when the button is
clicked. Also, the text in txt1 (a TextBlock not shown in the XAML) is updated to reflect
the change in the property.

XAML

<StackPanel Orientation="Horizontal" Margin="0,0,0,20">


<Button Name="btn1" Background="Silver" Width="100"
Click="Wrap">Wrap</Button>
<Button Name="btn2" Background="Silver" Width="100"
Click="NoWrap">NoWrap</Button>
<Button Name="btn4" Background="Silver" Width="100"
Click="WrapWithOverflow">WrapWithOverflow</Button>
</StackPanel>

<TextBlock Name="txt2" TextWrapping="Wrap" Margin="0,0,0,20"


Foreground="Black">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Lorem ipsum
dolor sit amet,
consectetuer adipiscing elit.Lorem ipsum dolor sit aet, consectetuer
adipiscing elit.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
</TextBlock>

C#

private void Wrap(object sender, RoutedEventArgs e)


{
txt2.TextWrapping = System.Windows.TextWrapping.Wrap;
txt1.Text = "The TextWrap property is currently set to Wrap.";
}
private void NoWrap(object sender, RoutedEventArgs e)
{
txt2.TextWrapping = System.Windows.TextWrapping.NoWrap;
txt1.Text = "The TextWrap property is currently set to NoWrap.";
}
private void WrapWithOverflow(object sender, RoutedEventArgs e)
{
txt2.TextWrapping = System.Windows.TextWrapping.WrapWithOverflow;
txt1.Text = "The TextWrap property is currently set to
WrapWithOverflow.";
}

See also
TextWrapping
TextWrapping
How to: Define a Table with XAML
Article • 02/06/2023

The following example demonstrates how to define a Table using Extensible Application
Markup Language (XAML). The example table has four columns (represented by
TableColumn elements) and several rows (represented by TableRow elements)
containing data as well as title, header, and footer information. Rows must be contained
in a TableRowGroup element. Each row in the table is comprised of one or more cells
(represented by TableCell elements). Content in a table cell must be contained in a Block
element; in this case Paragraph elements are used. The table also hosts a hyperlink
(represented by the Hyperlink element) in the footer row.

Example
XAML

<FlowDocumentReader>
<FlowDocument>

<Table CellSpacing="5">

<Table.Columns>
<TableColumn/>
<TableColumn/>
<TableColumn/>
<TableColumn/>
</Table.Columns>

<TableRowGroup>

<!-- Title row for the table. -->


<TableRow Background="SkyBlue">
<TableCell ColumnSpan="4" TextAlignment="Center">
<Paragraph FontSize="24pt" FontWeight="Bold">Planetary
Information</Paragraph>
</TableCell>
</TableRow>

<!-- Header row for the table. -->


<TableRow Background="LightGoldenrodYellow">
<TableCell><Paragraph FontSize="14pt"
FontWeight="Bold">Planet</Paragraph></TableCell>
<TableCell><Paragraph FontSize="14pt" FontWeight="Bold">Mean
Distance from Sun</Paragraph></TableCell>
<TableCell><Paragraph FontSize="14pt" FontWeight="Bold">Mean
Diameter</Paragraph></TableCell>
<TableCell><Paragraph FontSize="14pt"
FontWeight="Bold">Approximate Mass</Paragraph></TableCell>
</TableRow>

<!-- Sub-title row for the inner planets. -->


<TableRow>
<TableCell ColumnSpan="4"><Paragraph FontSize="14pt"
FontWeight="Bold">The Inner Planets</Paragraph></TableCell>
</TableRow>

<!-- Four data rows for the inner planets. -->


<TableRow>
<TableCell><Paragraph>Mercury</Paragraph></TableCell>
<TableCell><Paragraph>57,910,000 km</Paragraph></TableCell>
<TableCell><Paragraph>4,880 km</Paragraph></TableCell>
<TableCell><Paragraph>3.30e23 kg</Paragraph></TableCell>
</TableRow>
<TableRow Background="lightgray">
<TableCell><Paragraph>Venus</Paragraph></TableCell>
<TableCell><Paragraph>108,200,000 km</Paragraph></TableCell>
<TableCell><Paragraph>12,103.6 km</Paragraph></TableCell>
<TableCell><Paragraph>4.869e24 kg</Paragraph></TableCell>
</TableRow>
<TableRow>
<TableCell><Paragraph>Earth</Paragraph></TableCell>
<TableCell><Paragraph>149,600,000 km</Paragraph></TableCell>
<TableCell><Paragraph>12,756.3 km</Paragraph></TableCell>
<TableCell><Paragraph>5.972e24 kg</Paragraph></TableCell>
</TableRow>
<TableRow Background="lightgray">
<TableCell><Paragraph>Mars</Paragraph></TableCell>
<TableCell><Paragraph>227,940,000 km</Paragraph></TableCell>
<TableCell><Paragraph>6,794 km</Paragraph></TableCell>
<TableCell><Paragraph>6.4219e23 kg</Paragraph></TableCell>
</TableRow>

<!-- Sub-title row for the outter planets. -->


<TableRow>
<TableCell ColumnSpan="4"><Paragraph FontSize="14pt"
FontWeight="Bold">The Major Outer Planets</Paragraph></TableCell>
</TableRow>

<!-- Four data rows for the major outter planets. -->
<TableRow>
<TableCell><Paragraph>Jupiter</Paragraph></TableCell>
<TableCell><Paragraph>778,330,000 km</Paragraph></TableCell>
<TableCell><Paragraph>142,984 km</Paragraph></TableCell>
<TableCell><Paragraph>1.900e27 kg</Paragraph></TableCell>
</TableRow>
<TableRow Background="lightgray">
<TableCell><Paragraph>Saturn</Paragraph></TableCell>
<TableCell><Paragraph>1,429,400,000 km</Paragraph></TableCell>
<TableCell><Paragraph>120,536 km</Paragraph></TableCell>
<TableCell><Paragraph>5.68e26 kg</Paragraph></TableCell>
</TableRow>
<TableRow>
<TableCell><Paragraph>Uranus</Paragraph></TableCell>
<TableCell><Paragraph>2,870,990,000 km</Paragraph></TableCell>
<TableCell><Paragraph>51,118 km</Paragraph></TableCell>
<TableCell><Paragraph>8.683e25 kg</Paragraph></TableCell>
</TableRow>
<TableRow Background="lightgray">
<TableCell><Paragraph>Neptune</Paragraph></TableCell>
<TableCell><Paragraph>4,504,000,000 km</Paragraph></TableCell>
<TableCell><Paragraph>49,532 km</Paragraph></TableCell>
<TableCell><Paragraph>1.0247e26 kg</Paragraph></TableCell>
</TableRow>

<!-- Footer row for the table. -->


<TableRow>
<TableCell ColumnSpan="4"><Paragraph FontSize="10pt"
FontStyle="Italic">
Information from the
<Hyperlink
NavigateUri="http://encarta.msn.com/encnet/refpages/artcenter.aspx">Encarta<
/Hyperlink>
web site.
</Paragraph></TableCell>
</TableRow>

</TableRowGroup>
</Table>
</FlowDocument>
</FlowDocumentReader>

The following figure shows how the table defined in this example renders:
How-to: Alter the Typography of Text
Article • 02/17/2022

The following example shows how to set the Typography attribute, using Paragraph as
the example element.

Example 1: To show how altered and default


typographic properties of text render on screen
XAML

<Paragraph
TextAlignment="Left"
FontSize="18"
FontFamily="Palatino Linotype"
Typography.NumeralStyle="OldStyle"
Typography.Fraction="Stacked"
Typography.Variants="Inferior"
>
<Run>
This text has some altered typography characteristics. Note
that use of an open type font is necessary for most typographic
properties to be effective.
</Run>
<LineBreak/><LineBreak/>
<Run>
0123456789 10 11 12 13
</Run>
<LineBreak/><LineBreak/>
<Run>
1/2 2/3 3/4
</Run>
</Paragraph>

The following figure shows how this example renders.


In contrast, the following figure shows how a similar example with default typographic
properties renders.

Example 2: To show how to set typographic


property of text programmatically
The following example shows how to set the Typography property programmatically.

C#

Paragraph par = new Paragraph();

Run runText = new Run(


"This text has some altered typography characteristics. Note" +
"that use of an open type font is necessary for most typographic" +
"properties to be effective.");
Run runNumerals = new Run("0123456789 10 11 12 13");
Run runFractions = new Run("1/2 2/3 3/4");

par.Inlines.Add(runText);
par.Inlines.Add(new LineBreak());
par.Inlines.Add(new LineBreak());
par.Inlines.Add(runNumerals);
par.Inlines.Add(new LineBreak());
par.Inlines.Add(new LineBreak());
par.Inlines.Add(runFractions);

par.TextAlignment = TextAlignment.Left;
par.FontSize = 18;
par.FontFamily = new FontFamily("Palatino Linotype");

par.Typography.NumeralStyle = FontNumeralStyle.OldStyle;
par.Typography.Fraction = FontFraction.Stacked;
par.Typography.Variants = FontVariants.Inferior;

See also
Flow Document Overview
How to: Enable Text Trimming
Article • 07/27/2022

This example demonstrates the usage and effects of the values available in the
TextTrimming enumeration.

Example
The following example defines a TextBlock element with the TextTrimming attribute set.

XAML

<TextBlock
Name="myTextBlock"
Margin="20" Background="LightGoldenrodYellow"
TextTrimming="WordEllipsis" TextWrapping="NoWrap"
FontSize="14"
>
One<LineBreak/>
two two<LineBreak/>
Three Three Three<LineBreak/>
four four four four<LineBreak/>
Five Five Five Five Five<LineBreak/>
six six six six six six<LineBreak/>
Seven Seven Seven Seven Seven Seven Seven
</TextBlock>

Setting the corresponding TextTrimming property in code is demonstrated below.

C#

myTextBlock.TextTrimming = TextTrimming.CharacterEllipsis;

There are currently three options for trimming text: CharacterEllipsis, WordEllipsis, and
None.

When TextTrimming is set to CharacterEllipsis, text is trimmed and continued with an


ellipsis at the character closest to the trimming edge. This setting tends to trim text to fit
more closely to the trimming boundary, but may result in words being partially trimmed.
The following figure shows the effect of this setting on a TextBlock similar to the one
defined above.
When TextTrimming is set to WordEllipsis, text is trimmed and continued with an ellipsis
at the end of the first full word closest to the trimming edge. This setting will not show
partially trimmed words, but tends not to trim text as closely to the trimming edge as
the CharacterEllipsis setting. The following figure shows the effect of this setting on the
TextBlock defined above.

When TextTrimming is set to None, no text trimming is performed. In this case, text is
simply cropped to the boundary of the parent text container. The following figure shows
the effect of this setting on a TextBlock similar to the one defined above.
How to: Insert an Element Into Text
Programmatically
Article • 02/06/2023

The following example shows how to use two TextPointer objects to specify a range
within text to apply a Span element to.

Example
C#

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Documents;

namespace SDKSample
{
public partial class InsertInlineIntoTextExample : Page
{
public InsertInlineIntoTextExample()
{

// Create a paragraph with a short sentence


Paragraph myParagraph = new Paragraph(new Run("Neptune has 72
times Earth's volume..."));

// Create two TextPointers that will specify the text range the
Span will cover
TextPointer myTextPointer1 =
myParagraph.ContentStart.GetPositionAtOffset(10);
TextPointer myTextPointer2 =
myParagraph.ContentEnd.GetPositionAtOffset(-5);

// Create a Span that covers the range between the two


TextPointers.
Span mySpan = new Span(myTextPointer1, myTextPointer2);
mySpan.Background = Brushes.Red;

// Create a FlowDocument with the paragraph as its initial


content.
FlowDocument myFlowDocument = new FlowDocument(myParagraph);

this.Content = myFlowDocument;
}
}
}
The illustration below shows what this example looks like.

See also
Flow Document Overview
How to: Manipulate Flow Content
Elements through the Blocks Property
Article • 02/06/2023

These examples demonstrate some of the more common operations that can be
performed on flow content elements through the Blocks property. This property is used
to add and remove items from BlockCollection. Flow content elements that feature a
Blocks property include:

Figure

Floater

ListItem

Section

TableCell

These examples happen to use Section as the flow content element, but these
techniques are applicable to all elements that host a flow content element collection.

Create a new Section


The following example creates a new Section and then uses the Add method to add a
new Paragraph to the Section contents.

C#

Section secx = new Section();


secx.Blocks.Add(new Paragraph(new Run("A bit of text content...")));

Create a new Paragraph element


The following example creates a new Paragraph element and inserts it at the beginning
of the Section.

C#

Paragraph parx = new Paragraph(new Run("Text to insert..."));


secx.Blocks.InsertBefore(secx.Blocks.FirstBlock, parx);
Get the top-level Block elements in the Section
The following example gets the number of top-level Block elements contained in the
Section.

C#

int countTopLevelBlocks = secx.Blocks.Count;

Delete the last Block element in the Section


The following example deletes the last Block element in the Section.

C#

secx.Blocks.Remove(secx.Blocks.LastBlock);

Clear all the Block element content from the


Section
The following example clears all of the contents (Block elements) from the Section.

C#

secx.Blocks.Clear();

See also
BlockCollection
InlineCollection
ListItemCollection
Flow Document Overview
Manipulate a Table's Row Groups through the RowGroups Property
Manipulate a Table's Columns through the Columns Property
Manipulate a Table's Row Groups through the RowGroups Property
How to: Manipulate Flow Content
Elements through the Inlines Property
Article • 02/06/2023

These examples demonstrate some of the more common operations that can be
performed on inline flow content elements (and containers of such elements, such as
TextBlock) through the Inlines property. This property is used to add and remove items
from InlineCollection. Flow content elements that feature an Inlines property include:

Bold

Hyperlink

Italic

Paragraph

Span

Underline

These examples happen to use Span as the flow content element, but these techniques
are applicable to all elements or controls that host an InlineCollection collection.

Create a new Span object


The following example creates a new Span object, and then uses the Add method to
add two text runs as content children of the Span.

C#

Span spanx = new Span();


spanx.Inlines.Add(new Run("A bit of text content..."));
spanx.Inlines.Add(new Run("A bit more text content..."));

Create a new Run element


The following example creates a new Run element and inserts it at the beginning of the
Span.

C#
Run runx = new Run("Text to insert...");
spanx.Inlines.InsertBefore(spanx.Inlines.FirstInline, runx);

Get the top-level Inline elements in the Span


The following example gets the number of top-level Inline elements contained in the
Span.

C#

int countTopLevelInlines = spanx.Inlines.Count;

Delete the last Inline element in the Span


The following example deletes the last Inline element in the Span.

C#

spanx.Inlines.Remove(spanx.Inlines.LastInline);

Clear all the Inline element content from the


Span
The following example clears all of the contents (Inline elements) from the Span.

C#

spanx.Inlines.Clear();

See also
BlockCollection
InlineCollection
ListItemCollection
Flow Document Overview
Manipulate a FlowDocument through the Blocks Property
Manipulate a Table's Columns through the Columns Property
Manipulate a Table's Row Groups through the RowGroups Property
How to: Manipulate a FlowDocument
through the Blocks Property
Article • 02/06/2023

These examples demonstrate some of the more common operations that can be
performed on a FlowDocument through the Blocks property.

Create a new FlowDocument


The following example creates a new FlowDocument and then appends a new
Paragraph element to the FlowDocument.

C#

FlowDocument flowDoc = new FlowDocument(new Paragraph(new Run("A bit of text


content...")));
flowDoc.Blocks.Add(new Paragraph(new Run("Text to append...")));

Create a new Paragraph element


The following example creates a new Paragraph element and inserts it at the beginning
of the FlowDocument.

C#

Paragraph p = new Paragraph(new Run("Text to insert..."));


flowDoc.Blocks.InsertBefore(flowDoc.Blocks.FirstBlock, p);

Get top-level Block elements


The following example gets the number of top-level Block elements contained in the
FlowDocument.

C#

int countTopLevelBlocks = flowDoc.Blocks.Count;

Delete the last Block element


The following example deletes the last Block element in the FlowDocument.

C#

flowDoc.Blocks.Remove(flowDoc.Blocks.LastBlock);

Clear all the Block contents


The following example clears all of the contents (Block elements) from the
FlowDocument.

C#

flowDoc.Blocks.Clear();

See also
Manipulate a Table's Row Groups through the RowGroups Property
Manipulate a Table's Columns through the Columns Property
Manipulate a Table's Row Groups through the RowGroups Property
How to: Manipulate a Table's Columns
through the Columns Property
Article • 02/06/2023

This example demonstrates some of the more common operations that can be
performed on a table's columns through the Columns property.

Create a new table


The following example creates a new table and then uses the Add method to add
columns to the table's Columns collection.

C#

Table tbl = new Table();


int columnsToAdd = 4;
for (int x = 0; x < columnsToAdd; x++)
tbl.Columns.Add(new TableColumn());

Insert a new TableColumn


The following example inserts a new TableColumn. The new column is inserted at index
position 0, making it the new first column in the table.

7 Note

The TableColumnCollection collection uses standard zero-based indexing.

C#

tbl.Columns.Insert(0, new TableColumn());

Access properties in the TableColumnCollection


The following example accesses some arbitrary properties on columns in the
TableColumnCollection collection, referring to particular columns by index.

C#
tbl.Columns[0].Width = new GridLength(20);
tbl.Columns[1].Background = Brushes.AliceBlue;
tbl.Columns[2].Width = new GridLength(20);
tbl.Columns[3].Background = Brushes.AliceBlue;

Get the number of columns in a table


The following example gets the number of columns currently hosted by the table.

C#

int columns = tbl.Columns.Count;

Remove a column by reference


The following example removes a particular column by reference.

C#

tbl.Columns.Remove(tbl.Columns[3]);

Remove a column by index


The following example removes a particular column by index.

C#

tbl.Columns.RemoveAt(2);

Remove all the columns


The following example removes all columns from the table's columns collection.

C#

tbl.Columns.Clear();

See also
Table Overview
Define a Table with XAML
Build a Table Programmatically
Manipulate a Table's Row Groups through the RowGroups Property
Manipulate a FlowDocument through the Blocks Property
Manipulate a Table's Row Groups through the RowGroups Property
How to: Manipulate a Table's Row
Groups through the RowGroups
Property
Article • 02/06/2023

This example demonstrates some of the more common operations that can be
performed on a table's row groups through the RowGroups property.

Create a new table using Add method


The following example creates a new table and then uses the Add method to add
columns to the table's RowGroups collection.

C#

Table tbl = new Table();


int rowGroupsToAdd = 4;
for (int x = 0; x < rowGroupsToAdd; x++)
tbl.RowGroups.Add(new TableRowGroup());

Inserts a new TableRowGroup


The following example inserts a new TableRowGroup. The new column is inserted at
index position 0, making it the new first row group in the table.

7 Note

The TableRowGroupCollection collection uses standard zero-based indexing.

C#

tbl.RowGroups.Insert(0, new TableRowGroup());

Add rows to the TableRowGroup


The following example adds several rows to a particular TableRowGroup (specified by
index) in the table.
C#

int rowsToAdd = 10;


for (int x = 0; x < rowsToAdd; x++)
tbl.RowGroups[0].Rows.Add(new TableRow());

Access row properties in the first row group


The following example accesses some arbitrary properties on rows in the first row group
in the table.

C#

// Alias the working TableRowGroup for ease in referencing.


TableRowGroup trg = tbl.RowGroups[0];
trg.Rows[0].Background = Brushes.CornflowerBlue;
trg.Rows[1].FontSize = 24;
trg.Rows[2].ToolTip = "This row's tooltip";

Add cells to a TableRow


The following example adds several cells to a particular TableRow (specified by index) in
the table.

C#

int cellsToAdd = 10;


for (int x = 0; x < cellsToAdd; x++)
tbl.RowGroups[0].Rows[0].Cells.Add(new TableCell(new Paragraph(new
Run("Cell " + (x + 1)))));

Access methods and properties on cells in the


first row group
The following example access some arbitrary methods and properties on cells in the first
row in the first row group.

C#

// Alias the working for for ease in referencing.


TableRow row = tbl.RowGroups[0].Rows[0];
row.Cells[0].Background = Brushes.PapayaWhip;
row.Cells[1].FontStyle = FontStyles.Italic;
// This call clears all of the content from this cell.
row.Cells[2].Blocks.Clear();

Get the number of TableRowGroup elements in


a table
The following example returns the number of TableRowGroup elements hosted by the
table.

C#

int rowGroups = tbl.RowGroups.Count;

Remove a row group by reference


The following example removes a particular row group by reference.

C#

tbl.RowGroups.Remove(tbl.RowGroups[0]);

Remove a row group by index


The following example removes a particular row group by index.

C#

tbl.RowGroups.RemoveAt(0);

Remove all row groups from the table's row


groups collection
The following example removes all row groups from the table's row groups collection.

C#

tbl.RowGroups.Clear();
See also
How-to: Manipulate Flow Content Elements through the Inlines Property
Manipulate a FlowDocument through the Blocks Property
Manipulate a Table's Columns through the Columns Property
How to: Use Flow Content Elements
Article • 02/06/2023

The following example demonstrates declarative usage for various flow content
elements and associated attributes. Elements and attributes demonstrated include:

Bold element

BreakPageBefore attribute

FontSize attribute

Italic element

LineBreak element

List element

ListItem element

Paragraph element

Run element

Section element

Span element

Variants attribute (superscript and subscript)

Underline element

Example
XAML

<FlowDocument
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Paragraph FontSize="18">Flow Format Example</Paragraph>

<Paragraph>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam
nonummy
nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
Ut wisi
enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit
lobortis
nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure.
</Paragraph>
<Paragraph>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam
nonummy nibh
euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut
wisi enim
ad minim veniam, quis nostrud exerci tation ullamcorper suscipit
lobortis nisl
ut aliquip ex ea commodo consequat. Duis autem vel eum iriure.
</Paragraph>

<Paragraph FontSize="18">More flow elements</Paragraph>


<Paragraph FontSize="15">Inline, font type and weight, and a
List</Paragraph>

<List>
<ListItem><Paragraph>ListItem 1</Paragraph></ListItem>
<ListItem><Paragraph>ListItem 2</Paragraph></ListItem>
<ListItem><Paragraph>ListItem 3</Paragraph></ListItem>
<ListItem><Paragraph>ListItem 4</Paragraph></ListItem>
<ListItem><Paragraph>ListItem 5</Paragraph></ListItem>
</List>

<Paragraph><Bold>Bolded</Bold></Paragraph>
<Paragraph><Underline>Underlined</Underline></Paragraph>
<Paragraph><Bold><Underline>Bolded and Underlined</Underline></Bold>
</Paragraph>
<Paragraph><Italic>Italic</Italic></Paragraph>

<Paragraph><Span>The Span element, no inherent rendering</Span>


</Paragraph>
<Paragraph><Run>The Run element, no inherent rendering</Run></Paragraph>

<Paragraph FontSize="15">Subscript, Superscript</Paragraph>

<Paragraph>
<Run Typography.Variants="Superscript">This text is Superscripted.
</Run> This text isn't.
</Paragraph>
<Paragraph>
<Run Typography.Variants="Subscript">This text is Subscripted.</Run>
This text isn't.
</Paragraph>
<Paragraph>
If a font does not support a particular form (such as Superscript) a
default font form will be displayed.
</Paragraph>

<Paragraph FontSize="15">Blocks, breaks, paragraph</Paragraph>

<Section><Paragraph>A block section of text</Paragraph></Section>


<Section><Paragraph>Another block section of text</Paragraph></Section>
<Paragraph><LineBreak/></Paragraph>
<Section><Paragraph>... and another section, preceded by a
LineBreak</Paragraph></Section>

<Section BreakPageBefore="True"/>
<Section><Paragraph>... and another section, preceded by a
PageBreak</Paragraph></Section>

<Paragraph>Finally, a paragraph. Note the break between this paragraph


...</Paragraph>
<Paragraph TextIndent="25">... and this paragraph, and also the left
indention.</Paragraph>

<Paragraph><LineBreak/></Paragraph>

</FlowDocument>
How to: Use FlowDocument Column-
Separating Attributes
Article • 02/06/2023

This example shows how to use the column-separating features of a FlowDocument.

Example
The following example defines a FlowDocument, and sets the ColumnGap,
ColumnRuleBrush, and ColumnRuleWidth attributes. The FlowDocument contains a
single paragraph of sample content.

XAML

<FlowDocumentReader>
<FlowDocument
ColumnGap="20.0"
ColumnRuleBrush="DodgerBlue"
ColumnRuleWidth="5.0"
ColumnWidth="140.0"
>
<Paragraph Background="AntiqueWhite" TextAlignment="Left">
This paragraph has the background set to antique white to make its
boundaries obvious.

The column gap is the space between columns; this FlowDocument will
have a column gap of 20 device-independend pixels. The column rule
is a vertical line drawn in the column gap, and is used to visually
separate columns; this FlowDocument a Dodger-blue column rule that
is 5 pixels wide.

The column rule and column gap both take space between columns. In
this case, a column gap width of 20 plus a column rule of width of 5
results in the space between columns being 25 pixels wide, 5 pixels
for the column rule, and 10 pixels of column gap on either side of the
column rule.
</Paragraph>
</FlowDocument>
</FlowDocumentReader>

The following figure shows the effects of the ColumnGap, ColumnRuleBrush, and
ColumnRuleWidth attributes in a rendered FlowDocument.
Typography
Article • 08/10/2023

Windows Presentation Foundation (WPF) includes support for rich presentation of text
content. Text in WPF is rendered using Microsoft ClearType, which enhances the clarity
and readability of text. WPF also supports OpenType fonts, which provide additional
capabilities beyond those defined by the TrueType® format.

In This Section
Typography in WPF
ClearType Overview
ClearType Registry Settings
Drawing Formatted Text
Advanced Text Formatting
Fonts
Glyphs
How-to Topics

See also
Typography
Documents in WPF
OpenType Font Features
Optimizing WPF Application Performance
Typography in WPF
Article • 08/10/2023

This topic introduces the major typographic features of WPF. These features include
improved quality and performance of text rendering, OpenType typography support,
enhanced international text, enhanced font support, and new text application
programming interfaces (APIs).

Improved Quality and Performance of Text


Text in WPF is rendered using Microsoft ClearType, which enhances the clarity and
readability of text. ClearType is a software technology developed by Microsoft that
improves the readability of text on existing LCDs (Liquid Crystal Displays), such as laptop
screens, Pocket PC screens and flat panel monitors. ClearType uses sub-pixel rendering
which allows text to be displayed with a greater fidelity to its true shape by aligning
characters on a fractional part of a pixel. The extra resolution increases the sharpness of
the tiny details in text display, making it much easier to read over long durations.
Another improvement of ClearType in WPF is y-direction anti-aliasing, which smoothes
the tops and bottoms of shallow curves in text characters. For more details on ClearType
features, see ClearType Overview.

Text with ClearType y-direction antialiasing

The entire text rendering pipeline can be hardware-accelerated in WPF provided your
machine meets the minimum level of hardware required. Rendering that cannot be
performed using hardware falls back to software rendering. Hardware-acceleration
affects all phases of the text rendering pipeline—from storing individual glyphs,
compositing glyphs into glyph runs, applying effects, to applying the ClearType
blending algorithm to the final displayed output. For more information on hardware
acceleration, see Graphics Rendering Tiers.
In addition, animated text, whether by character or glyph, takes full advantage of the
graphics hardware capability enabled by WPF. This results in smooth text animation.

Rich Typography
The OpenType font format is an extension of the TrueType® font format. The OpenType
font format was developed jointly by Microsoft and Adobe, and provides a rich
assortment of advanced typographic features. The Typography object exposes many of
the advanced features of OpenType fonts, such as stylistic alternates and swashes. The
Windows SDK provides a set of sample OpenType fonts that are designed with rich
features, such as the Pericles and Pescadero fonts. For more information, see Sample
OpenType Font Pack.

The Pericles OpenType font contains additional glyphs that provide stylistic alternates to
the standard set of glyphs. The following text displays stylistic alternate glyphs.

Swashes are decorative glyphs that use elaborate ornamentation often associated with
calligraphy. The following text displays standard and swash glyphs for the Pescadero
font.

For more details on OpenType features, see OpenType Font Features.


Enhanced International Text Support
WPF provides enhanced international text support by providing the following features:

Automatic line-spacing in all writing systems, using adaptive measurement.

Broad support for international text. For more information, see Globalization for
WPF.

Language-guided line breaking, hyphenation, and justification.

Enhanced Font Support


WPF provides enhanced font support by providing the following features:

Unicode for all text. Font behavior and selection no longer require charset or
codepage.

Font behavior independent of global settings, such as system locale.

Separate FontWeight, FontStretch, and FontStyle types for defining a FontFamily.


This provides greater flexibility than in Win32 programming, in which Boolean
combinations of italic and bold are used to define a font family.

Writing direction (horizontal versus vertical) handled independent of font name.

Font linking and font fallback in a portable XML file, using composite font
technology. Composite fonts allow for the construction of full range multilingual
fonts. Composite fonts also provide a mechanism that avoids displaying missing
glyphs. For more information, see the remarks in the FontFamily class.

International fonts built from composite fonts, using a group of single-language


fonts. This saves on resource costs when developing fonts for multiple languages.

Composite fonts embedded in a document, thereby providing document


portability. For more information, see the remarks in the FontFamily class.

New Text Application Programming Interfaces


(APIs)
WPF provides several text APIs for developers to use when including text in their
applications. These APIs are grouped into three categories:
Layout and user interface. The common text controls for the graphical user
interface (GUI).

Lightweight text drawing. Allows you to draw text directly to objects.

Advanced text formatting. Allows you to implement a custom text engine.

Layout and User Interface


At the highest level of functionality, the text APIs provide common UI controls such as
Label, TextBlock, and TextBox. These controls provide the basic UI elements within an
application, and offer an easy way to present and interact with text. Controls such as
RichTextBox and PasswordBox enable more advanced or specialized text-handling. And
classes such as TextRange, TextSelection, and TextPointer enable useful text
manipulation. These UI controls provide properties such as FontFamily, FontSize, and
FontStyle, which enable you to control the font that is used to render the text.

Using Bitmap Effects, Transforms, and Text Effects

WPF allows you to create visually interesting uses of text by uses features such as
bitmap effects, transforms, and text effects. The following example shows a typical type
of a drop shadow effect applied to text.

The following example shows a drop shadow effect and noise applied to text.

The following example shows an outer glow effect applied to text.

The following example shows a blur effect applied to text.


The following example shows the second line of text scaled by 150% along the x-axis,
and the third line of text scaled by 150% along the y-axis.

The following example shows text skewed along the x-axis.

A TextEffect object is a helper object that allows you to treat text as one or more groups
of characters in a text string. The following example shows an individual character being
rotated. Each character is rotated independently at 1-second intervals.

Using Flow Documents

In addition to the common UI controls, WPF offers a layout control for text presentation
—the FlowDocument element. The FlowDocument element, in conjunction with the
DocumentViewer element, provides a control for large amounts of text with varying
layout requirements. Layout controls provide access to advanced typography through
the Typography object and font-related properties of other UI controls.

The following example shows text content hosted in a FlowDocumentReader, which


provides search, navigation, pagination, and content scaling support.
For more information, see Documents in WPF.

Lightweight Text Drawing


You can draw text directly to WPF objects by using the DrawText method of the
DrawingContext object. To use this method, you create a FormattedText object. This
object allows you to draw multi-line text, in which each character in the text can be
individually formatted. The functionality of the FormattedText object contains much of
the functionality of the DrawText flags in the Windows API. In addition, the
FormattedText object contains functionality such as ellipsis support, in which an ellipsis
is displayed when text exceeds its bounds. The following example shows text that has
several formats applied to it, including a linear gradient on the second and third words.

You can convert formatted text into Geometry objects, allowing you to create other
types of visually interesting text. For example, you could create a Geometry object based
on the outline of a text string.
The following examples illustrate several ways of creating interesting visual effects by
modifying the stroke, fill, and highlight of converted text.

For more information on the FormattedText object, see Drawing Formatted Text.

Advanced Text Formatting


At the most advanced level of the text APIs, WPF offers you the ability to create custom
text layout by using the TextFormatter object and other types in the
System.Windows.Media.TextFormatting namespace. The TextFormatter and associated
classes allow you to implement custom text layout that supports your own definition of
character formats, paragraph styles, line breaking rules, and other layout features for
international text. There are very few cases in which you would want to override the
default implementation of the WPF text layout support. However, if you were creating a
text editing control or application, you might require a different implementation than
the default WPF implementation.

Unlike a traditional text API, the TextFormatter interacts with a text layout client through
a set of callback methods. It requires the client to provide these methods in an
implementation of the TextSource class. The following diagram illustrates the text layout
interaction between the client application and TextFormatter.
For more details on creating custom text layout, see Advanced Text Formatting.

See also
FormattedText
TextFormatter
ClearType Overview
OpenType Font Features
Drawing Formatted Text
Advanced Text Formatting
Text
Microsoft Typography
ClearType overview
Article • 06/02/2023

This article provides an overview of the Microsoft ClearType technology found in


Windows Presentation Foundation (WPF).

Technology Overview
ClearType is a software technology developed by Microsoft that improves the readability
of text on existing LCDs (Liquid Crystal Displays), such as laptop screens, Pocket PC
screens, and flat panel monitors. ClearType works by accessing the individual vertical
color stripe elements in every pixel of an LCD screen. Before ClearType, the smallest level
of detail that a computer could display was a single pixel, but with ClearType running on
an LCD monitor, it can display features of text as small as a fraction of a pixel in width.
The extra resolution increases the sharpness of the tiny details in text display, making it
much easier to read over long durations.

The ClearType available in Windows Presentation Foundation (WPF) is the latest


generation of ClearType, which has several improvements over the version found in
Microsoft Windows Graphics Device Interface (GDI).

Sub-pixel Positioning
A significant improvement over the previous version of ClearType is the use of sub-pixel
positioning. Unlike the ClearType implementation found in GDI, the ClearType found in
Windows Presentation Foundation (WPF) allows glyphs to start within the pixel and not
just the beginning boundary of the pixel. Because of this extra resolution in positioning
glyphs, the spacing and proportions of the glyphs is more precise and consistent.

The following two examples show how glyphs may begin on any sub-pixel boundary
when sub-pixel positioning is used. The example on the left is rendered using the earlier
version of the ClearType renderer, which did not employ sub-pixel positioning. The
example on the right is rendered using the new version of the ClearType renderer, using
sub-pixel positioning. Note how each e and l in the right-hand image is rendered
slightly differently because each starts on a different sub-pixel. When viewing the text at
its normal size on the screen, this difference is not noticeable because of the high
contrast of the glyph image. This is only possible because of sophisticated color filtering
that is incorporated in ClearType.
Text displayed with earlier and later versions
of ClearType

The following two examples compare output from the earlier ClearType renderer with
the new version of the ClearType renderer. The subpixel positioning, shown on the right,
greatly improves the spacing of type on screen, especially at small sizes where the
difference between a sub-pixel and a whole pixel represents a significant proportion of
glyph width. Note that spacing between the letters is more even in the second image.
The cumulative benefit of sub-pixel positioning to the overall appearance of a screen of
text is greatly increased, and represents a significant evolution in ClearType technology.
Text with earlier and later versions of
ClearType

Y-Direction Antialiasing
Another improvement of ClearType in Windows Presentation Foundation (WPF) is y-
direction anti-aliasing. The ClearType in GDI without y-direction anti-aliasing provides
better resolution on the x-axis but not the y-axis. On the tops and bottoms of shallow
curves, the jagged edges detract from its readability.

The following example shows the effect of having no y-direction antialiasing. In this
case, the jagged edges on the top and bottom of the letter are apparent.
Text with jagged edges on
shallow curves

ClearType in Windows Presentation Foundation (WPF) provides antialiasing on the y-


direction level to smooth out any jagged edges. This is particularly important for
improving the readability of East Asian languages where ideographs have an almost
equal amount of horizontal and vertical shallow curves.

The following example shows the effect of y-direction antialiasing. In this case, the top
and bottom of the letter show a smooth curve.

Text with ClearType y-


direction antialiasing

Hardware Acceleration
ClearType in Windows Presentation Foundation (WPF) can take advantage of hardware
acceleration for better performance and to reduce CPU load and system memory
requirements. By using the pixel shaders and video memory of a graphics card,
ClearType provides faster rendering of text, particularly when animation is used.

ClearType in Windows Presentation Foundation (WPF) does not modify the system-wide
ClearType settings. Disabling ClearType in Windows sets Windows Presentation
Foundation (WPF) antialiasing to grayscale mode.

One of the Windows Presentation Foundation (WPF) architectural design decisions is to


have resolution-independent layout better support higher resolution DPI monitors. This
has the consequence of Windows Presentation Foundation (WPF) not supporting aliased
text rendering or the bitmaps in some East Asian fonts, because they're both resolution
dependent.

See also
ClearType Registry Settings
ClearType Registry Settings
Article • 02/06/2023

This topic provides an overview of the Microsoft ClearType registry settings that are
used by WPF applications.

Technology Overview
WPF applications that render text to a display device use ClearType features to provide
an enhanced reading experience. ClearType is a software technology developed by
Microsoft that improves the readability of text on existing LCDs (Liquid Crystal Displays),
such as laptop screens, Pocket PC screens and flat panel monitors. ClearType works by
accessing the individual vertical color stripe elements in every pixel of an LCD screen. For
more information on ClearType, see ClearType Overview.

Text that is rendered with ClearType can appear significantly different when viewed on
various display devices. For example, a small number of monitors implement the color
stripe elements in blue, green, red order rather than the more common red, green, blue
(RGB) order.

Text that is rendered with ClearType can also appear significantly different when viewed
by individuals with varying levels of color sensitivity. Some individuals can detect slight
differences in color better than others.

In each of these cases, ClearType features need to be modified in order to provide the
best reading experience for each individual.

Registry Settings
WPF specifies four registry settings for controlling ClearType features:

Setting Description

ClearType level Describes the level of ClearType color clarity.

Gamma level Describes the level of the pixel color component for a display device.

Pixel structure Describes the arrangement of pixels for a display device.

Text contrast level Describes the level of contrast for displayed text.
These settings can be accessed by an external configuration utility that knows how to
reference the identified WPF ClearType registry settings. These settings can also be
created or modified by accessing the values directly by using the Windows Registry
Editor.

If the WPF ClearType registry settings are not set (which is the default state), the WPF
application queries the Windows system parameters information for font smoothing
settings.

7 Note

For information on enumerating display device names, see the


SystemParametersInfo Win32 function.

ClearType Level
The ClearType level allows you to adjust the rendering of text based on the color
sensitivity and perception of an individual. For some individuals, the rendering of text
that uses ClearType at its highest level does not produce the best reading experience.

The ClearType level is an integer value that ranges from 0 to 100. The default level is
100, which means ClearType uses the maximum capability of the color stripe elements of
the display device. However, a ClearType level of 0 renders text as gray scale. By setting
the ClearType level somewhere between 0 and 100, you can create an intermediate level
that is suitable to an individual's color sensitivity.

Registry Setting
The registry setting location for the ClearType level is an individual user setting that
corresponds to a specific display device name:

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Avalon.Graphics\<displayName>

For each display device name for a user, a ClearTypeLevel DWORD value is defined. The
following screenshot shows the Registry Editor setting for the ClearType level.
7 Note

WPF applications render text in one of either two modes, with and without
ClearType. When text is rendered without ClearType, it is referred to as gray scale
rendering.

Gamma Level
The gamma level refers to the nonlinear relationship between a pixel value and
luminance. The gamma level setting should correspond to the physical characteristics of
the display device; otherwise, distortions in rendered output may occur. For example,
text may appear too wide or too narrow, or color fringes may appear on the edges of
vertical stems of glyphs.

The gamma level is an integer value that ranges from 1000 to 2200. The default level is
1900.

Registry Setting
The registry setting location for the gamma level is a local machine setting that
corresponds to a specific display device name:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Avalon.Graphics\<displayName>

For each display device name for a user, a GammaLevel DWORD value is defined. The
following screenshot shows the Registry Editor setting for the gamma level.
Pixel Structure
The pixel structure describes the type of pixels that make up a display device. The pixel
structure is defined as one of three types:

Type Value Description

Flat 0 The display device has no pixel structure. This means that light sources for each
color are spread equally on the pixel area—this is referred to as gray scale
rendering. This is how a standard display device works. ClearType is never applied
to the rendered text.

RGB 1 The display device has pixels that consist of three stripes in the following order:
red, green, and blue. ClearType is applied to the rendered text.

BGR 2 The display device has pixels that consist of three stripes in the following order:
blue, green, and red. ClearType is applied to the rendered text. Notice how the
order is inverted from the RGB type.

The pixel structure corresponds to an integer value that ranges from 0 to 2. The default
level is 0, which represents a flat pixel structure.

7 Note

For information on enumerating display device names, see the


EnumDisplayDevices Win32 function.

Registry Setting
The registry setting location for the pixel structure is a local machine setting that
corresponds to a specific display device name:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Avalon.Graphics\<displayName>
For each display device name for a user, a PixelStructure DWORD value is defined. The
following screenshot shows the Registry Editor setting for the pixel structure.

Text Contrast Level


The text contrast level allows you to adjust the rendering of text based on the stem
widths of glyphs. The text contrast level is an integer value that ranges from 0 to 6—the
larger the integer value, the wider the stem. The default level is 1.

Registry Setting
The registry setting location for the text contrast level is an individual user setting that
corresponds to a specific display device name:

HKEY_CURRENT_USER\Software\Microsoft\Avalon.Graphics\<displayName>

For each display device name for a user, a TextContrastLevel DWORD value is defined.
The following screenshot shows the Registry Editor setting for the text contrast level.

See also
ClearType Overview
ClearType Antialiasing
Drawing Formatted Text
Article • 08/04/2022

This topic provides an overview of the features of the FormattedText object. This object
provides low-level control for drawing text in Windows Presentation Foundation (WPF)
applications.

Technology Overview
The FormattedText object allows you to draw multi-line text, in which each character in
the text can be individually formatted. The following example shows text that has several
formats applied to it.

7 Note

For those developers migrating from the Win32 API, the table in the Win32
Migration section lists the Win32 DrawText flags and the approximate equivalent in
Windows Presentation Foundation (WPF).

Reasons for Using Formatted Text


WPF includes multiple controls for drawing text to the screen. Each control is targeted to
a different scenario and has its own list of features and limitations. In general, the
TextBlock element should be used when limited text support is required, such as a brief
sentence in a user interface (UI). Label can be used when minimal text support is
required. For more information, see Documents in WPF.

The FormattedText object provides greater text formatting features than Windows
Presentation Foundation (WPF) text controls, and can be useful in cases where you want
to use text as a decorative element. For more information, see the following section
Converting Formatted Text to a Geometry.

In addition, the FormattedText object is useful for creating text-oriented DrawingVisual-


derived objects. DrawingVisual is a lightweight drawing class that is used to render
shapes, images, or text. For more information, see Hit Test Using DrawingVisuals
Sample .

Using the FormattedText Object


To create formatted text, call the FormattedText constructor to create a FormattedText
object. Once you have created the initial formatted text string, you can apply a range of
formatting styles.

Use the MaxTextWidth property to constrain the text to a specific width. The text will
automatically wrap to avoid exceeding the specified width. Use the MaxTextHeight
property to constrain the text to a specific height. The text will display an ellipsis, "…" for
the text that exceeds the specified height.

You can apply multiple formatting styles to one or more characters. For example, you
could call both the SetFontSize and SetForegroundBrush methods to change the
formatting of the first five characters in the text.

The following code example creates a FormattedText object and then applies several
formatting styles to the text.

C#

protected override void OnRender(DrawingContext drawingContext)


{
string testString = "Lorem ipsum dolor sit amet, consectetur adipisicing
elit, sed do eiusmod tempor";

// Create the initial formatted text string.


FormattedText formattedText = new FormattedText(
testString,
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Verdana"),
32,
Brushes.Black);
// Set a maximum width and height. If the text overflows these values,
an ellipsis "..." appears.
formattedText.MaxTextWidth = 300;
formattedText.MaxTextHeight = 240;

// Use a larger font size beginning at the first (zero-based) character


and continuing for 5 characters.
// The font size is calculated in terms of points -- not as device-
independent pixels.
formattedText.SetFontSize(36 * (96.0 / 72.0), 0, 5);

// Use a Bold font weight beginning at the 6th character and continuing
for 11 characters.
formattedText.SetFontWeight(FontWeights.Bold, 6, 11);

// Use a linear gradient brush beginning at the 6th character and


continuing for 11 characters.
formattedText.SetForegroundBrush(
new LinearGradientBrush(
Colors.Orange,
Colors.Teal,
90.0),
6, 11);

// Use an Italic font style beginning at the 28th character and


continuing for 28 characters.
formattedText.SetFontStyle(FontStyles.Italic, 28, 28);

// Draw the formatted text string to the DrawingContext of the control.


drawingContext.DrawText(formattedText, new Point(10, 0));
}

Font Size Unit of Measure


As with other text objects in Windows Presentation Foundation (WPF) applications, the
FormattedText object uses device-independent pixels as the unit of measure. However,
most Win32 applications use points as the unit of measure. If you want to use display
text in units of points in Windows Presentation Foundation (WPF) applications, you need
to convert device-independent units (1/96th inch per unit) to points. The following code
example shows how to perform this conversion.

C#

// The font size is calculated in terms of points -- not as device-


independent pixels.
formattedText.SetFontSize(36 * (96.0 / 72.0), 0, 5);
Converting Formatted Text to a Geometry
You can convert formatted text into Geometry objects, allowing you to create other
types of visually interesting text. For example, you could create a Geometry object based
on the outline of a text string.

The following examples illustrate several ways of creating interesting visual effects by
modifying the stroke, fill, and highlight of converted text.

When text is converted to a Geometry object, it is no longer a collection of characters—


you cannot modify the characters in the text string. However, you can affect the
appearance of the converted text by modifying its stroke and fill properties. The stroke
refers to the outline of the converted text; the fill refers to the area inside the outline of
the converted text. For more information, see Create Outlined Text.

You can also convert formatted text to a PathGeometry object, and use the object for
highlighting the text. For example, you could apply an animation to the PathGeometry
object so that the animation follows the outline of the formatted text.

The following example shows formatted text that has been converted to a
PathGeometry object. An animated ellipse follows the path of the strokes of the
rendered text.

Sphere following the path geometry of text


For more information, see How to: Create a PathGeometry Animation for Text.

You can create other interesting uses for formatted text once it has been converted to a
PathGeometry object. For example, you can clip video to display inside it.

Win32 Migration
The features of FormattedText for drawing text are similar to the features of the Win32
DrawText function. For those developers migrating from the Win32 API, the following
table lists the Win32 DrawText flags and the approximate equivalent in Windows
Presentation Foundation (WPF).

DrawText flag WPF Notes


equivalent

DT_BOTTOM Height Use the Height property to compute an


appropriate Win32 DrawText 'y' position.

DT_CALCRECT Height, Width Use the Height and Width properties to


calculate the output rectangle.

DT_CENTER TextAlignment Use the TextAlignment property with the value


set to Center.

DT_EDITCONTROL None Not required. Space width and last line


rendering are the same as in the framework
edit control.
DrawText flag WPF Notes
equivalent

DT_END_ELLIPSIS Trimming Use the Trimming property with the value


CharacterEllipsis.

Use WordEllipsis to get Win32


DT_END_ELLIPSIS with DT_WORD_ELIPSIS end
ellipsis—in this case, character ellipsis only
occurs on words that do not fit on a single line.

DT_EXPAND_TABS None Not required. Tabs are automatically expanded


to stops every 4 ems, which is approximately
the width of 8 language-independent
characters.

DT_EXTERNALLEADING None Not required. External leading is always


included in line spacing. Use the LineHeight
property to create user-defined line spacing.

DT_HIDEPREFIX None Not supported. Remove the '&' from the string
before constructing the FormattedText object.

DT_LEFT TextAlignment This is the default text alignment. Use the


TextAlignment property with the value set to
Left. (WPF only)

DT_MODIFYSTRING None Not supported.

DT_NOCLIP VisualClip Clipping does not happen automatically. If you


want to clip text, use the VisualClip property.

DT_NOFULLWIDTHCHARBREAK None Not supported.

DT_NOPREFIX None Not required. The '&' character in strings is


always treated as a normal character.

DT_PATHELLIPSIS None Use the Trimming property with the value


WordEllipsis.

DT_PREFIX None Not supported. If you want to use underscores


for text, such as an accelerator key or link, use
the SetTextDecorations method.

DT_PREFIXONLY None Not supported.

DT_RIGHT TextAlignment Use the TextAlignment property with the value


set to Right. (WPF only)

DT_RTLREADING FlowDirection Set the FlowDirection property to RightToLeft.


DrawText flag WPF Notes
equivalent

DT_SINGLELINE None Not required. FormattedText objects behave as


a single line control, unless either the
MaxTextWidth property is set or the text
contains a carriage return/line feed (CR/LF).

DT_TABSTOP None No support for user-defined tab stop positions.

DT_TOP Height Not required. Top justification is the default.


Other vertical positioning values can be
defined by using the Height property to
compute an appropriate Win32 DrawText 'y'
position.

DT_VCENTER Height Use the Height property to compute an


appropriate Win32 DrawText 'y' position.

DT_WORDBREAK None Not required. Word breaking happens


automatically with FormattedText objects. You
cannot disable it.

DT_WORD_ELLIPSIS Trimming Use the Trimming property with the value


WordEllipsis.

See also
FormattedText
Documents in WPF
Typography in WPF
Create Outlined Text
How to: Create a PathGeometry Animation for Text
Advanced Text Formatting
Article • 02/06/2023

Windows Presentation Foundation (WPF) provides a robust set of APIs for including text
in your application. Layout and user interface (UI) APIs, such as TextBlock, provide the
most common and general-use elements for text presentation. Drawing APIs, such as
GlyphRunDrawing and FormattedText, provide a means for including formatted text in
drawings. At the most advanced level, WPF provides an extensible text formatting
engine to control every aspect of text presentation, such as text store management, text
run formatting management, and embedded object management.

This topic provides an introduction to WPF text formatting. It focuses on client


implementation and use of the WPF text formatting engine.

7 Note

All code examples within this document can be found in the Advanced Text
Formatting Sample .

Prerequisites
This topic assumes that you are familiar with the higher level APIs used for text
presentation. Most user scenarios will not require the advanced text formatting APIs
discussed in this topic. For an introduction to the different text APIs, see Documents in
WPF.

Advanced Text Formatting


The text layout and UI controls in WPF provide formatting properties that allow you to
easily include formatted text in your application. These controls expose a number of
properties to handle the presentation of text, which includes its typeface, size, and color.
Under ordinary circumstances, these controls can handle the majority of text
presentation in your application. However, some advanced scenarios require the control
of text storage as well as text presentation. WPF provides an extensible text formatting
engine for this purpose.

The advanced text formatting features found in WPF consist of a text formatting engine,
a text store, text runs, and formatting properties. The text formatting engine,
TextFormatter, creates lines of text to be used for presentation. This is achieved by
initiating the line formatting process and calling the text formatter's FormatLine. The
text formatter retrieves text runs from your text store by calling the store's GetTextRun
method. The TextRun objects are then formed into TextLine objects by the text formatter
and given to your application for inspection or display.

Using the Text Formatter


TextFormatter is the WPF text formatting engine and provides services for formatting
and breaking text lines. The text formatter can handle different text character formats
and paragraph styles, and includes support for international text layout.

Unlike a traditional text API, the TextFormatter interacts with a text layout client through
a set of callback methods. It requires the client to provide these methods in an
implementation of the TextSource class. The following diagram illustrates the text layout
interaction between the client application and TextFormatter.

The text formatter is used to retrieve formatted text lines from the text store, which is an
implementation of TextSource. This is done by first creating an instance of the text
formatter by using the Create method. This method creates an instance of the text
formatter and sets the maximum line height and width values. As soon as an instance of
the text formatter is created, the line creation process is started by calling the
FormatLine method. TextFormatter calls back to the text source to retrieve the text and
formatting parameters for the runs of text that form a line.

In the following example, the process of formatting a text store is shown. The
TextFormatter object is used to retrieve text lines from the text store and then format
the text line for drawing into the DrawingContext.
C#

// Create a DrawingGroup object for storing formatted text.


textDest = new DrawingGroup();
DrawingContext dc = textDest.Open();

// Update the text store.


_textStore.Text = textToFormat.Text;
_textStore.FontRendering = _currentRendering;

// Create a TextFormatter object.


TextFormatter formatter = TextFormatter.Create();

// Format each line of text from the text store and draw it.
while (textStorePosition < _textStore.Text.Length)
{
// Create a textline from the text store using the TextFormatter object.
using (TextLine myTextLine = formatter.FormatLine(
_textStore,
textStorePosition,
96*6,
new GenericTextParagraphProperties(_currentRendering),
null))
{
// Draw the formatted text into the drawing context.
myTextLine.Draw(dc, linePosition, InvertAxes.None);

// Update the index position in the text store.


textStorePosition += myTextLine.Length;

// Update the line position coordinate for the displayed line.


linePosition.Y += myTextLine.Height;
}
}

// Persist the drawn text content.


dc.Close();

// Display the formatted text in the DrawingGroup object.


myDrawingBrush.Drawing = textDest;

Implementing the Client Text Store


When you extend the text formatting engine, you are required to implement and
manage all aspects of the text store. This is not a trivial task. The text store is responsible
for tracking text run properties, paragraph properties, embedded objects, and other
similar content. It also provides the text formatter with individual TextRun objects which
the text formatter uses to create TextLine objects.
To handle the virtualization of the text store, the text store must be derived from
TextSource. TextSource defines the method the text formatter uses to retrieve text runs
from the text store. GetTextRun is the method used by the text formatter to retrieve text
runs used in line formatting. The call to GetTextRun is repeatedly made by the text
formatter until one of the following conditions occurs:

A TextEndOfLine or a subclass is returned.

The accumulated width of text runs exceeds the maximum line width specified in
either the call to create the text formatter or the call to the text formatter's
FormatLine method.

A Unicode newline sequence, such as "CF", "LF", or "CRLF", is returned.

Providing Text Runs


The core of the text formatting process is the interaction between the text formatter and
the text store. Your implementation of TextSource provides the text formatter with the
TextRun objects and the properties with which to format the text runs. This interaction is
handled by the GetTextRun method, which is called by the text formatter.

The following table shows some of the predefined TextRun objects.

TextRun Type Usage

TextCharacters The specialized text run used to pass a representation of character glyphs
back to the text formatter.

TextEmbeddedObject The specialized text run used to provide content in which measuring, hit
testing, and drawing is done in whole, such as a button or image within
the text.

TextEndOfLine The specialized text run used to mark the end of a line.

TextEndOfParagraph The specialized text run used to mark the end of a paragraph.

TextEndOfSegment The specialized text run used to mark the end of a segment, such as to
end the scope affected by a previous TextModifier run.

TextHidden The specialized text run used to mark a range of hidden characters.

TextModifier The specialized text run used to modify properties of text runs in its
scope. The scope extends to the next matching TextEndOfSegment text
run, or the next TextEndOfParagraph.

Any of the predefined TextRun objects can be subclassed. This allows your text source to
provide the text formatter with text runs that include custom data.
The following example demonstrates a GetTextRun method. This text store returns
TextRun objects to the text formatter for processing.

C#

// Used by the TextFormatter object to retrieve a run of text from the text
source.
public override TextRun GetTextRun(int textSourceCharacterIndex)
{
// Make sure text source index is in bounds.
if (textSourceCharacterIndex < 0)
throw new ArgumentOutOfRangeException("textSourceCharacterIndex",
"Value must be greater than 0.");
if (textSourceCharacterIndex >= _text.Length)
{
return new TextEndOfParagraph(1);
}

// Create TextCharacters using the current font rendering properties.


if (textSourceCharacterIndex < _text.Length)
{
return new TextCharacters(
_text,
textSourceCharacterIndex,
_text.Length - textSourceCharacterIndex,
new GenericTextRunProperties(_currentRendering));
}

// Return an end-of-paragraph if no more text source.


return new TextEndOfParagraph(1);
}

7 Note

In this example, the text store provides the same text properties to all of the text.
Advanced text stores would need to implement their own span management to
allow individual characters to have different properties.

Specifying Formatting Properties


TextRun objects are formatted by using properties provided by the text store. These
properties come in two types, TextParagraphProperties and TextRunProperties.
TextParagraphProperties handle paragraph inclusive properties such as TextAlignment
and FlowDirection. TextRunProperties are properties that can be different for each text
run within a paragraph, such as foreground brush, Typeface, and font size. To implement
custom paragraph and custom text run property types, your application must create
classes that derive from TextParagraphProperties and TextRunProperties respectively.

See also
Typography in WPF
Documents in WPF
Fonts (WPF)
Article • 02/06/2023

Windows Presentation Foundation (WPF) includes support for rich presentation of text
using OpenType fonts. A sample pack of OpenType fonts is included with the Windows
SDK.

In This Section
OpenType Font Features
Packaging Fonts with Applications
Sample OpenType Font Pack
How-to Topics

See also
FontStyle
SystemFonts
Documents in WPF
Typography in WPF
OpenType Font Features
Article • 08/18/2022

This topic provides an overview of some of the key features of OpenType font
technology in Windows Presentation Foundation (WPF).

OpenType Font Format


The OpenType font format is an extension of the TrueType® font format, adding
support for PostScript font data. The OpenType font format was developed jointly by
Microsoft and Adobe Corporation. OpenType fonts and the operating system services
which support OpenType fonts provide users with a simple way to install and use fonts,
whether the fonts contain TrueType outlines or CFF (PostScript) outlines.

The OpenType font format addresses the following developer challenges:

Broader multi-platform support.

Better support for international character sets.

Better protection for font data.

Smaller file sizes to make font distribution more efficient.

Broader support for advanced typographic control.

7 Note

The Windows SDK contains a set of sample OpenType fonts that you can use with
Windows Presentation Foundation (WPF) applications. These fonts provide most of
the features illustrated in the rest of this topic. For more information, see Sample
OpenType Font Pack.

For details of the OpenType font format, see the OpenType specification.

Advanced Typographic Extensions


The Advanced Typographic tables (OpenType Layout tables) extend the functionality of
fonts with either TrueType or CFF outlines. OpenType Layout fonts contain additional
information that extends the capabilities of the fonts to support high-quality
international typography. Most OpenType fonts expose only a subset of the total
OpenType features available. OpenType fonts provide the following features.

Rich mapping between characters and glyphs that support ligatures, positional
forms, alternates, and other font substitutions.

Support for two-dimensional positioning and glyph attachment.

Explicit script and language information contained in font, so a text-processing


application can adjust its behavior accordingly.

The OpenType Layout tables are described in more detail in the "Font File Tables"
section of the OpenType specification.

The remainder of this overview introduces the breadth and flexibility of some of the
visually-interesting OpenType features that are exposed by the properties of the
Typography object. For more information on this object, see Typography Class.

Variants
Variants are used to render different typographic styles, such as superscripts and
subscripts.

Superscripts and Subscripts


The Variants property allows you to set superscript and subscript values for an
OpenType font.

The following text displays superscripts for the Palatino Linotype font.

The following markup example shows how to define superscripts for the Palatino
Linotype font, using properties of the Typography object.

XAML

<Paragraph FontFamily="Palatino Linotype">


2<Run Typography.Variants="Superscript">3</Run>
14<Run Typography.Variants="Superscript">th</Run>
</Paragraph>

The following text displays subscripts for the Palatino Linotype font.
The following markup example shows how to define subscripts for the Palatino Linotype
font, using properties of the Typography object.

XAML

<Paragraph FontFamily="Palatino Linotype">


H<Run Typography.Variants="Subscript">2</Run>O
Footnote<Run Typography.Variants="Subscript">4</Run>
</Paragraph>

Decorative Uses of Superscripts and Subscripts


You can also use superscripts and subscripts to create decorative effects of mixed case
text. The following text displays superscript and subscript text for the Palatino Linotype
font. Note that the capitals are not affected.

The following markup example shows how to define superscripts and subscripts for a
font, using properties of the Typography object.

XAML

<Paragraph FontFamily="Palatino Linotype" Typography.Variants="Superscript">


Chapter One
</Paragraph>
<Paragraph FontFamily="Palatino Linotype" Typography.Variants="Subscript">
Chapter One
</Paragraph>

Capitals
Capitals are a set of typographical forms that render text in capital-styled glyphs.
Typically, when text is rendered as all capitals, the spacing between letters can appear
too tight, and the weight and proportion of the letters too heavy. OpenType supports a
number of styling formats for capitals, including small capitals, petite capitals, titling,
and capital spacing. These styling formats allow you to control the appearance of
capitals.

The following text displays standard capital letters for the Pescadero font, followed by
the letters styled as "SmallCaps" and "AllSmallCaps". In this case, the same font size is
used for all three words.

The following markup example shows how to define capitals for the Pescadero font,
using properties of the Typography object. When the "SmallCaps" format is used, any
leading capital letter is ignored.

XAML

<Paragraph FontFamily="Pescadero" FontSize="48">


<Run>CAPITALS</Run>
<Run Typography.Capitals="SmallCaps">Capitals</Run>
<Run Typography.Capitals="AllSmallCaps">Capitals</Run>
</Paragraph>

Titling Capitals
Titling capitals are lighter in weight and proportion and designed to give a more elegant
look than normal capitals. Titling capitals are typically used in larger font sizes as
headings. The following text displays normal and titling capitals for the Pescadero font.
Notice the narrower stem widths of the text on the second line.

The following markup example shows how to define titling capitals for the Pescadero
font, using properties of the Typography object.

XAML

<Paragraph FontFamily="Pescadero">
<Run Typography.Capitals="Titling">chapter one</Run>
</Paragraph>
Capital Spacing
Capital spacing is a feature that allows you to provide more spacing when using all
capitals in text. Capital letters are typically designed to blend with lowercase letters.
Spacing that appears attractive between and a capital letter and a lowercase letter may
look too tight when all capital letters are used. The following text displays normal and
capital spacing for the Pescadero font.

The following markup example shows how to define capital spacing for the Pescadero
font, using properties of the Typography object.

XAML

<Paragraph FontFamily="Pescadero">
<Run Typography.CapitalSpacing="True">CHAPTER ONE</Run>
</Paragraph>

Ligatures
Ligatures are two or more glyphs that are formed into a single glyph in order to create
more readable or attractive text. OpenType fonts support four types of ligatures:

Standard ligatures. Designed to enhance readability. Standard ligatures include


"fi", "fl", and "ff".

Contextual ligatures. Designed to enhance readability by providing better joining


behavior between the characters that make up the ligature.

Discretionary ligatures. Designed to be ornamental, and not specifically designed


for readability.

Historical ligatures. Designed to be historical, and not specifically designed for


readability.

The following text displays standard ligature glyphs for the Pericles font.
The following markup example shows how to define standard ligature glyphs for the
Pericles font, using properties of the Typography object.

XAML

<Paragraph FontFamily="Pericles" Typography.StandardLigatures="True">


<Run Typography.StylisticAlternates="1">FI</Run>
<Run Typography.StylisticAlternates="1">FL</Run>
<Run Typography.StylisticAlternates="1">TH</Run>
<Run Typography.StylisticAlternates="1">TT</Run>
<Run Typography.StylisticAlternates="1">TV</Run>
<Run Typography.StylisticAlternates="1">TW</Run>
<Run Typography.StylisticAlternates="1">TY</Run>
<Run Typography.StylisticAlternates="1">VT</Run>
<Run Typography.StylisticAlternates="1">WT</Run>
<Run Typography.StylisticAlternates="1">YT</Run>
</Paragraph>

The following text displays discretionary ligature glyphs for the Pericles font.

The following markup example shows how to define discretionary ligature glyphs for the
Pericles font, using properties of the Typography object.

XAML

<Paragraph FontFamily="Pericles" Typography.DiscretionaryLigatures="True">


<Run Typography.StylisticAlternates="1">CO</Run>
<Run Typography.StylisticAlternates="1">LA</Run>
<Run Typography.StylisticAlternates="1">LE</Run>
<Run Typography.StylisticAlternates="1">LI</Run>
<Run Typography.StylisticAlternates="1">LL</Run>
<Run Typography.StylisticAlternates="1">LO</Run>
<Run Typography.StylisticAlternates="1">LU</Run>
</Paragraph>

By default, OpenType fonts in Windows Presentation Foundation (WPF) enable standard


ligatures. For example, if you use the Palatino Linotype font, the standard ligatures "fi",
"ff", and "fl" appear as a combined character glyph. Notice that the pair of characters for
each standard ligature touch each other.
However, you can disable standard ligature features so that a standard ligature such as
"ff" displays as two separate glyphs, rather than as a combined character glyph.

The following markup example shows how to disable standard ligature glyphs for the
Palatino Linotype font, using properties of the Typography object.

XAML

<!-- Set standard ligatures to false in order to disable feature. -->


<Paragraph Typography.StandardLigatures="False" FontFamily="Palatino
Linotype" FontSize="72">
fi ff fl
</Paragraph>

Swashes
Swashes are decorative glyphs that use elaborate ornamentation often associated with
calligraphy. The following text displays standard and swash glyphs for the Pescadero
font.

Swashes are often used as decorative elements in short phrases such as event
announcements. The following text uses swashes to emphasize the capital letters of the
name of the event.

The following markup example shows how to define swashes for a font, using properties
of the Typography object.

XAML

<Paragraph FontFamily="Pescadero" TextBlock.TextAlignment="Center">


Wishing you a<LineBreak/>
<Run Typography.StandardSwashes="1" FontSize="36">Happy New Year!</Run>
</Paragraph>

Contextual Swashes
Certain combinations of swash glyphs can cause an unattractive appearance, such as
overlapping descenders on adjacent letters. Using a contextual swash allows you to use
a substitute swash glyph that produces a better appearance. The following text shows
the same word before and after a contextual swash is applied.

The following markup example shows how to define a contextual swash for the
Pescadero font, using properties of the Typography object.

XAML

<Paragraph FontFamily="Pescadero" Typography.StandardSwashes="1">


Lyon <Run Typography.ContextualSwashes="1">L</Run>yon
</Paragraph>

Alternates
Alternates are glyphs that can be substituted for a standard glyph. OpenType fonts, such
as the Pericles font used in the following examples, can contain alternate glyphs that
you can use to create different appearances for text. The following text displays
standard glyphs for the Pericles font.

The Pericles OpenType font contains additional glyphs that provide stylistic alternates to
the standard set of glyphs. The following text displays stylistic alternate glyphs.

The following markup example shows how to define stylistic alternate glyphs for the
Pericles font, using properties of the Typography object.

XAML
<Paragraph FontFamily="Pericles">
<Run Typography.StylisticAlternates="1">A</Run>NCIENT
GR<Run Typography.StylisticAlternates="1">EE</Run>K
MYTH<Run Typography.StylisticAlternates="1">O</Run>LOGY
</Paragraph>

The following text displays several other stylistic alternate glyphs for the Pericles font.

The following markup example shows how to define these other stylistic alternate
glyphs.

XAML

<Paragraph FontFamily="Pericles">
<Run Typography.StylisticAlternates="1">A</Run>
<Run Typography.StylisticAlternates="2">A</Run>
<Run Typography.StylisticAlternates="3">A</Run>
<Run Typography.StylisticAlternates="1">C</Run>
<Run Typography.StylisticAlternates="1">E</Run>
<Run Typography.StylisticAlternates="1">G</Run>
<Run Typography.StylisticAlternates="1">O</Run>
<Run Typography.StylisticAlternates="1">Q</Run>
<Run Typography.StylisticAlternates="1">R</Run>
<Run Typography.StylisticAlternates="2">R</Run>
<Run Typography.StylisticAlternates="1">S</Run>
<Run Typography.StylisticAlternates="1">Y</Run>
</Paragraph>

Random Contextual Alternates


Random contextual alternates provide multiple substitute glyphs for a single character.
When implemented with script-type fonts, this feature can simulate handwriting by
using of a set of randomly chosen glyphs with slight differences in appearance. The
following text uses random contextual alternates for the Lindsey font. Notice that the
letter "a" varies slightly in appearance

The following markup example shows how to define random contextual alternates for
the Lindsey font, using properties of the Typography object.

XAML
<TextBlock FontFamily="Lindsey">
<Run Typography.ContextualAlternates="True">
a banana in a cabana
</Run>
</TextBlock>

Historical Forms
Historical forms are typographic conventions that were common in the past. The
following text displays the phrase, "Boston, Massachusetts", using an historical form of
glyphs for the Palatino Linotype font.

The following markup example shows how to define historical forms for the Palatino
Linotype font, using properties of the Typography object.

XAML

<Paragraph FontFamily="Palatino Linotype">


<Run Typography.HistoricalForms="True">Boston, Massachusetts</Run>
</Paragraph>

Numerical Styles
OpenType fonts support a large number of features that can be used with numerical
values in text.

Fractions
OpenType fonts support styles for fractions, including slashed and stacked.

The following text displays fraction styles for the Palatino Linotype font.

The following markup example shows how to define fraction styles for the Palatino
Linotype font, using properties of the Typography object.
XAML

<Paragraph FontFamily="Palatino Linotype" Typography.Fraction="Slashed">


1/8 1/4 3/8 1/2 5/8 3/4 7/8
</Paragraph>
<Paragraph FontFamily="Palatino Linotype" Typography.Fraction="Stacked">
1/8 1/4 3/8 1/2 5/8 3/4 7/8
</Paragraph>

Old Style Numerals


OpenType fonts support an old style numeral format. This format is useful for displaying
numerals in styles that are no longer standard. The following text displays an 18th
century date in standard and old style numeral formats for the Palatino Linotype font.

The following text displays standard numerals for the Palatino Linotype font, followed by
old style numerals.

The following markup example shows how to define old style numerals for the Palatino
Linotype font, using properties of the Typography object.

XAML

<Paragraph FontFamily="Palatino Linotype">


<Run Typography.NumeralStyle="Normal">1234567890</Run>
<Run Typography.NumeralStyle="OldStyle">1234567890</Run>
</Paragraph>

Proportional and Tabular Figures


OpenType fonts support a proportional and tabular figure feature to control the
alignment of widths when using numerals. Proportional figures treat each numeral as
having a different width—"1" is narrower than "5". Tabular figures are treated as equal-
width numerals so that they align vertically, which increases the readability of financial
type information.

The following text displays two proportional figures in the first column using the
Miramonte font. Note the difference in width between the numerals "5" and "1". The
second column shows the same two numeric values with the widths adjusted by using
the tabular figure feature.

The following markup example shows how to define proportional and tabular figures for
the Miramonte font, using properties of the Typography object.

XAML

<TextBlock FontFamily="Miramonte">
<Run Typography.NumeralAlignment="Proportional">114,131</Run>
</TextBlock>
<TextBlock FontFamily="Miramonte">
<Run Typography.NumeralAlignment="Tabular">114,131</Run>
</TextBlock>

Slashed Zero
OpenType fonts support a slashed zero numeral format to emphasize the difference
between the letter "O" and the numeral "0". The slashed zero numeral is often used for
identifiers in financial and business information.

The following text displays a sample order identifier using the Miramonte font. The first
line uses standard numerals. The second line used slashed zero numerals to provide
better contrast with the uppercase "O" letter.

The following markup example shows how to define slashed zero numerals for the
Miramonte font, using properties of the Typography object.

XAML

<Paragraph FontFamily="Miramonte">
<Run>Order #0048-OTC-390</Run>
<LineBreak/>
<Run Typography.SlashedZero="True">Order #0048-OTC-390</Run>
</Paragraph>
Typography Class
The Typography object exposes the set of features that an OpenType font supports. By
setting the properties of Typography in markup, you can easily author documents that
take advantage of OpenType features.

The following text displays standard capital letters for the Pescadero font, followed by
the letters styled as "SmallCaps" and "AllSmallCaps". In this case, the same font size is
used for all three words.

The following markup example shows how to define capitals for the Pescadero font,
using properties of the Typography object. When the "SmallCaps" format is used, any
leading capital letter is ignored.

XAML

<Paragraph FontFamily="Pescadero" FontSize="48">


<Run>CAPITALS</Run>
<Run Typography.Capitals="SmallCaps">Capitals</Run>
<Run Typography.Capitals="AllSmallCaps">Capitals</Run>
</Paragraph>

The following code example accomplishes the same task as the previous markup
example.

C#

MyParagraph.FontFamily = new FontFamily("Pescadero");


MyParagraph.FontSize = 48;

Run run_1 = new Run("CAPITALS ");


MyParagraph.Inlines.Add(run_1);

Run run_2 = new Run("Capitals ");


run_2.Typography.Capitals = FontCapitals.SmallCaps;
MyParagraph.Inlines.Add(run_2);

Run run_3 = new Run("Capitals");


run_3.Typography.Capitals = FontCapitals.AllSmallCaps;
MyParagraph.Inlines.Add(run_3);

MyParagraph.Inlines.Add(new LineBreak());
Typography Class Properties
The following table lists the properties, values, and default settings of the Typography
object.

Property Value(s) Default Value

AnnotationAlternates Numeric value - byte 0

Capitals AllPetiteCaps | AllSmallCaps | Normal | FontCapitals.Normal


PetiteCaps | SmallCaps | Titling |
Unicase

CapitalSpacing Boolean false

CaseSensitiveForms Boolean false

ContextualAlternates Boolean true

ContextualLigatures Boolean true

ContextualSwashes Numeric value - byte 0

DiscretionaryLigatures Boolean false

EastAsianExpertForms Boolean false

EastAsianLanguage HojoKanji | Jis04 | Jis78 | Jis83 | Jis90 | FontEastAsianLanguage.Normal


NlcKanji | Normal | Simplified |
Traditional | TraditionalNames

EastAsianWidths Full | Half | Normal | Proportional | FontEastAsianWidths.Normal


Quarter | Third

Fraction Normal | Slashed | Stacked FontFraction.Normal

HistoricalForms Boolean false

HistoricalLigatures Boolean false

Kerning Boolean true

MathematicalGreek Boolean false

NumeralAlignment Normal | Proportional | Tabular FontNumeralAlignment.Normal

NumeralStyle Boolean FontNumeralStyle.Normal

SlashedZero Boolean false

StandardLigatures Boolean true


Property Value(s) Default Value

StandardSwashes numeric value – byte 0

StylisticAlternates numeric value – byte 0

StylisticSet1 Boolean false

StylisticSet2 Boolean false

StylisticSet3 Boolean false

StylisticSet4 Boolean false

StylisticSet5 Boolean false

StylisticSet6 Boolean false

StylisticSet7 Boolean false

StylisticSet8 Boolean false

StylisticSet9 Boolean false

StylisticSet10 Boolean false

StylisticSet11 Boolean false

StylisticSet12 Boolean false

StylisticSet13 Boolean false

StylisticSet14 Boolean false

StylisticSet15 Boolean false

StylisticSet16 Boolean false

StylisticSet17 Boolean false

StylisticSet18 Boolean false

StylisticSet19 Boolean false

StylisticSet20 Boolean false

Variants Inferior | Normal | Ordinal | Ruby | FontVariants.Normal


Subscript | Superscript

See also
Typography
OpenType specification
Typography in WPF
Sample OpenType Font Pack
Packaging Fonts with Applications
Packaging Fonts with Applications
Article • 03/17/2022

This topic provides an overview of how to package fonts with your Windows
Presentation Foundation (WPF) application.

7 Note

As with most types of software, font files are licensed, rather than sold. Licenses
that govern the use of fonts vary from vendor to vendor but in general most
licenses, including those covering the fonts Microsoft supplies with applications
and Windows, do not allow the fonts to be embedded within applications or
otherwise redistributed. Therefore, as a developer it is your responsibility to ensure
that you have the required license rights for any font you embed within an
application or otherwise redistribute.

Introduction to Packaging Fonts


You can easily package fonts as resources within your WPF applications to display user
interface text and other types of text based content. The fonts can be separate from or
embedded within the application's assembly files. You can also create a resource-only
font library, which your application can reference.

OpenType and TrueType® fonts contain a type flag, fsType, that indicates font
embedding licensing rights for the font. However, this type flag only refers to
embedded fonts stored in a document–it does not refer to fonts embedded in an
application. You can retrieve the font embedding rights for a font by creating a
GlyphTypeface object and referencing its EmbeddingRights property. Refer to the "OS/2
and Windows Metrics" section of the OpenType Specification for more information on
the fsType flag.

The Microsoft Typography Web site includes contact information that can help you
locate a particular font vendor or find a font vendor for custom work.

Adding Fonts as Content Items


You can add fonts to your application as project content items that are separate from
the application's assembly files. This means that content items are not embedded as
resources within an assembly. The following project file example shows how to define
content items.

XML

<Project DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Other project build settings ... -->

<ItemGroup>
<Content Include="Peric.ttf" />
<Content Include="Pericl.ttf" />
</ItemGroup>
</Project>

In order to ensure that the application can use the fonts at run time, the fonts must be
accessible in the application's deployment directory. The <CopyToOutputDirectory>
element in the application's project file allows you to automatically copy the fonts to the
application deployment directory during the build process. The following project file
example shows how to copy fonts to the deployment directory.

XML

<ItemGroup>
<Content Include="Peric.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Pericl.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

The following code example shows how to reference the application's font as a content
item—the referenced content item must be in the same directory as the application's
assembly files.

XAML

<TextBlock FontFamily="./#Pericles Light">


Aegean Sea
</TextBlock>

Adding Fonts as Resource Items


You can add fonts to your application as project resource items that are embedded
within the application's assembly files. Using a separate subdirectory for resources helps
to organize the application's project files. The following project file example shows how
to define fonts as resource items in a separate subdirectory.

XML

<Project DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Other project build settings ... -->

<ItemGroup>
<Resource Include="resources\Peric.ttf" />
<Resource Include="resources\Pericl.ttf" />
</ItemGroup>
</Project>

7 Note

When you add fonts as resources to your application, make sure you are setting the
<Resource> element, and not the <EmbeddedResource> element in your application's

project file. The <EmbeddedResource> element for the build action is not supported.

The following markup example shows how to reference the application's font resources.

XAML

<TextBlock FontFamily="./resources/#Pericles Light">


Aegean Sea
</TextBlock>

Referencing Font Resource Items from Code


In order to reference font resource items from code, you must supply a two-part font
resource reference: the base uniform resource identifier (URI); and the font location
reference. These values are used as the parameters for the FontFamily method. The
following code example shows how to reference the application's font resources in the
project subdirectory called resources .

C#

// The font resource reference includes the base URI reference (application
directory level),
// and a relative URI reference.
myTextBlock.FontFamily = new FontFamily(new Uri("pack://application:,,,/"),
"./resources/#Pericles Light");

The base uniform resource identifier (URI) can include the application subdirectory
where the font resource resides. In this case, the font location reference would not need
to specify a directory, but would have to include a leading " ./ ", which indicates the font
resource is in the same directory specified by the base uniform resource identifier (URI).
The following code example shows an alternate way of referencing the font resource
item—it is equivalent to the previous code example.

C#

// The base URI reference can include an application subdirectory.


myTextBlock.FontFamily = new FontFamily(new
Uri("pack://application:,,,/resources/"), "./#Pericles Light");

Referencing Fonts from the Same Application


Subdirectory
You can place both application content and resource files within the same user-defined
subdirectory of your application project. The following project file example shows a
content page and font resources defined in the same subdirectory.

XML

<ItemGroup>
<Page Include="pages\HomePage.xaml" />
</ItemGroup>
<ItemGroup>
<Resource Include="pages\Peric.ttf" />
<Resource Include="pages\Pericl.ttf" />
</ItemGroup>

Since the application content and font are in the same subdirectory, the font reference is
relative to the application content. The following examples show how to reference the
application's font resource when the font is in the same directory as the application.

XAML

<TextBlock FontFamily="./#Pericles Light">


Aegean Sea
</TextBlock>

C#
// The font resource reference includes the base Uri (application directory
level),
// and the file resource location, which is relative to the base Uri.
myTextBlock.FontFamily = new FontFamily(new Uri("pack://application:,,,/"),
"/pages/#Pericles Light");

Enumerating Fonts in an Application


To enumerate fonts as resource items in your application, use either the GetFontFamilies
or GetTypefaces method. The following example shows how to use the GetFontFamilies
method to return the collection of FontFamily objects from the application font location.
In this case, the application contains a subdirectory named "resources".

C#

foreach (FontFamily fontFamily in Fonts.GetFontFamilies(new


Uri("pack://application:,,,/"), "./resources/"))
{
// Perform action.
}

The following example shows how to use the GetTypefaces method to return the
collection of Typeface objects from the application font location. In this case, the
application contains a subdirectory named "resources".

C#

foreach (Typeface typeface in Fonts.GetTypefaces(new


Uri("pack://application:,,,/"), "./resources/"))
{
// Perform action.
}

Creating a Font Resource Library


You can create a resource-only library that contains only fonts—no code is part of this
type of library project. Creating a resource-only library is a common technique for
decoupling resources from the application code that uses them. This also allows the
library assembly to be included with multiple application projects. The following project
file example shows the key portions of a resource-only library project.

XML
<PropertyGroup>
<AssemblyName>FontLibrary</AssemblyName>
<OutputType>library</OutputType>
...
</PropertyGroup>
...
<ItemGroup>
<Resource Include="Kooten.ttf" />
<Resource Include="Pesca.ttf" />
</ItemGroup

Referencing a Font in a Resource Library


To reference a font in a resource library from your application, you must prefix the font
reference with the name of the library assembly. In this case, the font resource assembly
is "FontLibrary". To separate the assembly name from the reference within the assembly,
use a ';' character. Adding the "Component" keyword followed by the reference to the
font name completes the full reference to the font library's resource. The following code
example shows how to reference a font in a resource library assembly.

XAML

<Run FontFamily="/FontLibrary;Component/#Kootenay" FontSize="36">


ABCDEFGHIJKLMNOPQRSTUVWXYZ
</Run>

7 Note

This SDK contains a set of sample OpenType fonts that you can use with WPF
applications. The fonts are defined in a resource-only library. For more information,
see Sample OpenType Font Pack.

Limitations on Font Usage


The following list describes several limitations on the packaging and use of fonts in WPF
applications:

Font embedding permission bits: WPF applications do not check or enforce any
font embedding permission bits. See the Introduction_to_Packing Fonts section for
more information.
Site of origin fonts: WPF applications do not allow a font reference to an http or
ftp uniform resource identifier (URI).

Absolute URI using the pack: notation: WPF applications do not allow you to
create a FontFamily object programmatically using "pack:" as part of the absolute
uniform resource identifier (URI) reference to a font. For example,
"pack://application:,,,/resources/#Pericles Light" is an invalid font reference.

Automatic font embedding: During design time, there is no support for searching
an application's use of fonts and automatically embedding the fonts in the
application's resources.

Font subsets: WPF applications do not support the creation of font subsets for
non-fixed documents.

In cases where there is an incorrect reference, the application falls back to using an
available font.

See also
Typography
FontFamily
Microsoft Typography: Links, News, and Contacts
OpenType Specification
OpenType Font Features
Sample OpenType Font Pack
Sample OpenType Font Pack
Article • 02/06/2023

This topic provides an overview of the sample OpenType fonts that are distributed with
the Windows SDK. The sample fonts support extended OpenType features that can be
used by Windows Presentation Foundation (WPF) applications.

Fonts in the OpenType Font Pack


The Windows SDK provides a set of sample OpenType fonts that you can use in creating
Windows Presentation Foundation (WPF) applications. The sample fonts are supplied
under license from Ascender Corporation. These fonts implement only a subset of the
total features defined by the OpenType format. The following table lists the names of
the sample OpenType fonts.

Name File

Kootenay Kooten.ttf

Lindsey Linds.ttf

Miramonte Miramo.ttf

Miramonte Bold Miramob.ttf

Pericles Peric.ttf

Pericles Light Pericl.ttf

Pescadero Pesca.ttf

Pescadero Bold Pescab.ttf

The following illustration shows what the sample OpenType fonts look like.
The sample fonts are supplied under license from Ascender Corporation. Ascender is a
provider of advanced font products. To license extended or custom versions of the
sample fonts, see Ascender Corporation's Web site .

7 Note

As a developer it is your responsibility to ensure that you have the required license
rights for any font you embed within an application or otherwise redistribute.

Installing the Fonts


You have the option of installing the sample OpenType fonts to the default Windows
Fonts directory, \WINDOWS\Fonts. Use the Fonts control panel to install the fonts.
Once these fonts are on your computer, they are accessible to all applications that
reference default Windows fonts. You can display a representative set of characters in
several font sizes by doubling-clicking the font file. The following screenshot shows the
Lindsey font file, Linds.ttf.
Displaying the Lindsey font

Using the Fonts


There are two ways that you can use fonts in your application. You can add fonts to your
application as project content items that are not embedded as resources within an
assembly. Alternatively, you can add fonts to your application as project resource items
that are embedded within the application's assembly files. For more information, see
Packaging Fonts with Applications.

See also
Typography
OpenType Font Features
Packaging Fonts with Applications
Fonts How-to Topics
Article • 02/06/2023

The topics in this section demonstrate how to use the font features included with
Windows Presentation Foundation (WPF).

In This Section
Enumerate System Fonts
Use the FontSizeConverter Class

See also
FontStyle
SystemFonts
Documents in WPF
Typography in WPF
How to: Enumerate System Fonts
Article • 02/06/2023

Example
The following example shows how to enumerate the fonts in the system font collection.
The font family name of each FontFamily within SystemFontFamilies is added as an item
to a combo box.

C#

public void FillFontComboBox(ComboBox comboBoxFonts)


{
// Enumerate the current set of system fonts,
// and fill the combo box with the names of the fonts.
foreach (FontFamily fontFamily in Fonts.SystemFontFamilies)
{
// FontFamily.Source contains the font family name.
comboBoxFonts.Items.Add(fontFamily.Source);
}

comboBoxFonts.SelectedIndex = 0;
}

If multiple versions of the same font family reside in the same directory, the Windows
Presentation Foundation (WPF) font enumeration returns the most recent version of the
font. If the version information does not provide resolution, the font with latest
timestamp is returned. If the timestamp information is equivalent, the font file that is
first in alphabetical order is returned.
How to: Use the FontSizeConverter
Class
Article • 02/06/2023

Example
This example shows how to create an instance of FontSizeConverter and use it to
change a font size.

The example defines a custom method called changeSize that converts the contents of a
ListBoxItem, as defined in a separate Extensible Application Markup Language (XAML)
file, to an instance of Double, and later into a String. This method passes the ListBoxItem
to a FontSizeConverter object, which converts the Content of a ListBoxItem to an
instance of Double. This value is then passed back as the value of the FontSize property
of the TextBlock element.

This example also defines a second custom method that is called changeFamily . This
method converts the Content of the ListBoxItem to a String, and then passes that value
to the FontFamily property of the TextBlock element.

This example does not run.

C#

private void changeSize(object sender, SelectionChangedEventArgs args)


{
ListBoxItem li = ((sender as ListBox).SelectedItem as ListBoxItem);
FontSizeConverter myFontSizeConverter = new FontSizeConverter();
text1.FontSize =
(Double)myFontSizeConverter.ConvertFromString(li.Content.ToString());
}

private void changeFamily(object sender, SelectionChangedEventArgs args)


{
ListBoxItem li2 = ((sender as ListBox).SelectedItem as ListBoxItem);
text1.FontFamily = new
System.Windows.Media.FontFamily(li2.Content.ToString());
}

See also
FontSizeConverter
Glyphs
Article • 02/06/2023

Glyphs are a low-level depiction of a character to be drawn on-screen. Windows


Presentation Foundation (WPF) provides direct access to glyphs for customers who want
to intercept and persist text after formatting.

In This Section
Introduction to the GlyphRun Object and Glyphs Element
How to: Draw Text Using Glyphs

See also
GlyphRun
DrawText
Glyphs
Documents in WPF
Typography in WPF
Introduction to the GlyphRun Object
and Glyphs Element
Article • 08/10/2023

This topic describes the GlyphRun object and the Glyphs element.

Introduction to GlyphRun
Windows Presentation Foundation (WPF) provides advanced text support including
glyph-level markup with direct access to Glyphs for customers who want to intercept
and persist text after formatting. These features provide critical support for the different
text rendering requirements in each of the following scenarios.

1. Screen display of fixed-format documents.

2. Print scenarios.

Extensible Application Markup Language (XAML) as a device printer


language.

Microsoft XPS Document Writer.

Previous printer drivers, output from Win32 applications to the fixed format.

Print spool format.

3. Fixed-format document representation, including clients for previous versions of


Windows and other computing devices.

7 Note

Glyphs and GlyphRun are designed for fixed-format document presentation and
print scenarios. WPF provides several elements for general layout and User
interface (UI) scenarios such as Label and TextBlock. For more information on
layout and UI scenarios, see the Typography in WPF.

The GlyphRun Object


The GlyphRun object represents a sequence of glyphs from a single face of a single font
at a single size, and with a single rendering style.
GlyphRun includes both font details such as glyph Indices and individual glyph
positions. It also includes the original Unicode code points the run was generated from,
character-to-glyph buffer offset mapping information, and per-character and per-glyph
flags.

GlyphRun has a corresponding high-level FrameworkElement, Glyphs. Glyphs can be


used in the element tree and in XAML markup to represent GlyphRun output.

The Glyphs Element


The Glyphs element represents the output of a GlyphRun in XAML. The following
markup syntax is used to describe the Glyphs element.

XAML

<!-- The example shows how to use a Glyphs object. -->


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>

<StackPanel Background="PowderBlue">

<Glyphs
FontUri = "C:\WINDOWS\Fonts\TIMES.TTF"
FontRenderingEmSize = "100"
StyleSimulations = "BoldSimulation"
UnicodeString = "Hello World!"
Fill = "Black"
OriginX = "100"
OriginY = "200"
/>

</StackPanel>
</Page>

The following property definitions correspond to the first four attributes in the sample
markup.

Property Description

FontUri Specifies a resource identifier: file name, Web uniform resource identifier
(URI), or resource reference in the application .exe or container.

FontRenderingEmSize Specifies the font size in drawing surface units (default is .96 inches).

StyleSimulations Specifies flags for bold and Italic styles.


Property Description

BidiLevel Specifies the bidirectional layout level. Even-numbered and zero values
imply left-to-right layout; odd-numbered values imply right-to-left
layout.

Indices property
The Indices property is a string of glyph specifications. Where a sequence of glyphs
forms a single cluster, the specification of the first glyph in the cluster is preceded by a
specification of how many glyphs and how many code points combine to form the
cluster. The Indices property collects in one string the following properties.

Glyph indices

Glyph advance widths

Combining glyph attachment vectors

Cluster mapping from code points to glyphs

Glyph flags

Each glyph specification has the following form.

[GlyphIndex][,[Advance][,[uOffset][,[vOffset][,[Flags]]]]]

Glyph Metrics
Each glyph defines metrics that specify how it aligns with other Glyphs. The following
graphic defines the various typographic qualities of two different glyph characters.
Glyphs Markup
The following code example shows how to use various properties of the Glyphs element
in XAML.

XAML

<!-- The example shows how to use different property settings of Glyphs
objects. -->
<Canvas
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="PowderBlue"
>

<Glyphs
FontUri = "C:\WINDOWS\Fonts\ARIAL.TTF"
FontRenderingEmSize = "36"
StyleSimulations = "ItalicSimulation"
UnicodeString = "Hello World!"
Fill = "SteelBlue"
OriginX = "50"
OriginY = "75"
/>

<!-- "Hello World!" with default kerning -->


<Glyphs
FontUri = "C:\WINDOWS\Fonts\ARIAL.TTF"
FontRenderingEmSize = "36"
UnicodeString = "Hello World!"
Fill = "Maroon"
OriginX = "50"
OriginY = "150"
/>

<!-- "Hello World!" with explicit character widths for proportional font -->
<Glyphs
FontUri = "C:\WINDOWS\Fonts\ARIAL.TTF"
FontRenderingEmSize = "36"
UnicodeString = "Hello World!"
Indices = ",80;,80;,80;,80;,80;,80;,80;,80;,80;,80;,80"
Fill = "Maroon"
OriginX = "50"
OriginY = "225"
/>

<!-- "Hello World!" with fixed-width font -->


<Glyphs
FontUri = "C:\WINDOWS\Fonts\COUR.TTF"
FontRenderingEmSize = "36"
StyleSimulations = "BoldSimulation"
UnicodeString = "Hello World!"
Fill = "Maroon"
OriginX = "50"
OriginY = "300"
/>

<!-- "Open file" without "fi" ligature -->


<Glyphs
FontUri = "C:\WINDOWS\Fonts\TIMES.TTF"
FontRenderingEmSize = "36"
StyleSimulations = "BoldSimulation"
UnicodeString = "Open file"
Fill = "SlateGray"
OriginX = "400"
OriginY = "75"
/>

<!-- "Open file" with "fi" ligature -->


<Glyphs
FontUri = "C:\WINDOWS\Fonts\TIMES.TTF"
FontRenderingEmSize = "36"
StyleSimulations = "BoldSimulation"
UnicodeString = "Open file"
Indices = ";;;;;(2:1)191"
Fill = "SlateGray"
OriginX = "400"
OriginY = "150"
/>

</Canvas>

See also
Typography in WPF
Documents in WPF
Text
Draw Text Using Glyphs
Article • 08/10/2023

This topic explains how to use the low-level Glyphs object to display text in Extensible
Application Markup Language (XAML).

Example
The following examples show how to define properties for a Glyphs object in XAML. The
Glyphs object represents the output of a GlyphRun in XAML. The examples assume that
the Arial, Courier New, and Times New Roman fonts are installed in the
C:\WINDOWS\Fonts folder on the local computer.

XAML

<!-- The example shows how to use a Glyphs object. -->


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>

<StackPanel Background="PowderBlue">

<Glyphs
FontUri = "C:\WINDOWS\Fonts\TIMES.TTF"
FontRenderingEmSize = "100"
StyleSimulations = "BoldSimulation"
UnicodeString = "Hello World!"
Fill = "Black"
OriginX = "100"
OriginY = "200"
/>

</StackPanel>
</Page>

This example shows how to define other properties of Glyphs objects in XAML.

XAML

<!-- The example shows how to use different property settings of Glyphs
objects. -->
<Canvas
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="PowderBlue"
>
<Glyphs
FontUri = "C:\WINDOWS\Fonts\ARIAL.TTF"
FontRenderingEmSize = "36"
StyleSimulations = "ItalicSimulation"
UnicodeString = "Hello World!"
Fill = "SteelBlue"
OriginX = "50"
OriginY = "75"
/>

<!-- "Hello World!" with default kerning -->


<Glyphs
FontUri = "C:\WINDOWS\Fonts\ARIAL.TTF"
FontRenderingEmSize = "36"
UnicodeString = "Hello World!"
Fill = "Maroon"
OriginX = "50"
OriginY = "150"
/>

<!-- "Hello World!" with explicit character widths for proportional font -->
<Glyphs
FontUri = "C:\WINDOWS\Fonts\ARIAL.TTF"
FontRenderingEmSize = "36"
UnicodeString = "Hello World!"
Indices = ",80;,80;,80;,80;,80;,80;,80;,80;,80;,80;,80"
Fill = "Maroon"
OriginX = "50"
OriginY = "225"
/>

<!-- "Hello World!" with fixed-width font -->


<Glyphs
FontUri = "C:\WINDOWS\Fonts\COUR.TTF"
FontRenderingEmSize = "36"
StyleSimulations = "BoldSimulation"
UnicodeString = "Hello World!"
Fill = "Maroon"
OriginX = "50"
OriginY = "300"
/>

<!-- "Open file" without "fi" ligature -->


<Glyphs
FontUri = "C:\WINDOWS\Fonts\TIMES.TTF"
FontRenderingEmSize = "36"
StyleSimulations = "BoldSimulation"
UnicodeString = "Open file"
Fill = "SlateGray"
OriginX = "400"
OriginY = "75"
/>

<!-- "Open file" with "fi" ligature -->


<Glyphs
FontUri = "C:\WINDOWS\Fonts\TIMES.TTF"
FontRenderingEmSize = "36"
StyleSimulations = "BoldSimulation"
UnicodeString = "Open file"
Indices = ";;;;;(2:1)191"
Fill = "SlateGray"
OriginX = "400"
OriginY = "150"
/>

</Canvas>

See also
Typography in WPF
Typography How-to Topics
Article • 02/06/2023

The topics in this section describe how to use Windows Presentation Foundation (WPF)
support for rich presentation of text in your applications.

In This Section
Create a Text Decoration
Specify Whether a Hyperlink is Underlined
Apply Transforms to Text
Apply Animations to Text
Create Text with a Shadow
Create Outlined Text
Draw Text to a Control's Background
Draw Text to a Visual
Use Special Characters in XAML

See also
Typography
Documents in WPF
OpenType Font Features
How to: Create a Text Decoration
Article • 02/06/2023

A TextDecoration object is a visual ornamentation you can add to text. There are four
types of text decorations: underline, baseline, strikethrough, and overline. The following
example shows the locations of the text decorations relative to the text.

To add a text decoration to text, create a TextDecoration object and modify its
properties. Use the Location property to specify where the text decoration appears, such
as underline. Use the Pen property to specify the appearance of the text decoration,
such as a solid fill or gradient color. If you do not specify a value for the Pen property,
the decorations defaults to the same color as the text. Once you have defined a
TextDecoration object, add it to the TextDecorations collection of the desired text object.

The following example shows a text decoration that has been styled with a linear
gradient brush and a dashed pen.

The Hyperlink object is an inline-level flow content element that allows you to host
hyperlinks within the flow content. By default, Hyperlink uses a TextDecoration object to
display an underline. TextDecoration objects can be performance intensive to instantiate,
particularly if you have many Hyperlink objects. If you make extensive use of Hyperlink
elements, you may want to consider showing an underline only when triggering an
event, such as the MouseEnter event.

In the following example, the underline for the "My MSN" link is dynamic—it only
appears when the MouseEnter event is triggered.
For more information, see Specify Whether a Hyperlink is Underlined.

Example
In the following code example, an underline text decoration uses the default font value.

C#

// Use the default font values for the strikethrough text decoration.
private void SetDefaultStrikethrough()
{
// Set the underline decoration directly to the text block.
TextBlock1.TextDecorations = TextDecorations.Strikethrough;
}

XAML

<!-- Use the default font values for the strikethrough text decoration. -->
<TextBlock
TextDecorations="Strikethrough"
FontSize="36" >
The quick red fox
</TextBlock>

In the following code example, an underline text decoration is created with a solid color
brush for the pen.

C#

// Use a Red pen for the underline text decoration.


private void SetRedUnderline()
{
// Create an underline text decoration. Default is underline.
TextDecoration myUnderline = new TextDecoration();

// Create a solid color brush pen for the text decoration.


myUnderline.Pen = new Pen(Brushes.Red, 1);
myUnderline.PenThicknessUnit = TextDecorationUnit.FontRecommended;

// Set the underline decoration to a TextDecorationCollection and add it


to the text block.
TextDecorationCollection myCollection = new TextDecorationCollection();
myCollection.Add(myUnderline);
TextBlock2.TextDecorations = myCollection;
}

XAML
<!-- Use a Red pen for the underline text decoration -->
<TextBlock
FontSize="36" >
jumps over
<TextBlock.TextDecorations>
<TextDecorationCollection>
<TextDecoration
PenThicknessUnit="FontRecommended">
<TextDecoration.Pen>
<Pen Brush="Red" Thickness="1" />
</TextDecoration.Pen>
</TextDecoration>
</TextDecorationCollection>
</TextBlock.TextDecorations>
</TextBlock>

In the following code example, an underline text decoration is created with a linear
gradient brush for the dashed pen.

C#

// Use a linear gradient pen for the underline text decoration.


private void SetLinearGradientUnderline()
{
// Create an underline text decoration. Default is underline.
TextDecoration myUnderline = new TextDecoration();

// Create a linear gradient pen for the text decoration.


Pen myPen = new Pen();
myPen.Brush = new LinearGradientBrush(Colors.Yellow, Colors.Red, new
Point(0, 0.5), new Point(1, 0.5));
myPen.Brush.Opacity = 0.5;
myPen.Thickness = 1.5;
myPen.DashStyle = DashStyles.Dash;
myUnderline.Pen = myPen;
myUnderline.PenThicknessUnit = TextDecorationUnit.FontRecommended;

// Set the underline decoration to a TextDecorationCollection and add it


to the text block.
TextDecorationCollection myCollection = new TextDecorationCollection();
myCollection.Add(myUnderline);
TextBlock3.TextDecorations = myCollection;
}

XAML

<!-- Use a linear gradient pen for the underline text decoration. -->
<TextBlock FontSize="36">the lazy brown dog.
<TextBlock.TextDecorations>
<TextDecorationCollection>
<TextDecoration
PenThicknessUnit="FontRecommended">
<TextDecoration.Pen>
<Pen Thickness="1.5">
<Pen.Brush>
<LinearGradientBrush Opacity="0.5"
StartPoint="0,0.5" EndPoint="1,0.5">
<LinearGradientBrush.GradientStops>
<GradientStop Color="Yellow" Offset="0" />
<GradientStop Color="Red" Offset="1" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Pen.Brush>
<Pen.DashStyle>
<DashStyle Dashes="2"/>
</Pen.DashStyle>
</Pen>
</TextDecoration.Pen>
</TextDecoration>
</TextDecorationCollection>
</TextBlock.TextDecorations>
</TextBlock>

See also
TextDecoration
Hyperlink
Specify Whether a Hyperlink is Underlined
How to: Specify Whether a Hyperlink is
Underlined
Article • 02/06/2023

The Hyperlink object is an inline-level flow content element that allows you to host
hyperlinks within the flow content. By default, Hyperlink uses a TextDecoration object to
display an underline. TextDecoration objects can be performance intensive to instantiate,
particularly if you have many Hyperlink objects. If you make extensive use of Hyperlink
elements, you may want to consider showing an underline only when triggering an
event, such as the MouseEnter event.

In the following example, the underline for the "My MSN" link is dynamic, that is, it only
appears when the MouseEnter event is triggered.

Example
The following markup sample shows a Hyperlink defined with and without an underline:

XAML

<!-- Hyperlink with default underline. -->


<Hyperlink NavigateUri="http://www.msn.com">
MSN Home
</Hyperlink>

<Run Text=" | " />

<!-- Hyperlink with no underline. -->


<Hyperlink Name="myHyperlink" TextDecorations="None"
MouseEnter="OnMouseEnter"
MouseLeave="OnMouseLeave"
NavigateUri="http://www.msn.com">
My MSN
</Hyperlink>
The following code sample shows how to create an underline for the Hyperlink on the
MouseEnter event, and remove it on the MouseLeave event.

C#

// Display the underline on only the MouseEnter event.


private void OnMouseEnter(object sender, EventArgs e)
{
myHyperlink.TextDecorations = TextDecorations.Underline;
}

// Remove the underline on the MouseLeave event.


private void OnMouseLeave(object sender, EventArgs e)
{
myHyperlink.TextDecorations = null;
}

See also
TextDecoration
Hyperlink
Optimizing WPF Application Performance
Create a Text Decoration
How to: Apply Transforms to Text
Article • 02/06/2023

Transforms can alter the display of text in your application. The following examples use
different types of rendering transforms to affect the display of text in a TextBlock
control.

Example
The following example shows text rotated about a specified point in the two-
dimensional x-y plane.

The following code example uses a RotateTransform to rotate text. An Angle value of 90
rotates the element 90 degrees clockwise.

XAML

<!-- Rotate the text 90 degrees using a RotateTransform. -->


<TextBlock FontFamily="Arial Black" FontSize="64" Foreground="Moccasin"
Margin ="80, 10, 0, 0">
Text Transforms
<TextBlock.RenderTransform>
<RotateTransform Angle="90" />
</TextBlock.RenderTransform>
</TextBlock>

The following example shows the second line of text scaled by 150% along the x-axis,
and the third line of text scaled by 150% along the y-axis.
The following code example uses a ScaleTransform to scale text from its original size.

XAML

<!-- Scale the text using a ScaleTransform. -->


<TextBlock
Name="textblockScaleMaster"
FontSize="32"
Foreground="SteelBlue"
Text="Scaled Text"
Margin="100, 0, 0, 0"
Grid.Column="0" Grid.Row="0">
</TextBlock>
<TextBlock
FontSize="32"
FontWeight="Bold"
Foreground="SteelBlue"
Text="{Binding Path=Text, ElementName=textblockScaleMaster}"
Margin="100, 0, 0, 0"
Grid.Column="0" Grid.Row="1">
<TextBlock.RenderTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.0" />
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock
FontSize="32"
FontWeight="Bold"
Foreground="SteelBlue"
Text="{Binding Path=Text, ElementName=textblockScaleMaster}"
Margin="100, 0, 0, 0"
Grid.Column="0" Grid.Row="2">
<TextBlock.RenderTransform>
<ScaleTransform ScaleX="1.0" ScaleY="1.5" />
</TextBlock.RenderTransform>
</TextBlock>

7 Note

Scaling text is not the same as increasing the font size of text. Font sizes are
calculated independently of each other in order to provide the best resolution at
different sizes. Scaled text, on the other hand, preserves the proportions of the
original-sized text.
The following example shows text skewed along the x-axis.

The following code example uses a SkewTransform to skew text. A skew, also known as a
shear, is a transformation that stretches the coordinate space in a non-uniform manner.
In this example, the two text strings are skewed -30° and 30° along the x-coordinate.

XAML

<!-- Skew the text using a SkewTransform. -->


<TextBlock
Name="textblockSkewMaster"
FontSize="32"
FontWeight="Bold"
Foreground="Maroon"
Text="Skewed Text"
Margin="125, 0, 0, 0"
Grid.Column="0" Grid.Row="0">
<TextBlock.RenderTransform>
<SkewTransform AngleX="-30" AngleY="0" />
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock
FontSize="32"
FontWeight="Bold"
Foreground="Maroon"
Text="{Binding Path=Text, ElementName=textblockSkewMaster}"
Margin="100, 0, 0, 0"
Grid.Column="0" Grid.Row="1">
<TextBlock.RenderTransform>
<SkewTransform AngleX="30" AngleY="0" />
</TextBlock.RenderTransform>
</TextBlock>

The following example shows text translated, or moved, along the x- and y-axis.

The following code example uses a TranslateTransform to offset text. In this example, a
slightly offset copy of text below the primary text creates a shadow effect.

XAML

<!-- Skew the text using a TranslateTransform. -->


<TextBlock
FontSize="32"
FontWeight="Bold"
Foreground="Black"
Text="{Binding Path=Text, ElementName=textblockTranslateMaster}"
Margin="100, 0, 0, 0"
Grid.Column="0" Grid.Row="0">
<TextBlock.RenderTransform>
<TranslateTransform X="2" Y="2" />
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock
Name="textblockTranslateMaster"
FontSize="32"
FontWeight="Bold"
Foreground="Coral"
Text="Translated Text"
Margin="100, 0, 0, 0"
Grid.Column="0" Grid.Row="0"/>

7 Note

The DropShadowBitmapEffect provides a rich set of features for providing shadow


effects. For more information, see Create Text with a Shadow.

See also
Apply Animations to Text
How to: Apply Animations to Text
Article • 02/06/2023

Animations can alter the display and appearance of text in your application. The
following examples use different types of animations to affect the display of text in a
TextBlock control.

Example
The following example uses a DoubleAnimation to animate the width of the text block.
The width value changes from the width of the text block to 0 over a duration of 10
seconds, and then reverses the width values and continues. This type of animation
creates a wipe effect.

XAML

<TextBlock
Name="MyWipedText"
Margin="20"
Width="480" Height="100" FontSize="48" FontWeight="Bold"
Foreground="Maroon">
This is wiped text

<!-- Animates the text block's width. -->


<TextBlock.Triggers>
<EventTrigger RoutedEvent="TextBlock.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="MyWipedText"
Storyboard.TargetProperty="(TextBlock.Width)"
To="0.0" Duration="0:0:10"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>

The following example uses a DoubleAnimation to animate the opacity of the text block.
The opacity value changes from 1.0 to 0 over a duration of 5 seconds, and then reverses
the opacity values and continues.

XAML
<TextBlock
Name="MyFadingText"
Margin="20"
Width="640" Height="100" FontSize="48" FontWeight="Bold"
Foreground="Maroon">
This is fading text

<!-- Animates the text block's opacity. -->


<TextBlock.Triggers>
<EventTrigger RoutedEvent="TextBlock.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="MyFadingText"
Storyboard.TargetProperty="(TextBlock.Opacity)"
From="1.0" To="0.0" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>

The following diagram shows the effect of the TextBlock control changing its opacity
from 1.00 to 0.00 during the 5-second interval defined by the Duration.

The following example uses a ColorAnimation to animate the foreground color of the
text block. The foreground color value changes from one color to a second color over a
duration of 5 seconds, and then reverses the color values and continues.

XAML

<TextBlock
Name="MyChangingColorText"
Margin="20"
Width="640" Height="100" FontSize="48" FontWeight="Bold">
This is changing color text
<TextBlock.Foreground>
<SolidColorBrush x:Name="MySolidColorBrush" Color="Maroon" />
</TextBlock.Foreground>

<!-- Animates the text block's color. -->


<TextBlock.Triggers>
<EventTrigger RoutedEvent="TextBlock.Loaded">
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetName="MySolidColorBrush"
Storyboard.TargetProperty="Color"
From="DarkOrange" To="SteelBlue" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>

The following example uses a DoubleAnimation to rotate the text block. The text block
performs a full rotation over a duration of 20 seconds, and then continues to repeat the
rotation.

XAML

<TextBlock
Name="MyRotatingText"
Margin="20"
Width="640" Height="100" FontSize="48" FontWeight="Bold" Foreground="Teal"
>
This is rotating text
<TextBlock.RenderTransform>
<RotateTransform x:Name="MyRotateTransform" Angle="0" CenterX="230"
CenterY="25"/>
</TextBlock.RenderTransform>

<!-- Animates the text block's rotation. -->


<TextBlock.Triggers>
<EventTrigger RoutedEvent="TextBlock.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="MyRotateTransform"
Storyboard.TargetProperty="(RotateTransform.Angle)"
From="0.0" To="360" Duration="0:0:10"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
See also
Animation Overview
How to: Create Text with a Shadow
Article • 02/06/2023

The examples in this section show how to create a shadow effect for displayed text.

Example
The DropShadowEffect object allows you to create a variety of drop shadow effects for
Windows Presentation Foundation (WPF) objects. The following example shows a drop
shadow effect applied to text. In this case, the shadow is a soft shadow, which means
the shadow color blurs.

You can control the width of a shadow by setting the ShadowDepth property. A value of
4.0 indicates a shadow width of 4 pixels. You can control the softness, or blur, of a

shadow by modifying the BlurRadius property. A value of 0.0 indicates no blurring. The
following code example shows how to create a soft shadow.

XAML

<!-- Soft single shadow. -->


<TextBlock
Text="Shadow Text"
Foreground="Teal">
<TextBlock.Effect>
<DropShadowEffect
ShadowDepth="4"
Direction="330"
Color="Black"
Opacity="0.5"
BlurRadius="4"/>
</TextBlock.Effect>
</TextBlock>

7 Note

These shadow effects do not go through the Windows Presentation Foundation


(WPF) text rendering pipeline. As a result, ClearType is disabled when using these
effects.
The following example shows a hard drop shadow effect applied to text. In this case, the
shadow is not blurred.

You can create a hard shadow by setting the BlurRadius property to 0.0 , which indicates
that no blurring is used. You can control the direction of the shadow by modifying the
Direction property. Set the directional value of this property to a degree between 0 and
360 . The following illustration shows the directional values of the Direction property
setting.

The following code example shows how to create a hard shadow.

XAML

<!-- Hard single shadow. -->


<TextBlock
Text="Shadow Text"
Foreground="Maroon">
<TextBlock.Effect>
<DropShadowEffect
ShadowDepth="6"
Direction="135"
Color="Maroon"
Opacity="0.35"
BlurRadius="0.0" />
</TextBlock.Effect>
</TextBlock>

Using a Blur Effect


A BlurBitmapEffect can be used to create a shadow-like effect that can be placed behind
a text object. A blur bitmap effect applied to text blurs the text evenly in all directions.

The following example shows a blur effect applied to text.

The following code example shows how to create a blur effect.

XAML

<!-- Shadow effect by creating a blur. -->


<TextBlock
Text="Shadow Text"
Foreground="Green"
Grid.Column="0" Grid.Row="0" >
<TextBlock.Effect>
<BlurEffect
Radius="8.0"
KernelType="Box"/>
</TextBlock.Effect>
</TextBlock>
<TextBlock
Text="Shadow Text"
Foreground="Maroon"
Grid.Column="0" Grid.Row="0" />

Using a Translate Transform


A TranslateTransform can be used to create a shadow-like effect that can be placed
behind a text object.

The following code example uses a TranslateTransform to offset text. In this example, a
slightly offset copy of text below the primary text creates a shadow effect.
The following code example shows how to create a transform for a shadow effect.

XAML

<!-- Shadow effect by creating a transform. -->


<TextBlock
Foreground="Black"
Text="Shadow Text"
Grid.Column="0" Grid.Row="0">
<TextBlock.RenderTransform>
<TranslateTransform X="3" Y="3" />
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock
Foreground="Coral"
Text="Shadow Text"
Grid.Column="0" Grid.Row="0">
</TextBlock>
How to: Create outlined text
Article • 06/02/2023

In most cases, when you're adding ornamentation to text strings in your Windows
Presentation Foundation (WPF) application, you are using text in terms of a collection of
discrete characters, or glyphs. For example, you could create a linear gradient brush and
apply it to the Foreground property of a TextBox object. When you display or edit the
text box, the linear gradient brush is automatically applied to the current set of
characters in the text string.

However, you can also convert text into Geometry objects, allowing you to create other
types of visually rich text. For example, you could create a Geometry object based on the
outline of a text string.

When text is converted to a Geometry object, it is no longer a collection of characters—


you cannot modify the characters in the text string. However, you can affect the
appearance of the converted text by modifying its stroke and fill properties. The stroke
refers to the outline of the converted text; the fill refers to the area inside the outline of
the converted text.

The following examples illustrate several ways of creating visual effects by modifying the
stroke and fill of converted text.

It is also possible to modify the bounding box rectangle, or highlight, of the converted
text. The following example illustrates a way to create visual effects by modifying the
stroke and highlight of converted text.
Example
The key to converting text to a Geometry object is to use the FormattedText object.
Once you have created this object, you can use the BuildGeometry and
BuildHighlightGeometry methods to convert the text to Geometry objects. The first
method returns the geometry of the formatted text; the second method returns the
geometry of the formatted text's bounding box. The following code example shows how
to create a FormattedText object and to retrieve the geometries of the formatted text
and its bounding box.

C#

/// <summary>
/// Create the outline geometry based on the formatted text.
/// </summary>
public void CreateText()
{
System.Windows.FontStyle fontStyle = FontStyles.Normal;
FontWeight fontWeight = FontWeights.Medium;

if (Bold == true) fontWeight = FontWeights.Bold;


if (Italic == true) fontStyle = FontStyles.Italic;

// Create the formatted text based on the properties set.


FormattedText formattedText = new FormattedText(
Text,
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface(
Font,
fontStyle,
fontWeight,
FontStretches.Normal),
FontSize,
System.Windows.Media.Brushes.Black // This brush does not matter
since we use the geometry of the text.
);

// Build the geometry object that represents the text.


_textGeometry = formattedText.BuildGeometry(new System.Windows.Point(0,
0));

// Build the geometry object that represents the text highlight.


if (Highlight == true)
{
_textHighLightGeometry = formattedText.BuildHighlightGeometry(new
System.Windows.Point(0, 0));
}
}

In order to display the retrieved the Geometry objects, you need to access the
DrawingContext of the object that's displaying the converted text. In these code
examples, this access is achieved by creating a custom control object that's derived from
a class that supports user-defined rendering.

To display Geometry objects in the custom control, provide an override for the
OnRender method. Your overridden method should use the DrawGeometry method to
draw the Geometry objects.

C#

/// <summary>
/// OnRender override draws the geometry of the text and optional highlight.
/// </summary>
/// <param name="drawingContext">Drawing context of the OutlineText control.
</param>
protected override void OnRender(DrawingContext drawingContext)
{
// Draw the outline based on the properties that are set.
drawingContext.DrawGeometry(Fill, new System.Windows.Media.Pen(Stroke,
StrokeThickness), _textGeometry);

// Draw the text highlight based on the properties that are set.
if (Highlight == true)
{
drawingContext.DrawGeometry(null, new
System.Windows.Media.Pen(Stroke, StrokeThickness), _textHighLightGeometry);
}
}

For the source of the example custom user control object, see OutlineTextControl.cs for
C# and OutlineTextControl.vb for Visual Basic .

See also
Drawing Formatted Text
How to: Draw Text to a Control's
Background
Article • 02/06/2023

You can draw text directly to the background of a control by converting a text string to a
FormattedText object, and then drawing the object to the control's DrawingContext. You
can also use this technique for drawing to the background of objects derived from
Panel, such as Canvas and StackPanel.

Example of controls with custom text backgrounds

Example
To draw to the background of a control, create a new DrawingBrush object and draw the
converted text to the object's DrawingContext. Then, assign the new DrawingBrush to
the control's background property.

The following code example shows how to create a FormattedText object and draw to
the background of a Label and Button object.

C#

// Handle the WindowLoaded event for the window.


private void WindowLoaded(object sender, EventArgs e)
{
// Update the background property of the label and button.
myLabel.Background = new DrawingBrush(DrawMyText("My Custom Label"));
myButton.Background = new DrawingBrush(DrawMyText("Display Text"));
}

// Convert the text string to a geometry and draw it to the control's


DrawingContext.
private Drawing DrawMyText(string textString)
{
// Create a new DrawingGroup of the control.
DrawingGroup drawingGroup = new DrawingGroup();

// Open the DrawingGroup in order to access the DrawingContext.


using (DrawingContext drawingContext = drawingGroup.Open())
{
// Create the formatted text based on the properties set.
FormattedText formattedText = new FormattedText(
textString,
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Comic Sans MS Bold"),
48,
System.Windows.Media.Brushes.Black // This brush does not matter
since we use the geometry of the text.
);

// Build the geometry object that represents the text.


Geometry textGeometry = formattedText.BuildGeometry(new
System.Windows.Point(20, 0));

// Draw a rounded rectangle under the text that is slightly larger


than the text.

drawingContext.DrawRoundedRectangle(System.Windows.Media.Brushes.PapayaWhip,
null, new Rect(new System.Windows.Size(formattedText.Width + 50,
formattedText.Height + 5)), 5.0, 5.0);

// Draw the outline based on the properties that are set.


drawingContext.DrawGeometry(System.Windows.Media.Brushes.Gold, new
System.Windows.Media.Pen(System.Windows.Media.Brushes.Maroon, 1.5),
textGeometry);

// Return the updated DrawingGroup content to be used by the


control.
return drawingGroup;
}
}

See also
FormattedText
Drawing Formatted Text
How to: Draw Text to a Visual
Article • 02/06/2023

The following example shows how to draw text to a DrawingVisual using a


DrawingContext object. A drawing context is returned by calling the RenderOpen
method of a DrawingVisual object. You can draw graphics and text into a drawing
context.

To draw text into the drawing context, use the DrawText method of a DrawingContext
object. When you are finished drawing content into the drawing context, call the Close
method to close the drawing context and persist the content.

Example
C#

// Create a DrawingVisual that contains text.


private DrawingVisual CreateDrawingVisualText()
{
// Create an instance of a DrawingVisual.
DrawingVisual drawingVisual = new DrawingVisual();

// Retrieve the DrawingContext from the DrawingVisual.


DrawingContext drawingContext = drawingVisual.RenderOpen();

// Draw a formatted text string into the DrawingContext.


drawingContext.DrawText(
new FormattedText("Click Me!",
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Verdana"),
36, System.Windows.Media.Brushes.Black),
new System.Windows.Point(200, 116));

// Close the DrawingContext to persist changes to the DrawingVisual.


drawingContext.Close();

return drawingVisual;
}

7 Note

For the complete code sample from which the preceding code example was
extracted, see Hit Test Using DrawingVisuals Sample .
How to: Use Special Characters in XAML
Article • 02/06/2023

Markup files that are created in Visual Studio are automatically saved in the Unicode
UTF-8 file format, which means that most special characters, such as accent marks, are
encoded correctly. However, there is a set of commonly-used special characters that are
handled differently. These special characters follow the World Wide Web Consortium
(W3C) XML standard for encoding .

The following table shows the syntax for encoding this set of special characters:

Character Syntax Description

< &lt; Less than symbol.

> &gt; Greater than sign.

& &amp; Ampersand symbol.

" &quot; Double quote symbol.

' &apos; Single quote symbol.

7 Note

If you create a markup file using a text editor, such as Windows Notepad, you must
save the file in the Unicode UTF-8 file format in order to preserve any encoded
special characters.

The following example shows how you can use special characters in text when creating
markup.

Example
XAML

<!-- Display special characters that require special encoding: < > & " -->
<TextBlock>
&lt; <!-- Less than symbol -->
&gt; <!-- Greater than symbol -->
&amp; <!-- Ampersand symbol -->
&quot; <!-- Double quote symbol -->
</TextBlock>
<!-- Display miscellaneous special characters -->
<TextBlock>
Cæsar <!-- AE dipthong symbol -->
© 2006 <!-- Copyright symbol -->
Español <!-- Tilde symbol -->
¥ <!-- Yen symbol -->
</TextBlock>
Printing and Print System Management
Article • 02/06/2023

Windows Vista and Microsoft .NET Framework introduce a new print path — an
alternative to Microsoft Windows Graphics Device Interface (GDI) printing — and a
vastly expanded set of print system management APIs.

In This Section
Printing Overview
A discussion of the new print path and APIs.

How-to Topics
A set of articles showing how to use the new print path and APIs.

See also
System.Printing
System.Printing.IndexedProperties
System.Printing.Interop
Documents in WPF
XPS Documents
Printing Overview
Article • 02/06/2023

With Microsoft .NET Framework, application developers using Windows Presentation


Foundation (WPF) have a rich new set of printing and print system management APIs.
With Windows Vista, some of these print system enhancements are also available to
developers creating Windows Forms applications and developers using unmanaged
code. At the core of this new functionality is the new XML Paper Specification (XPS) file
format and the XPS print path.

This topic contains the following sections.

About XPS
XPS is an electronic document format, a spool file format and a page description
language. It is an open document format that uses XML, Open Packaging Conventions
(OPC), and other industry standards to create cross-platform documents. XPS simplifies
the process by which digital documents are created, shared, printed, viewed, and
archived. For additional information on XPS, see XPS Documents.

Several techniques for printing XPS-based content using WPF are demonstrated in
Programmatically Print XPS Files. You may find it useful to reference these samples
during review of content contained in this topic. (Unmanaged code developers should
see documentation for the MXDC_ESCAPE function. Windows Forms developers must
use the API in the System.Drawing.Printing namespace which does not support the full
XPS print path, but does support a hybrid GDI-to-XPS print path. See Print Path
Architecture below.)

XPS Print Path


The XML Paper Specification (XPS) print path is a new Windows feature that redefines
how printing is handled in Windows applications. Because XPS can replace a document
presentation language (such as RTF), a print spooler format (such as WMF), and a page
description language (such as PCL or Postscript); the new print path maintains the XPS
format from application publication to the final processing in the print driver or device.

The XPS print path is built upon the XPS printer driver model (XPSDrv), which provides
several benefits for developers such as "what you see is what you get" (WYSIWYG)
printing, improved color support, and significantly improved print performance. (For
more on XPSDrv, see the Windows Driver Kit documentation.)
The operation of the print spooler for XPS documents is essentially the same as in
previous versions of Windows. However, it has been enhanced to support the XPS print
path in addition to the existing GDI print path. The new print path natively consumes an
XPS spool file. While user-mode printer drivers written for previous versions of Windows
will continue to work, an XPS printer driver (XPSDrv) is required in order to use the XPS
print path.

The benefits of the XPS print path are significant, and include:

WYSIWYG print support

Native support of advanced color profiles, which include 32 bits per channel (bpc),
CMYK, named-colors, n-inks, and native support of transparency and gradients.

Improved print performance for both .NET Framework and Win32 based
applications.

Industry standard XPS format.

For basic print scenarios, a simple and intuitive API is available with a single entry point
for user interface, configuration and job submission. For advanced scenarios, an
additional support is added for UI at all), synchronous or asynchronous printing, and
batch printing capabilities. Both options provide print support in full or partial trust
mode.

XPS was designed with extensibility in mind. By using the extensibility framework,
features and capabilities can be added to XPS in a modular manner. Extensibility
features include:

Print Schema. The public schema is updated regularly and enables rapid extension
of device capabilities. (See PrintTicket and PrintCapabilities below.)

Extensible Filter Pipeline. The XPS printer driver (XPSDrv) filter pipeline was
designed to enable both direct and scalable printing of XPS documents. For more
information, see XPSDrv Printer Drivers.

Print Path Architecture


While both Win32 and .NET Framework applications support XPS, Win32 and Windows
Forms applications use a GDI to XPS conversion in order to create XPS formatted
content for the XPS printer driver (XPSDrv). These applications are not required to use
the XPS print path, and can continue to use Enhanced Metafile (EMF) based printing.
However, most XPS features and enhancements are only available to applications that
target the XPS print path.
To enable the use of XPSDrv-based printers by Win32 and Windows Forms applications,
the XPS printer driver (XPSDrv) supports conversion of GDI to XPS format. The XPSDrv
model also provides a converter for XPS to GDI format so that Win32 applications can
print XPS Documents. For WPF applications, conversion of XPS to GDI format is done
automatically by the Write and WriteAsync methods of the XpsDocumentWriter class
whenever the target print queue of the write operation does not have an XPSDrv driver.
(Windows Forms applications cannot print XPS Documents.)

The following illustration depicts the print subsystem and defines the portions provided
by Microsoft, and the portions defined by software and hardware vendors:

Basic XPS Printing


WPF defines both a basic and advanced API. For those applications that do not require
extensive print customization or access to the complete XPS feature set, basic print
support is available. Basic print support is exposed through a print dialog control that
requires minimal configuration and features a familiar UI. Many XPS features are
available using this simplified print model.

PrintDialog
The System.Windows.Controls.PrintDialog control provides a single entry point for UI,
configuration, and XPS job submission. For information about how to instantiate and
use the control, see Invoke a Print Dialog.
Advanced XPS Printing
To access the complete set of XPS features, the advanced print API must be used.
Several relevant API are described in greater detail below. For a complete list of XPS
print path APIs, see the System.Windows.Xps and System.Printing namespace references.

PrintTicket and PrintCapabilities


The PrintTicket and PrintCapabilities classes are the foundation of the advanced XPS
features. Both types of objects are XML formatted structures of print-oriented features
such as collation, two-sided printing, stapling, etc. These structures are defined by the
print schema. A PrintTicket instructs a printer how to process a print job. The
PrintCapabilities class defines the capabilities of a printer. By querying the capabilities of
a printer, a PrintTicket can be created that takes full advantage of a printer's supported
features. Similarly, unsupported features can be avoided.

The following example demonstrates how to query the PrintCapabilities of a printer and
create a PrintTicket using code.

C#

// ---------------------- GetPrintTicketFromPrinter -----------------------


/// <summary>
/// Returns a PrintTicket based on the current default printer.</summary>
/// <returns>
/// A PrintTicket for the current local default printer.</returns>
private PrintTicket GetPrintTicketFromPrinter()
{
PrintQueue printQueue = null;

LocalPrintServer localPrintServer = new LocalPrintServer();

// Retrieving collection of local printer on user machine


PrintQueueCollection localPrinterCollection =
localPrintServer.GetPrintQueues();

System.Collections.IEnumerator localPrinterEnumerator =
localPrinterCollection.GetEnumerator();

if (localPrinterEnumerator.MoveNext())
{
// Get PrintQueue from first available printer
printQueue = (PrintQueue)localPrinterEnumerator.Current;
}
else
{
// No printer exist, return null PrintTicket
return null;
}
// Get default PrintTicket from printer
PrintTicket printTicket = printQueue.DefaultPrintTicket;

PrintCapabilities printCapabilites = printQueue.GetPrintCapabilities();

// Modify PrintTicket
if (printCapabilites.CollationCapability.Contains(Collation.Collated))
{
printTicket.Collation = Collation.Collated;
}

if ( printCapabilites.DuplexingCapability.Contains(
Duplexing.TwoSidedLongEdge) )
{
printTicket.Duplexing = Duplexing.TwoSidedLongEdge;
}

if
(printCapabilites.StaplingCapability.Contains(Stapling.StapleDualLeft))
{
printTicket.Stapling = Stapling.StapleDualLeft;
}

return printTicket;
}// end:GetPrintTicketFromPrinter()

PrintServer and PrintQueue


The PrintServer class represents a network print server and the PrintQueue class
represents a printer and the output job queue associated with it. Together, these APIs
allow advanced management of a server's print jobs. A PrintServer, or one of its derived
classes, is used to manage a PrintQueue. The AddJob method is used to insert a new
print job into the queue.

The following example demonstrates how to create a LocalPrintServer and access its
default PrintQueue by using code.

C#

// -------------------- GetPrintXpsDocumentWriter() -------------------


/// <summary>
/// Returns an XpsDocumentWriter for the default print queue.</summary>
/// <returns>
/// An XpsDocumentWriter for the default print queue.</returns>
private XpsDocumentWriter GetPrintXpsDocumentWriter()
{
// Create a local print server
LocalPrintServer ps = new LocalPrintServer();
// Get the default print queue
PrintQueue pq = ps.DefaultPrintQueue;

// Get an XpsDocumentWriter for the default print queue


XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(pq);
return xpsdw;
}// end:GetPrintXpsDocumentWriter()

XpsDocumentWriter
An XpsDocumentWriter, with its many the Write and WriteAsync methods, is used to
write XPS documents to a PrintQueue. For example, the Write(FixedPage, PrintTicket)
method is used to output an XPS document and PrintTicket synchronously. The
WriteAsync(FixedDocument, PrintTicket) method is used to output an XPS document
and PrintTicket asynchronously.

The following example demonstrates how to create an XpsDocumentWriter using code.

C#

// -------------------- GetPrintXpsDocumentWriter() -------------------


/// <summary>
/// Returns an XpsDocumentWriter for the default print queue.</summary>
/// <returns>
/// An XpsDocumentWriter for the default print queue.</returns>
private XpsDocumentWriter GetPrintXpsDocumentWriter()
{
// Create a local print server
LocalPrintServer ps = new LocalPrintServer();

// Get the default print queue


PrintQueue pq = ps.DefaultPrintQueue;

// Get an XpsDocumentWriter for the default print queue


XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(pq);
return xpsdw;
}// end:GetPrintXpsDocumentWriter()

The AddJob methods also provide ways to print. See Programmatically Print XPS Files.
for details.

GDI Print Path


While WPF applications natively support the XPS print path, Win32 and Windows Forms
applications can also take advantage of some XPS features. The XPS printer driver
(XPSDrv) can convert GDI based output to XPS format. For advanced scenarios, custom
conversion of content is supported using the Microsoft XPS Document Converter
(MXDC). Similarly, WPF applications can also output to the GDI print path by calling one
of the Write or WriteAsync methods of the XpsDocumentWriter class and designating a
non-XpsDrv printer as the target print queue.

For applications that do not require XPS functionality or support, the current GDI print
path remains unchanged.

For additional reference material on the GDI print path and the various XPS
conversion options, see Microsoft XPS Document Converter (MXDC) and XPSDrv
Printer Drivers.

XPSDrv Driver Model


The XPS print path improves spooler efficiency by using XPS as the native print spool
format when printing to an XPS -enabled printer or driver. The simplified spooling
process eliminates the need to generate an intermediate spool file, such as an EMF data
file, before the document is spooled. Through smaller spool file sizes, the XPS print path
can reduce network traffic and improve print performance.

EMF is a closed format that represents application output as a series of calls into GDI for
rendering services. Unlike EMF, the XPS spool format represents the actual document
without requiring further interpretation when output to an XPS-based printer driver
(XPSDrv). The drivers can operate directly on the data in the format. This capability
eliminates the data and color space conversions required when you use EMF files and
GDI-based print drivers.

Spool file sizes are usually reduced when you use XPS Documents that target an XPS
printer driver (XPSDrv) compared with their EMF equivalents; however, there are
exceptions:

A vector graphic that is very complex, multi-layered, or inefficiently written can be


larger than a bitmapped version of the same graphic.

For screen display purposes, XPS files embed device fonts as well as computer-
based fonts; whereas GDI spool files do not embed device fonts. But both kinds of
fonts are subsetted (see below) and printer drivers can remove the device fonts
before transmitting the file to the printer.

Spool size reduction is performed through several mechanisms:

Font subsetting. Only characters used within the actual document are stored in the
XPS file.
Advanced Graphics Support. Native support for transparency and gradient
primitives avoids rasterization of content in the XPS Document.

Identification of common resources. Resources that are used multiple times (such
as an image that represents a corporate logo) are treated as shared resources and
are loaded only once.

ZIP compression. All XPS documents use ZIP compression.

See also
PrintDialog
XpsDocumentWriter
XpsDocument
PrintTicket
PrintCapabilities
PrintServer
PrintQueue
How-to Topics
Documents in WPF
XPS Documents
Document Serialization and Storage
Microsoft XPS Document Converter (MXDC)
Printing How-to Topics
Article • 02/06/2023

The topics in this section demonstrate how to use the printing and print system
management features included with Windows Presentation Foundation (WPF) as well as
the new XML Paper Specification (XPS) print path.

In This Section
Invoke a Print Dialog
Instructions for XAML markup to declare a Microsoft Windows print dialog object and
using code to invoke the dialog from within a Windows Presentation Foundation (WPF)
application.

Clone a Printer
Instructions for how to install a second print queue with exactly the same properties as
an existing print queue.

Diagnose Problematic Print Job


Instructions for using the properties of print queues and print jobs to diagnose a print
job that is not printing.

Discover Whether a Print Job Can Be Printed At This Time of Day


Instructions for using the properties of print queues and print jobs to programmatically
decide what times of day the job can be printed.

Enumerate a Subset of Print Queues


Instructions for generating a list of printers having certain characteristics.

Get Print System Object Properties Without Reflection


Instructions for how to discover at runtime print system object's properties and their
types.

Programmatically Print XPS Files


Instructions for rapid printing of XML Paper Specification (XPS) files without the need for
a user interface (UI).

Remotely Survey the Status of Printers


Instructions for creating a utility that will survey printers to discover those experiencing
a paper jam or other problem.
Validate and Merge PrintTickets
Instructions for checking that a print ticket is valid and that it does not request anything
that is not supported by the printer.

See also
System.Printing
System.Printing.IndexedProperties
System.Printing.Interop
Printing Overview
Documents in WPF
XPS Documents
How to: Invoke a Print Dialog
Article • 02/06/2023

To provide the ability to print from you application, you can simply create and open a
PrintDialog object.

Example
The PrintDialog control provides a single entry point for UI, configuration, and XPS job
submission. The control is easy to use and can be instantiated by using Extensible
Application Markup Language (XAML) markup or code. The following example
demonstrates how to instantiate and open the control in code and how to print from it.
It also shows how to ensure that the dialog will give the user the option of setting a
specific range of pages. The example code assumes that there is a file
FixedDocumentSequence.xps in the root of the C: drive.

C#

private void InvokePrint(object sender, RoutedEventArgs e)


{
// Create the print dialog object and set options
PrintDialog pDialog = new PrintDialog();
pDialog.PageRangeSelection = PageRangeSelection.AllPages;
pDialog.UserPageRangeEnabled = true;

// Display the dialog. This returns true if the user presses the
Print button.
Nullable<Boolean> print = pDialog.ShowDialog();
if (print == true)
{
XpsDocument xpsDocument = new
XpsDocument("C:\\FixedDocumentSequence.xps", FileAccess.ReadWrite);
FixedDocumentSequence fixedDocSeq =
xpsDocument.GetFixedDocumentSequence();
pDialog.PrintDocument(fixedDocSeq.DocumentPaginator, "Test print
job");
}
}

Once the dialog is open, users will be able to select from the printers installed on their
computer. They will also have the option of selecting the Microsoft XPS Document
Writer to create an XML Paper Specification (XPS) file instead of printing.

7 Note
The System.Windows.Controls.PrintDialog control of WPF, which is discussed in
this topic, should not be confused with the System.Windows.Forms.PrintDialog
component of Windows Forms.

Strictly speaking, you can use the PrintDocument method without ever opening the
dialog. In that sense, the control can be used as an unseen printing component. But for
performance reasons, it would be better to use either the AddJob method or one of the
many Write and WriteAsync methods of the XpsDocumentWriter. For more about this,
see Programmatically Print XPS Files.

See also
PrintDialog
Documents in WPF
Printing Overview
Microsoft XPS Document Writer
How to: Clone a Printer
Article • 02/06/2023

Most businesses will, at some point, buy multiple printers of the same model. Typically,
these are all installed with virtually identical configuration settings. Installing each
printer can be time-consuming and error prone. The System.Printing.IndexedProperties
namespace and the InstallPrintQueue class that are exposed with Microsoft .NET
Framework makes it possible to instantly install any number of additional print queues
that are cloned from an existing print queue.

Example
In the example below, a second print queue is cloned from an existing print queue. The
second differs from the first only in its name, location, port, and shared status. The
major steps for doing this are as follows.

1. Create a PrintQueue object for the existing printer that is going to be cloned.

2. Create a PrintPropertyDictionary from the PropertiesCollection of the PrintQueue.


The Value property of each entry in this dictionary is an object of one of the types
derived from PrintProperty. There are two ways to set the value of an entry in this
dictionary.

Use the dictionary's Remove and Add methods to remove the entry and then
re-add it with the desired value.

Use the dictionary's SetProperty method.

The example below illustrates both ways.

3. Create a PrintBooleanProperty object and set its Name to "IsShared" and its Value
to true .

4. Use the PrintBooleanProperty object to be the value of the


PrintPropertyDictionary's "IsShared" entry.

5. Create a PrintStringProperty object and set its Name to "ShareName" and its Value
to an appropriate String.

6. Use the PrintStringProperty object to be the value of the PrintPropertyDictionary's


"ShareName" entry.
7. Create another PrintStringProperty object and set its Name to "Location" and its
Value to an appropriate String.

8. Use the second PrintStringProperty object to be the value of the


PrintPropertyDictionary's "Location" entry.

9. Create an array of Strings. Each item is the name of a port on the server.

10. Use InstallPrintQueue to install the new printer with the new values.

An example is below.

C#

LocalPrintServer myLocalPrintServer = new


LocalPrintServer(PrintSystemDesiredAccess.AdministrateServer);
PrintQueue sourcePrintQueue = myLocalPrintServer.DefaultPrintQueue;
PrintPropertyDictionary myPrintProperties =
sourcePrintQueue.PropertiesCollection;

// Share the new printer using Remove/Add methods


PrintBooleanProperty shared = new PrintBooleanProperty("IsShared", true);
myPrintProperties.Remove("IsShared");
myPrintProperties.Add("IsShared", shared);

// Give the new printer its share name using SetProperty method
PrintStringProperty theShareName = new PrintStringProperty("ShareName",
"\"Son of " + sourcePrintQueue.Name +"\"");
myPrintProperties.SetProperty("ShareName", theShareName);

// Specify the physical location of the new printer using Remove/Add methods
PrintStringProperty theLocation = new PrintStringProperty("Location", "the
supply room");
myPrintProperties.Remove("Location");
myPrintProperties.Add("Location", theLocation);

// Specify the port for the new printer


String[] port = new String[] { "COM1:" };

// Install the new printer on the local print server


PrintQueue clonedPrinter = myLocalPrintServer.InstallPrintQueue("My clone of
" + sourcePrintQueue.Name, "Xerox WCP 35 PS", port, "WinPrint",
myPrintProperties);
myLocalPrintServer.Commit();

// Report outcome
Console.WriteLine("{0} in {1} has been installed and shared as {2}",
clonedPrinter.Name, clonedPrinter.Location, clonedPrinter.ShareName);
Console.WriteLine("Press Return to continue ...");
Console.ReadLine();
See also
System.Printing.IndexedProperties
PrintPropertyDictionary
LocalPrintServer
PrintQueue
DictionaryEntry
Documents in WPF
Printing Overview
How to: Diagnose Problematic Print Job
Article • 02/06/2023

Network administrators often field complaints from users about print jobs that do not
print or print slowly. The rich set of print job properties exposed in the APIs of Microsoft
.NET Framework provide a means for performing a rapid remote diagnosis of print jobs.

Example
The major steps for creating this kind of utility are as follows.

1. Identify the print job that the user is complaining about. Users often cannot do this
precisely. They may not know the names of the print servers or printers. They may
describe the location of the printer in different terminology than was used in
setting its Location property. Accordingly, it is a good idea to generate a list of the
user's currently submitted jobs. If there is more than one, then communication
between the user and the print system administrator can be used to pinpoint the
job that is having problems. The substeps are as follows.

a. Obtain a list of all print servers.

b. Loop through the servers to query their print queues.

c. Within each pass of the server loop, loop through all the server's queues to
query their jobs

d. Within each pass of the queue loop, loop through its jobs and gather
identifying information about those that were submitted by the complaining
user.

2. When the problematic print job has been identified, examine relevant properties to
see what might be the problem. For example, is job in an error state or did the
printer servicing the queue go offline before the job could print?

The code below is series of code examples. The first code example contains the loop
through the print queues. (Step 1c above.) The variable myPrintQueues is the
PrintQueueCollection object for the current print server.

The code example begins by refreshing the current print queue object with
PrintQueue.Refresh. This ensures that the object's properties accurately represent the
state of the physical printer that it represents. Then the application gets the collection of
print jobs currently in the print queue by using GetPrintJobInfoCollection.
Next the application loops through the PrintSystemJobInfo collection and compares
each Submitter property with the alias of the complaining user. If they match, the
application adds identifying information about the job to the string that will be
presented. (The userName and jobList variables are initialized earlier in the application.)

C#

foreach (PrintQueue pq in myPrintQueues)


{
pq.Refresh();
PrintJobInfoCollection jobs = pq.GetPrintJobInfoCollection();
foreach (PrintSystemJobInfo job in jobs)
{
// Since the user may not be able to articulate which job is
problematic,
// present information about each job the user has submitted.
if (job.Submitter == userName)
{
atLeastOne = true;
jobList = jobList + "\nServer:" + line;
jobList = jobList + "\n\tQueue:" + pq.Name;
jobList = jobList + "\n\tLocation:" + pq.Location;
jobList = jobList + "\n\t\tJob: " + job.JobName + " ID: " +
job.JobIdentifier;
}
}// end for each print job
}// end for each print queue

The next code example picks up the application at Step 2. (See above.) The problematic
job has been identified and the application prompts for the information that will identify
it. From this information it creates PrintServer, PrintQueue, and PrintSystemJobInfo
objects.

At this point the application contains a branching structure corresponding to the two
ways of checking a print job's status:

You can read the flags of the JobStatus property which is of type PrintJobStatus.

You can read each relevant property such as IsBlocked and IsInError.

This example demonstrates both methods, so the user was previously prompted as to
which method to use and responded with "Y" if they wanted to use the flags of the
JobStatus property. See below for the details of the two methods. Finally, the application
uses a method called ReportQueueAndJobAvailability to report on whether the job can
be printed at this time of day. This method is discussed in Discover Whether a Print Job
Can Be Printed At This Time of Day.
C#

// When the problematic print job has been identified, enter information
about it.
Console.Write("\nEnter the print server hosting the job (including leading
slashes \\\\): " +
"\n(press Return for the current computer \\\\{0}): ",
Environment.MachineName);
String pServer = Console.ReadLine();
if (pServer == "")
{
pServer = "\\\\" +Environment.MachineName;
}
Console.Write("\nEnter the print queue hosting the job: ");
String pQueue = Console.ReadLine();
Console.Write("\nEnter the job ID: ");
Int16 jobID = Convert.ToInt16(Console.ReadLine());

// Create objects to represent the server, queue, and print job.


PrintServer hostingServer = new PrintServer(pServer,
PrintSystemDesiredAccess.AdministrateServer);
PrintQueue hostingQueue = new PrintQueue(hostingServer, pQueue,
PrintSystemDesiredAccess.AdministratePrinter);
PrintSystemJobInfo theJob = hostingQueue.GetJob(jobID);

if (useAttributesResponse == "Y")
{
TroubleSpotter.SpotTroubleUsingJobAttributes(theJob);
// TroubleSpotter class is defined in the complete example.
}
else
{
TroubleSpotter.SpotTroubleUsingProperties(theJob);
}

TroubleSpotter.ReportQueueAndJobAvailability(theJob);

To check print job status using the flags of the JobStatus property, you check each
relevant flag to see if it is set. The standard way to see if one bit is set in a set of bit flags
is to perform a logical AND operation with the set of flags as one operand and the flag
itself as the other. Since the flag itself has only one bit set, the result of the logical AND
is that, at most, that same bit is set. To find out whether it is or not, just compare the
result of the logical AND with the flag itself. For more information, see PrintJobStatus,
the & Operator (C# Reference), and FlagsAttribute.

For each attribute whose bit is set, the code reports this to the console screen and
sometimes suggests a way to respond. (The HandlePausedJob method that is called if
the job or queue is paused is discussed below.)

C#
// Check for possible trouble states of a print job using the flags of the
JobStatus property
internal static void SpotTroubleUsingJobAttributes(PrintSystemJobInfo
theJob)
{
if ((theJob.JobStatus & PrintJobStatus.Blocked) ==
PrintJobStatus.Blocked)
{
Console.WriteLine("The job is blocked.");
}
if (((theJob.JobStatus & PrintJobStatus.Completed) ==
PrintJobStatus.Completed)
||
((theJob.JobStatus & PrintJobStatus.Printed) ==
PrintJobStatus.Printed))
{
Console.WriteLine("The job has finished. Have user recheck all
output bins and be sure the correct printer is being checked.");
}
if (((theJob.JobStatus & PrintJobStatus.Deleted) ==
PrintJobStatus.Deleted)
||
((theJob.JobStatus & PrintJobStatus.Deleting) ==
PrintJobStatus.Deleting))
{
Console.WriteLine("The user or someone with administration rights to
the queue has deleted the job. It must be resubmitted.");
}
if ((theJob.JobStatus & PrintJobStatus.Error) == PrintJobStatus.Error)
{
Console.WriteLine("The job has errored.");
}
if ((theJob.JobStatus & PrintJobStatus.Offline) ==
PrintJobStatus.Offline)
{
Console.WriteLine("The printer is offline. Have user put it online
with printer front panel.");
}
if ((theJob.JobStatus & PrintJobStatus.PaperOut) ==
PrintJobStatus.PaperOut)
{
Console.WriteLine("The printer is out of paper of the size required
by the job. Have user add paper.");
}

if (((theJob.JobStatus & PrintJobStatus.Paused) ==


PrintJobStatus.Paused)
||
((theJob.HostingPrintQueue.QueueStatus & PrintQueueStatus.Paused) ==
PrintQueueStatus.Paused))
{
HandlePausedJob(theJob);
//HandlePausedJob is defined in the complete example.
}
if ((theJob.JobStatus & PrintJobStatus.Printing) ==
PrintJobStatus.Printing)
{
Console.WriteLine("The job is printing now.");
}
if ((theJob.JobStatus & PrintJobStatus.Spooling) ==
PrintJobStatus.Spooling)
{
Console.WriteLine("The job is spooling now.");
}
if ((theJob.JobStatus & PrintJobStatus.UserIntervention) ==
PrintJobStatus.UserIntervention)
{
Console.WriteLine("The printer needs human intervention.");
}
}//end SpotTroubleUsingJobAttributes

To check print job status using separate properties, you simply read each property and,
if the property is true , report to the console screen and possibly suggest a way to
respond. (The HandlePausedJob method that is called if the job or queue is paused is
discussed below.)

C#

// Check for possible trouble states of a print job using its properties
internal static void SpotTroubleUsingProperties(PrintSystemJobInfo theJob)
{
if (theJob.IsBlocked)
{
Console.WriteLine("The job is blocked.");
}
if (theJob.IsCompleted || theJob.IsPrinted)
{
Console.WriteLine("The job has finished. Have user recheck all
output bins and be sure the correct printer is being checked.");
}
if (theJob.IsDeleted || theJob.IsDeleting)
{
Console.WriteLine("The user or someone with administration rights to
the queue has deleted the job. It must be resubmitted.");
}
if (theJob.IsInError)
{
Console.WriteLine("The job has errored.");
}
if (theJob.IsOffline)
{
Console.WriteLine("The printer is offline. Have user put it online
with printer front panel.");
}
if (theJob.IsPaperOut)
{
Console.WriteLine("The printer is out of paper of the size required
by the job. Have user add paper.");
}

if (theJob.IsPaused || theJob.HostingPrintQueue.IsPaused)
{
HandlePausedJob(theJob);
//HandlePausedJob is defined in the complete example.
}

if (theJob.IsPrinting)
{
Console.WriteLine("The job is printing now.");
}
if (theJob.IsSpooling)
{
Console.WriteLine("The job is spooling now.");
}
if (theJob.IsUserInterventionRequired)
{
Console.WriteLine("The printer needs human intervention.");
}
}//end SpotTroubleUsingProperties

The HandlePausedJob method enables the application's user to remotely resume


paused jobs. Because there might be a good reason why the print queue was paused,
the method begins by prompting for a user decision about whether to resume it. If the
answer is "Y", then the PrintQueue.Resume method is called.

Next the user is prompted to decide if the job itself should be resumed, just in case it is
paused independently of the print queue. (Compare PrintQueue.IsPaused and
PrintSystemJobInfo.IsPaused.) If the answer is "Y", then PrintSystemJobInfo.Resume is
called; otherwise Cancel is called.

C#

internal static void HandlePausedJob(PrintSystemJobInfo theJob)


{
// If there's no good reason for the queue to be paused, resume it and
// give user choice to resume or cancel the job.
Console.WriteLine("The user or someone with administrative rights to the
queue" +
"\nhas paused the job or queue." +
"\nResume the queue? (Has no effect if queue is not paused.)" +
"\nEnter \"Y\" to resume, otherwise press return: ");
String resume = Console.ReadLine();
if (resume == "Y")
{
theJob.HostingPrintQueue.Resume();
// It is possible the job is also paused. Find out how the user
wants to handle that.
Console.WriteLine("Does user want to resume print job or cancel it?"
+
"\nEnter \"Y\" to resume (any other key cancels the print job):
");
String userDecision = Console.ReadLine();
if (userDecision == "Y")
{
theJob.Resume();
}
else
{
theJob.Cancel();
}
}//end if the queue should be resumed
}//end HandlePausedJob

See also
PrintJobStatus
PrintSystemJobInfo
FlagsAttribute
PrintQueue
& Operator (C# Reference)
Documents in WPF
Printing Overview
How to: Discover Whether a Print Job
Can Be Printed At This Time of Day
Article • 02/06/2023

Print queues are not always available for 24 hours a day. They have start and end time
properties that can be set to make them unavailable at certain times of day. This feature
can be used, for example, to reserve a printer for the exclusive use of a certain
department after 5 P.M.. That department would have a different queue servicing the
printer than other departments use. The queue for the other departments would be set
to be unavailable after 5 P.M., while queue for the favored department could be set to
be available at all times.

Moreover, print jobs themselves can be set to be printable only within a specified span
of time.

The PrintQueue and PrintSystemJobInfo classes exposed in the APIs of Microsoft .NET
Framework provide a means for remotely checking whether a given print job can print
on a given queue at the current time.

Example
The example below is a sample that can diagnose problems with a print job.

There are two major steps for this kind of function as follows.

1. Read the StartTimeOfDay and UntilTimeOfDay properties of the PrintQueue to


determine whether the current time is between them.

2. Read the StartTimeOfDay and UntilTimeOfDay properties of the


PrintSystemJobInfo to determine whether the current time is between them.

But complications arise from the fact that these properties are not DateTime objects.
Instead they are Int32 objects that express the time of day as the number of minutes
since midnight. Moreover, this is not midnight in the current time zone, but midnight
UTC (Coordinated Universal Time).

The first code example presents the static method ReportQueueAndJobAvailability,


which is passed a PrintSystemJobInfo and calls helper methods to determine whether
the job can print at the current time and, if not, when it can print. Notice that a
PrintQueue is not passed to the method. This is because the PrintSystemJobInfo
includes a reference to the queue in its HostingPrintQueue property.
The subordinate methods include the overloaded ReportAvailabilityAtThisTime method
which can take either a PrintQueue or a PrintSystemJobInfo as a parameter. There is also
a TimeConverter.ConvertToLocalHumanReadableTime. All of these methods are
discussed below.

The ReportQueueAndJobAvailability method begins by checking to see if either the


queue or the print job is unavailable at this time. If either of them is unavailable, it then
checks to see if the queue unavailable. If it is not available, then the method reports this
fact and the time when the queue will become available again. It then checks the job
and if it is unavailable, it reports the next time span when it when it can print. Finally, the
method reports the earliest time when the job can print. This is the later of following
two times.

The time when the print queue is next available.

The time when the print job is next available.

When reporting times of day, the ToShortTimeString method is also called because this
method suppresses the years, months, and days from the output. You cannot restrict the
availability of either a print queue or a print job to particular years, months, or days.

C#

internal static void ReportQueueAndJobAvailability(PrintSystemJobInfo


theJob)
{
if (!(ReportAvailabilityAtThisTime(theJob.HostingPrintQueue) &&
ReportAvailabilityAtThisTime(theJob)))
{
if (!ReportAvailabilityAtThisTime(theJob.HostingPrintQueue))
{
Console.WriteLine("\nThat queue is not available at this time of
day." +
"\nJobs in the queue will start printing again at {0}",

TimeConverter.ConvertToLocalHumanReadableTime(theJob.HostingPrintQueue.Start
TimeOfDay).ToShortTimeString());
// TimeConverter class is defined in the complete sample
}

if (!ReportAvailabilityAtThisTime(theJob))
{
Console.WriteLine("\nThat job is set to print only between {0}
and {1}",

TimeConverter.ConvertToLocalHumanReadableTime(theJob.StartTimeOfDay).ToShort
TimeString(),

TimeConverter.ConvertToLocalHumanReadableTime(theJob.UntilTimeOfDay).ToShort
TimeString());
}
Console.WriteLine("\nThe job will begin printing as soon as it
reaches the top of the queue after:");
if (theJob.StartTimeOfDay > theJob.HostingPrintQueue.StartTimeOfDay)
{

Console.WriteLine(TimeConverter.ConvertToLocalHumanReadableTime(theJob.Start
TimeOfDay).ToShortTimeString());
}
else
{

Console.WriteLine(TimeConverter.ConvertToLocalHumanReadableTime(theJob.Hosti
ngPrintQueue.StartTimeOfDay).ToShortTimeString());
}
}//end if at least one is not available
}//end ReportQueueAndJobAvailability

The two overloads of the ReportAvailabilityAtThisTime method are identical except for
the type passed to them, so only the PrintQueue version is presented below.

7 Note

The fact that the methods are identical except for type raises the question of why
the sample does not create a generic method ReportAvailabilityAtThisTime<T>.
The reason is that such a method would have to be restricted to a class that has the
StartTimeOfDay and UntilTimeOfDay properties that the method calls, but a
generic method can only be restricted to a single class and the only class common
to both PrintQueue and PrintSystemJobInfo in the inheritance tree is
PrintSystemObject which has no such properties.

The ReportAvailabilityAtThisTime method (presented in the code example below)


begins by initializing a Boolean sentinel variable to true . It will be reset to false , if the
queue is not available.

Next, the method checks to see if the start and "until" times are identical. If they are, the
queue is always available, so the method returns true .

If the queue is not available all the time, the method uses the static UtcNow property to
get the current time as a DateTime object. (We do not need local time because the
StartTimeOfDay and UntilTimeOfDay properties are themselves in UTC time.)

However, these two properties are not DateTime objects. They are Int32s expressing the
time as the number of minutes-after-UTC-midnight. So we do have to convert our
DateTime object to minutes-after-midnight. When that is done, the method simply
checks to see whether "now" is between the queue's start and "until" times, sets the
sentinel to false if "now" is not between the two times, and returns the sentinel.

C#

private static Boolean ReportAvailabilityAtThisTime(PrintQueue pq)


{
Boolean available = true;
if (pq.StartTimeOfDay != pq.UntilTimeOfDay) // If the printer is not
available 24 hours a day
{
DateTime utcNow = DateTime.UtcNow;
Int32 utcNowAsMinutesAfterMidnight = (utcNow.TimeOfDay.Hours * 60) +
utcNow.TimeOfDay.Minutes;

// If now is not within the range of available times . . .


if (!((pq.StartTimeOfDay < utcNowAsMinutesAfterMidnight)
&&
(utcNowAsMinutesAfterMidnight < pq.UntilTimeOfDay)))
{
available = false;
}
}
return available;
}//end ReportAvailabilityAtThisTime

The TimeConverter.ConvertToLocalHumanReadableTime method (presented in the


code example below) does not use any methods introduced with Microsoft .NET
Framework, so the discussion is brief. The method has a double conversion task: it must
take an integer expressing minutes-after-midnight and convert it to a human-readable
time and it must convert this to the local time. It accomplishes this by first creating a
DateTime object that is set to midnight UTC and then it uses the AddMinutes method to
add the minutes that were passed to the method. This returns a new DateTime
expressing the original time that was passed to the method. The ToLocalTime method
then converts this to local time.

C#

class TimeConverter
{
// Convert time as minutes past UTC midnight into human readable time in
local time zone.
internal static DateTime ConvertToLocalHumanReadableTime(Int32
timeInMinutesAfterUTCMidnight)
{
// Construct a UTC midnight object.
// Must start with current date so that the local Daylight Savings
system, if any, will be taken into account.
DateTime utcNow = DateTime.UtcNow;
DateTime utcMidnight = new DateTime(utcNow.Year, utcNow.Month,
utcNow.Day, 0, 0, 0, DateTimeKind.Utc);

// Add the minutes passed into the method in order to get the
intended UTC time.
Double minutesAfterUTCMidnight =
(Double)timeInMinutesAfterUTCMidnight;
DateTime utcTime = utcMidnight.AddMinutes(minutesAfterUTCMidnight);

// Convert to local time.


DateTime localTime = utcTime.ToLocalTime();

return localTime;
}// end ConvertToLocalHumanReadableTime
}//end TimeConverter class

See also
DateTime
PrintSystemJobInfo
PrintQueue
Documents in WPF
Printing Overview
How to: Enumerate a Subset of Print
Queues
Article • 02/06/2023

A common situation faced by information technology (IT) professionals managing a


company-wide set of printers is to generate a list of printers having certain
characteristics. This functionality is provided by the GetPrintQueues method of a
PrintServer object and the EnumeratedPrintQueueTypes enumeration.

Example
In the example below, the code begins by creating an array of flags that specify the
characteristics of the print queues we want to list. In this example, we are looking for
print queues that are installed locally on the print server and are shared. The
EnumeratedPrintQueueTypes enumeration provides many other possibilities.

The code then creates a LocalPrintServer object, a class derived from PrintServer. The
local print server is the computer on which the application is running.

The last significant step is to pass the array to the GetPrintQueues method.

Finally, the results are presented to the user.

C#

// Specify that the list will contain only the print queues that are
installed as local and are shared
EnumeratedPrintQueueTypes[] enumerationFlags =
{EnumeratedPrintQueueTypes.Local,

EnumeratedPrintQueueTypes.Shared};

LocalPrintServer printServer = new LocalPrintServer();

//Use the enumerationFlags to filter out unwanted print queues


PrintQueueCollection printQueuesOnLocalServer =
printServer.GetPrintQueues(enumerationFlags);

Console.WriteLine("These are your shared, local print queues:\n\n");

foreach (PrintQueue printer in printQueuesOnLocalServer)


{
Console.WriteLine("\tThe shared printer " + printer.Name + " is located
at " + printer.Location + "\n");
}
Console.WriteLine("Press enter to continue.");
Console.ReadLine();

You could extend this example by having the foreach loop that steps through each print
queue do further screening. For example, you could screen out printers that do not
support two-sided printing by having the loop call each print queue's
GetPrintCapabilities method and test the returned value for the presence of duplexing.

See also
GetPrintQueues
PrintServer
LocalPrintServer
EnumeratedPrintQueueTypes
PrintQueue
GetPrintCapabilities
Documents in WPF
Printing Overview
Microsoft XPS Document Writer
How to: Get Print System Object
Properties Without Reflection
Article • 02/06/2023

Using reflection to itemize the properties (and the types of those properties) on an
object can slow application performance. The System.Printing.IndexedProperties
namespace provides a means to getting this information without using reflection.

Example
The steps for doing this are as follows.

1. Create an instance of the type. In the example below, the type is the PrintQueue
type that ships with Microsoft .NET Framework, but nearly identical code should
work for types that you derive from PrintSystemObject.

2. Create a PrintPropertyDictionary from the type's PropertiesCollection. The Value


property of each entry in this dictionary is an object of one of the types derived
from PrintProperty.

3. Enumerate the members of the dictionary. For each of them, do the following.

4. Up-cast the value of each entry to PrintProperty and use it to create a


PrintProperty object.

5. Get the type of the Value of each of the PrintProperty object.

C#

// Enumerate the properties, and their types, of a queue without using


Reflection
LocalPrintServer localPrintServer = new LocalPrintServer();
PrintQueue defaultPrintQueue = LocalPrintServer.GetDefaultPrintQueue();

PrintPropertyDictionary printQueueProperties =
defaultPrintQueue.PropertiesCollection;

Console.WriteLine("These are the properties, and their types, of {0}, a


{1}", defaultPrintQueue.Name, defaultPrintQueue.GetType().ToString() +"\n");

foreach (DictionaryEntry entry in printQueueProperties)


{
PrintProperty property = (PrintProperty)entry.Value;
if (property.Value != null)
{
Console.WriteLine(property.Name + "\t(Type: {0})",
property.Value.GetType().ToString());
}
}
Console.WriteLine("\n\nPress Return to continue...");
Console.ReadLine();

See also
PrintProperty
PrintSystemObject
System.Printing.IndexedProperties
PrintPropertyDictionary
LocalPrintServer
PrintQueue
DictionaryEntry
Documents in WPF
Printing Overview
How to: Programmatically Print XPS
Files
Article • 07/27/2022

You can use one overload of the AddJob method to print XML Paper Specification (XPS)
files without opening a PrintDialog or, in principle, any user interface (UI) at all.

You can also print XPS files using the many XpsDocumentWriter.Write and
XpsDocumentWriter.WriteAsync methods. For more information, see Printing an XPS
Document.

Another way of printing XPS is to use the PrintDialog.PrintDocument or


PrintDialog.PrintVisual methods. See Invoke a Print Dialog.

Example
The main steps to using the three-parameter AddJob(String, String, Boolean) method
are as follows. The example below gives details.

1. Determine if the printer is an XPSDrv printer. See Printing Overview for more about
XPSDrv.

2. If the printer is not an XPSDrv printer, set the thread's apartment to single thread.

3. Instantiate a print server and print queue object.

4. Call the method, specifying a job name, the file to be printed, and a Boolean flag
indicating whether or not the printer is an XPSDrv printer.

The example below shows how to batch print all XPS files in a directory. Although the
application prompts the user to specify the directory, the three-parameter
AddJob(String, String, Boolean) method does not require a user interface (UI). It can be
used in any code path where you have an XPS file name and path that you can pass to
it.

The three-parameter AddJob(String, String, Boolean) overload of AddJob must run in a


single thread apartment whenever the Boolean parameter is false , which it must be
when a non-XPSDrv printer is being used. However, the default apartment state for .NET
is multiple thread. This default must be reversed since the example assumes a non-
XPSDrv printer.
There are two ways to change the default. One way is to simply add the
STAThreadAttribute (that is, " [System.STAThreadAttribute()] ") just above the first line of
the application's Main method (usually " static void Main(string[] args) "). However,
many applications require that the Main method have a multi-threaded apartment state,
so there is a second method: put the call to AddJob(String, String, Boolean) in a separate
thread whose apartment state is set to STA with SetApartmentState. The example below
uses this second technique.

Accordingly, the example begins by instantiating a Thread object and passing it a


PrintXPS method as the ThreadStart parameter. (The PrintXPS method is defined later in
the example.) Next the thread is set to a single thread apartment. The only remaining
code of the Main method starts the new thread.

The meat of the example is in the static BatchXPSPrinter.PrintXPS method. After


creating a print server and queue, the method prompts the user for a directory
containing XPS files. After validating the existence of the directory and the presence of
*.xps files in it, the method adds each such file to the print queue. The example assumes
that the printer is non-XPSDrv, so we are passing false to the last parameter of
AddJob(String, String, Boolean) method. For this reason, the method will validate the
XPS markup in the file before it attempts to convert it to the printer's page description
language. If the validation fails, an exception is thrown. The example code will catch the
exception, notify the user about it, and then go on to process the next XPS file.

C#

class Program
{
[System.MTAThreadAttribute()] // Added for clarity, but this line is
redundant because MTA is the default.
static void Main(string[] args)
{
// Create the secondary thread and pass the printing method for
// the constructor's ThreadStart delegate parameter. The
BatchXPSPrinter
// class is defined below.
Thread printingThread = new Thread(BatchXPSPrinter.PrintXPS);

// Set the thread that will use PrintQueue.AddJob to single


threading.
printingThread.SetApartmentState(ApartmentState.STA);

// Start the printing thread. The method passed to the Thread


// constructor will execute.
printingThread.Start();
}//end Main
}//end Program class
public class BatchXPSPrinter
{
public static void PrintXPS()
{
// Create print server and print queue.
LocalPrintServer localPrintServer = new LocalPrintServer();
PrintQueue defaultPrintQueue =
LocalPrintServer.GetDefaultPrintQueue();

// Prompt user to identify the directory, and then create the


directory object.
Console.Write("Enter the directory containing the XPS files: ");
String directoryPath = Console.ReadLine();
DirectoryInfo dir = new DirectoryInfo(directoryPath);

// If the user mistyped, end the thread and return to the Main
thread.
if (!dir.Exists)
{
Console.WriteLine("There is no such directory.");
}
else
{
// If there are no XPS files in the directory, end the thread
// and return to the Main thread.
if (dir.GetFiles("*.xps").Length == 0)
{
Console.WriteLine("There are no XPS files in the
directory.");
}
else
{
Console.WriteLine("\nJobs will now be added to the print
queue.");
Console.WriteLine("If the queue is not paused and the
printer is working, jobs will begin printing.");

// Batch process all XPS files in the directory.


foreach (FileInfo f in dir.GetFiles("*.xps"))
{
String nextFile = directoryPath + "\\" + f.Name;
Console.WriteLine("Adding {0} to queue.", nextFile);

try
{
// Print the Xps file while providing XPS validation
and progress notifications.
PrintSystemJobInfo xpsPrintJob =
defaultPrintQueue.AddJob(f.Name, nextFile, false);
}
catch (PrintJobException e)
{
Console.WriteLine("\n\t{0} could not be added to the
print queue.", f.Name);
if (e.InnerException.Message == "File contains
corrupted data.")
{
Console.WriteLine("\tIt is not a valid XPS file.
Use the isXPS Conformance Tool to debug it.");
}
Console.WriteLine("\tContinuing with next XPS
file.\n");
}
}// end for each XPS file
}//end if there are no XPS files in the directory
}//end if the directory does not exist

Console.WriteLine("Press Enter to end program.");


Console.ReadLine();
}// end PrintXPS method
}// end BatchXPSPrinter class

If you are using an XPSDrv printer, then you can set the final parameter to true . In that
case, since XPS is the printer's page description language, the method will send the file
to the printer without validating it or converting it to another page description
language. If you are uncertain at design time whether the application will be using an
XPSDrv printer, you can modify the application to have it read the IsXpsDevice property
and branch according to what it finds.

Since there will initially be few XPSDrv printers available immediately after the release of
Windows Vista and Microsoft .NET Framework, you may need to disguise a non-XPSDrv
printer as an XPSDrv printer. To do so, add Pipelineconfig.xml to the list of files in the
following registry key of the computer running your application:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Environments\Windo
ws NT x86\Drivers\Version-3\<PseudoXPSPrinter>\DependentFiles

where <PseudoXPSPrinter> is any print queue. The machine must then be rebooted.

This disguise will enable you to pass true as the final parameter of AddJob(String,
String, Boolean) without causing an exception, but since <PseudoXPSPrinter> is not
really an XPSDrv printer, only garbage will print.

7 Note

For simplicity, the example above uses the presence of an *.xps extension as its test
that a file is XPS. However, XPS files do not have to have this extension. The
isXPS.exe (isXPS Conformance Tool) is one way of testing a file for XPS validity.
See also
PrintQueue
AddJob
ApartmentState
STAThreadAttribute
XPS Documents
Printing an XPS Document
Managed and Unmanaged Threading
isXPS.exe (isXPS Conformance Tool)
Documents in WPF
Printing Overview
How to: Remotely Survey the Status of
Printers
Article • 02/06/2023

At any given time at medium and large companies there may be multiple printers that
are not working due to a paper jam or being out of paper or some other problematic
situation. The rich set of printer properties exposed in the APIs of Microsoft .NET
Framework provide a means for performing a rapid survey of the states of printers.

Example
The major steps for creating this kind of utility are as follows.

1. Obtain a list of all print servers.

2. Loop through the servers to query their print queues.

3. Within each pass of the server loop, loop through all the server's queues and read
each property that might indicate that the queue is not currently working.

The code below is a series of snippets. For simplicity, this example assumes that there is
a CRLF-delimited list of print servers. The variable fileOfPrintServers is a StreamReader
object for this file. Since each server name is on its own line, any call of ReadLine gets
the name of the next server and moves the StreamReader's cursor to the beginning of
the next line.

Within the outer loop, the code creates a PrintServer object for the latest print server
and specifies that the application is to have administrative rights to the server.

7 Note

If there are a lot of servers, you can improve performance by using the
PrintServer(String, String[], PrintSystemDesiredAccess) constructors that only
initialize the properties you are going to need.

The example then uses GetPrintQueues to create a collection of all of the server's
queues and begins to loop through them. This inner loop contains a branching structure
corresponding to the two ways of checking a printer's status:
You can read the flags of the QueueStatus property which is of type
PrintQueueStatus.

You can read each relevant property such as IsOutOfPaper, and IsPaperJammed.

This example demonstrates both methods, so the user was previously prompted as to
which method to use and responded with "y" if they wanted to use the flags of the
QueueStatus property. See below for the details of the two methods.

Finally, the results are presented to the user.

C#

// Survey queue status for every queue on every print server


String line;
String statusReport = "\n\nAny problem states are indicated below:\n\n";
while ((line = fileOfPrintServers.ReadLine()) != null)
{
PrintServer myPS = new PrintServer(line,
PrintSystemDesiredAccess.AdministrateServer);
PrintQueueCollection myPrintQueues = myPS.GetPrintQueues();
statusReport = statusReport + "\n" + line;
foreach (PrintQueue pq in myPrintQueues)
{
pq.Refresh();
statusReport = statusReport + "\n\t" + pq.Name + ":";
if (useAttributesResponse == "y")
{
TroubleSpotter.SpotTroubleUsingQueueAttributes(ref
statusReport, pq);
// TroubleSpotter class is defined in the complete example.
}
else
{
TroubleSpotter.SpotTroubleUsingProperties(ref statusReport,
pq);
}
}// end for each print queue
}// end while list of print servers is not yet exhausted

fileOfPrintServers.Close();
Console.WriteLine(statusReport);
Console.WriteLine("\nPress Return to continue.");
Console.ReadLine();

To check printer status using the flags of the QueueStatus property, you check each
relevant flag to see if it is set. The standard way to see if one bit is set in a set of bit flags
is to perform a logical AND operation with the set of flags as one operand and the flag
itself as the other. Since the flag itself has only one bit set, the result of the logical AND
is that, at most, that same bit is set. To find out whether it is or not, just compare the
result of the logical AND with the flag itself. For more information, see
PrintQueueStatus, the & Operator (C# Reference), and FlagsAttribute.

For each attribute whose bit is set, the code adds a notice to the final report that will be
presented to the user. (The ReportAvailabilityAtThisTime method that is called at the
end of the code is discussed below.)

C#

// Check for possible trouble states of a printer using the flags of the
QueueStatus property
internal static void SpotTroubleUsingQueueAttributes(ref String
statusReport, PrintQueue pq)
{
if ((pq.QueueStatus & PrintQueueStatus.PaperProblem) ==
PrintQueueStatus.PaperProblem)
{
statusReport = statusReport + "Has a paper problem. ";
}
if ((pq.QueueStatus & PrintQueueStatus.NoToner) ==
PrintQueueStatus.NoToner)
{
statusReport = statusReport + "Is out of toner. ";
}
if ((pq.QueueStatus & PrintQueueStatus.DoorOpen) ==
PrintQueueStatus.DoorOpen)
{
statusReport = statusReport + "Has an open door. ";
}
if ((pq.QueueStatus & PrintQueueStatus.Error) == PrintQueueStatus.Error)
{
statusReport = statusReport + "Is in an error state. ";
}
if ((pq.QueueStatus & PrintQueueStatus.NotAvailable) ==
PrintQueueStatus.NotAvailable)
{
statusReport = statusReport + "Is not available. ";
}
if ((pq.QueueStatus & PrintQueueStatus.Offline) ==
PrintQueueStatus.Offline)
{
statusReport = statusReport + "Is off line. ";
}
if ((pq.QueueStatus & PrintQueueStatus.OutOfMemory) ==
PrintQueueStatus.OutOfMemory)
{
statusReport = statusReport + "Is out of memory. ";
}
if ((pq.QueueStatus & PrintQueueStatus.PaperOut) ==
PrintQueueStatus.PaperOut)
{
statusReport = statusReport + "Is out of paper. ";
}
if ((pq.QueueStatus & PrintQueueStatus.OutputBinFull) ==
PrintQueueStatus.OutputBinFull)
{
statusReport = statusReport + "Has a full output bin. ";
}
if ((pq.QueueStatus & PrintQueueStatus.PaperJam) ==
PrintQueueStatus.PaperJam)
{
statusReport = statusReport + "Has a paper jam. ";
}
if ((pq.QueueStatus & PrintQueueStatus.Paused) ==
PrintQueueStatus.Paused)
{
statusReport = statusReport + "Is paused. ";
}
if ((pq.QueueStatus & PrintQueueStatus.TonerLow) ==
PrintQueueStatus.TonerLow)
{
statusReport = statusReport + "Is low on toner. ";
}
if ((pq.QueueStatus & PrintQueueStatus.UserIntervention) ==
PrintQueueStatus.UserIntervention)
{
statusReport = statusReport + "Needs user intervention. ";
}

// Check if queue is even available at this time of day


// The method below is defined in the complete example.
ReportAvailabilityAtThisTime(ref statusReport, pq);
}

To check printer status using each property, you simply read each property and add a
note to the final report that will be presented to the user if the property is true . (The
ReportAvailabilityAtThisTime method that is called at the end of the code is discussed
below.)

C#

// Check for possible trouble states of a printer using its properties


internal static void SpotTroubleUsingProperties(ref String statusReport,
PrintQueue pq)
{
if (pq.HasPaperProblem)
{
statusReport = statusReport + "Has a paper problem. ";
}
if (!(pq.HasToner))
{
statusReport = statusReport + "Is out of toner. ";
}
if (pq.IsDoorOpened)
{
statusReport = statusReport + "Has an open door. ";
}
if (pq.IsInError)
{
statusReport = statusReport + "Is in an error state. ";
}
if (pq.IsNotAvailable)
{
statusReport = statusReport + "Is not available. ";
}
if (pq.IsOffline)
{
statusReport = statusReport + "Is off line. ";
}
if (pq.IsOutOfMemory)
{
statusReport = statusReport + "Is out of memory. ";
}
if (pq.IsOutOfPaper)
{
statusReport = statusReport + "Is out of paper. ";
}
if (pq.IsOutputBinFull)
{
statusReport = statusReport + "Has a full output bin. ";
}
if (pq.IsPaperJammed)
{
statusReport = statusReport + "Has a paper jam. ";
}
if (pq.IsPaused)
{
statusReport = statusReport + "Is paused. ";
}
if (pq.IsTonerLow)
{
statusReport = statusReport + "Is low on toner. ";
}
if (pq.NeedUserIntervention)
{
statusReport = statusReport + "Needs user intervention. ";
}

// Check if queue is even available at this time of day


// The following method is defined in the complete example.
ReportAvailabilityAtThisTime(ref statusReport, pq);
}//end SpotTroubleUsingProperties

The ReportAvailabilityAtThisTime method was created in case you need to determine if


the queue is available at the current time of day.
The method will do nothing if the StartTimeOfDay and UntilTimeOfDay properties are
equal; because in that case the printer is available at all times. If they are different, the
method gets the current time which then has to be converted into total minutes past
midnight because the StartTimeOfDay and UntilTimeOfDay properties are Int32s
representing minutes-after-midnight, not DateTime objects. Finally, the method checks
to see if the current time is between the start and "until" times.

C#

private static void ReportAvailabilityAtThisTime(ref String statusReport,


PrintQueue pq)
{
if (pq.StartTimeOfDay != pq.UntilTimeOfDay) // If the printer is not
available 24 hours a day
{
DateTime utcNow = DateTime.UtcNow;
Int32 utcNowAsMinutesAfterMidnight = (utcNow.TimeOfDay.Hours * 60) +
utcNow.TimeOfDay.Minutes;

// If now is not within the range of available times . . .


if (!((pq.StartTimeOfDay < utcNowAsMinutesAfterMidnight)
&&
(utcNowAsMinutesAfterMidnight < pq.UntilTimeOfDay)))
{
statusReport = statusReport + " Is not available at this time of
day. ";
}
}
}

See also
StartTimeOfDay
UntilTimeOfDay
DateTime
PrintQueueStatus
FlagsAttribute
GetPrintQueues
PrintServer
LocalPrintServer
EnumeratedPrintQueueTypes
PrintQueue
& Operator (C# Reference)
Documents in WPF
Printing Overview
How to: Validate and Merge PrintTickets
Article • 02/06/2023

The Microsoft Windows Print Schema includes the flexible and extensible
PrintCapabilities and PrintTicket elements. The former itemizes the capabilities of a print
device and the latter specifies how the device should use those capabilities with respect
to a particular sequence of documents, individual document, or individual page.

A typical sequence of tasks for an application that supports printing would be as follows.

1. Determine a printer's capabilities.

2. Configure a PrintTicket to use those capabilities.

3. Validate the PrintTicket.

This article shows how to do this.

Example
In the simple example below, we are interested only in whether a printer can support
duplexing — two-sided printing. The major steps are as follows.

1. Get a PrintCapabilities object with the GetPrintCapabilities method.

2. Test for the presence of the capability you want. In the example below, we test the
DuplexingCapability property of the PrintCapabilities object for the presence of the
capability of printing on both sides of a sheet of paper with the "page turning"
along the long side of the sheet. Since DuplexingCapability is a collection, we use
the Contains method of ReadOnlyCollection<T>.

7 Note

This step is not strictly necessary. The MergeAndValidatePrintTicket method


used below will check each request in the PrintTicket against the capabilities
of the printer. If the requested capability is not supported by printer, the
printer driver will substitute an alternative request in the PrintTicket returned
by the method.

3. If the printer supports duplexing, the sample code creates a PrintTicket that asks
for duplexing. But the application does not specify every possible printer setting
available in the PrintTicket element. That would be wasteful of both programmer
and program time. Instead, the code sets only the duplexing request and then
merges this PrintTicket with an existing, fully configured and validated, PrintTicket,
in this case, the user's default PrintTicket.

4. Accordingly, the sample calls the MergeAndValidatePrintTicket method to merge


the new, minimal, PrintTicket with the user's default PrintTicket. This returns a
ValidationResult that includes the new PrintTicket as one of its properties.

5. The sample then tests that the new PrintTicket requests duplexing. If it does, then
the sample makes it the new default print ticket for the user. If step 2 above had
been left out and the printer did not support duplexing along the long side, then
the test would have resulted in false . (See the note above.)

6. The last significant step is to commit the change to the UserPrintTicket property of
the PrintQueue with the Commit method.

C#

/// <summary>
/// Changes the user-default PrintTicket setting of the specified print
queue.
/// </summary>
/// <param name="queue">the printer whose user-default PrintTicket setting
needs to be changed</param>
static private void ChangePrintTicketSetting(PrintQueue queue)
{
//
// Obtain the printer's PrintCapabilities so we can determine whether or
not
// duplexing printing is supported by the printer.
//
PrintCapabilities printcap = queue.GetPrintCapabilities();

//
// The printer's duplexing capability is returned as a read-only
collection of duplexing options
// that can be supported by the printer. If the collection returned
contains the duplexing
// option we want to set, it means the duplexing option we want to set
is supported by the printer,
// so we can make the user-default PrintTicket setting change.
//
if (printcap.DuplexingCapability.Contains(Duplexing.TwoSidedLongEdge))
{
//
// To change the user-default PrintTicket, we can first create a
delta PrintTicket with
// the new duplexing setting.
//
PrintTicket deltaTicket = new PrintTicket();
deltaTicket.Duplexing = Duplexing.TwoSidedLongEdge;
//
// Then merge the delta PrintTicket onto the printer's current user-
default PrintTicket,
// and validate the merged PrintTicket to get the new PrintTicket we
want to set as the
// printer's new user-default PrintTicket.
//
ValidationResult result =
queue.MergeAndValidatePrintTicket(queue.UserPrintTicket, deltaTicket);

//
// The duplexing option we want to set could be constrained by other
PrintTicket settings
// or device settings. We can check the validated merged PrintTicket
to see whether the
// the validation process has kept the duplexing option we want to
set unchanged.
//
if (result.ValidatedPrintTicket.Duplexing ==
Duplexing.TwoSidedLongEdge)
{
//
// Set the printer's user-default PrintTicket and commit the set
operation.
//
queue.UserPrintTicket = result.ValidatedPrintTicket;
queue.Commit();
Console.WriteLine("PrintTicket new duplexing setting is set on
'{0}'.", queue.FullName);
}
else
{
//
// The duplexing option we want to set has been changed by the
validation process
// when it was resolving setting constraints.
//
Console.WriteLine("PrintTicket new duplexing setting is
constrained on '{0}'.", queue.FullName);
}
}
else
{
//
// If the printer doesn't support the duplexing option we want to
set, skip it.
//
Console.WriteLine("PrintTicket new duplexing setting is not
supported on '{0}'.", queue.FullName);
}
}
So that you can quickly test this example, the remainder of it is presented below. Create
a project and a namespace and then paste both the code snippets in this article into the
namespace block.

C#

/// <summary>
/// Displays the correct command line syntax to run this sample program.
/// </summary>
static private void DisplayUsage()
{
Console.WriteLine();
Console.WriteLine("Usage #1: printticket.exe -l \"<printer_name>\"");
Console.WriteLine(" Run program on the specified local printer");
Console.WriteLine();
Console.WriteLine(" Quotation marks may be omitted if there are no
spaces in printer_name.");
Console.WriteLine();
Console.WriteLine("Usage #2: printticket.exe -r \"\\\\<server_name>\\
<printer_name>\"");
Console.WriteLine(" Run program on the specified network printer");
Console.WriteLine();
Console.WriteLine(" Quotation marks may be omitted if there are no
spaces in server_name or printer_name.");
Console.WriteLine();
Console.WriteLine("Usage #3: printticket.exe -a");
Console.WriteLine(" Run program on all installed printers");
Console.WriteLine();
}

[STAThread]
static public void Main(string[] args)
{
try
{
if ((args.Length == 1) && (args[0] == "-a"))
{
//
// Change PrintTicket setting for all local and network printer
connections.
//
LocalPrintServer server = new LocalPrintServer();

EnumeratedPrintQueueTypes[] queue_types =
{EnumeratedPrintQueueTypes.Local,

EnumeratedPrintQueueTypes.Connections};

//
// Enumerate through all the printers.
//
foreach (PrintQueue queue in server.GetPrintQueues(queue_types))
{
//
// Change the PrintTicket setting queue by queue.
//
ChangePrintTicketSetting(queue);
}
}//end if -a

else if ((args.Length == 2) && (args[0] == "-l"))


{
//
// Change PrintTicket setting only for the specified local
printer.
//
LocalPrintServer server = new LocalPrintServer();
PrintQueue queue = new PrintQueue(server, args[1]);
ChangePrintTicketSetting(queue);
}//end if -l

else if ((args.Length == 2) && (args[0] == "-r"))


{
//
// Change PrintTicket setting only for the specified remote
printer.
//
String serverName = args[1].Remove(args[1].LastIndexOf(@"\"));
String printerName = args[1].Remove(0,
args[1].LastIndexOf(@"\")+1);
PrintServer ps = new PrintServer(serverName);
PrintQueue queue = new PrintQueue(ps, printerName);
ChangePrintTicketSetting(queue);
}//end if -r

else
{
//
// Unrecognized command line.
// Show user the correct command line syntax to run this sample
program.
//
DisplayUsage();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);

//
// Show inner exception information if it's provided.
//
if (e.InnerException != null)
{
Console.WriteLine("--- Inner Exception ---");
Console.WriteLine(e.InnerException.Message);
Console.WriteLine(e.InnerException.StackTrace);
}
}
finally
{
Console.WriteLine("Press Return to continue...");
Console.ReadLine();
}
}//end Main

See also
PrintCapabilities
PrintTicket
GetPrintQueues
PrintServer
EnumeratedPrintQueueTypes
PrintQueue
GetPrintCapabilities
Documents in WPF
Printing Overview
Print Schema
Globalization and Localization
Article • 02/06/2023

Windows Presentation Foundation (WPF) provides extensive support for the


development of world-ready applications.

In This Section
WPF Globalization and Localization Overview
Globalization for WPF
Use Automatic Layout Overview
Localization Attributes and Comments
Bidirectional Features in WPF Overview
How-to Topics

Reference
System.Globalization

FlowDirection

NeutralResourcesLanguageAttribute

xml:lang Handling in XAML

Related Sections
WPF Globalization and Localization Overview
Article • 03/17/2022

When you limit your product's availability to only one language, you limit your potential customer
base to a fraction of our world's 7.5 billion population. If you want your applications to reach a
global audience, cost-effective localization of your product is one of the best and most economical
ways to reach more customers.

This overview introduces globalization and localization in WPF provides globalized design features,
including automatic layout, satellite assemblies, and localized attributes and commenting.

Localization is the translation of application resources into localized versions for the specific
cultures that the application supports. When you localize in WPF, you use the APIs in the
System.Windows.Markup.Localizer namespace. These APIs power the LocBaml Tool Sample
command-line tool. For information about how to build and use LocBaml, see Localize an
Application.

Best Practices for Globalization and Localization in


WPF
You can make the most of the globalization and localization functionality that is built into WPF by
following the UI design and localization-related tips that this section provides.

Best Practices for WPF UI Design


When you design a UI, consider implementing these best practices:

Write your UI in UI in code. When you create your UI by using XAML, you expose it through
built-in localization APIs.

Avoid using absolute positions and fixed sizes to lay out content; instead, use relative or
automatic sizing.

Use SizeToContent and keep widths and heights set to Auto .

Avoid using Canvas to lay out UIs.

Use Grid and its size-sharing feature.

Provide extra space in margins because localized text often requires more space. Extra space
allows for possible overhanging characters.

Enable TextWrapping on TextBlock to avoid clipping.

Set the xml:lang attribute. This attribute describes the culture of a specific element and its
child elements. The value of this property changes the behavior of several features in WPF.
For example, it changes the behavior of hyphenation, spell checking, number substitution,
complex script shaping, and font fallback. See Globalization for WPF for more information
about setting the xml:lang Handling in XAML.

Create a customized composite font to obtain better control of fonts that are used for
different languages. By default, WPF uses the GlobalUserInterface.composite font in your
Windows\Fonts directory.

When you create navigation applications that may be localized in a culture that presents text
in a right-to-left format, explicitly set the FlowDirection of every page to ensure the page
does not inherit FlowDirection from the NavigationWindow.

When you create stand-alone navigation applications that are hosted outside a browser, set
the StartupUri for your initial application to a NavigationWindow instead of to a page (for
example, <Application StartupUri="NavigationWindow.xaml"> ). This design enables you to
change the FlowDirection of the Window and the navigation bar. For more information and
an example, see Globalization Homepage Sample .

Best Practices for WPF Localization


When you localize WPF–based applications, consider implementing these best practices:

Use localization comments to provide extra context for localizers.

Use localization attributes to control localization instead of selectively omitting Uid properties
on elements. See Localization Attributes and Comments for more information.

Use msbuild -t:updateuid and -t:checkuid to add and check Uid properties in your UI, the
task is typically tedious and less accurate.

Do not edit or change Uid properties after you begin localization.

Do not use duplicate Uid properties (remember this tip when you use the copy-and-paste
command).

Set the UltimateResourceFallback location in AssemblyInfo.* to specify the appropriate


language for fallback (for example, [assembly: NeutralResourcesLanguage("en-US",
UltimateResourceFallbackLocation.Satellite)] ).

If you decide to include your source language in the main assembly by omitting the
<UICulture> tag in your project file, set the UltimateResourceFallback location as the main

assembly instead of the satellite (for example, [assembly: NeutralResourcesLanguage("en-


US", UltimateResourceFallbackLocation.MainAssembly)] ).

Localize a WPF Application


When you localize a WPF application, you have several options. For example, you can bind the
localizable resources in your application to an XML file, store localizable text in resx tables, or have
your localizer use Extensible Application Markup Language (XAML) files. This section describes a
localization workflow that uses the BAML form of XAML, which provides several benefits:

You can localize after you build.

You can update to a newer version of the BAML form of XAML with localizations from an
older version of the BAML form of XAML so that you can localize at the same time that you
develop.

You can validate original source elements and semantics at compile time because the BAML
form of XAML is the compiled form of XAML.

Localization Build Process


When you develop a WPF application, the build process for localization is as follows:

The developer creates and globalizes the WPF application. In the project file the developer
sets <UICulture>en-US</UICulture> so that when the application is compiled, a language-
neutral main assembly is generated. This assembly has a satellite .resources.dll file that
contains all the localizable resources. Optionally, you can keep the source language in the
main assembly because our localization APIs support extraction from the main assembly.

When the file is compiled into the build, the XAML is converted to the BAML form of XAML.
The culturally neutral MyDialog.exe and the culturally dependent (English)
MyDialog.resources.dll files are released to the English-speaking customer.

Localization Workflow
The localization process begins after the unlocalized MyDialog.resources.dll file is built. The UI
elements and properties in your original XAML are extracted from the BAML form of XAML into
key-value pairs by using the APIs under System.Windows.Markup.Localizer. Localizers use the key-
value pairs to localize the application. You can generate a new .resource.dll from the new values
after localization is complete.

The keys of the key-value pairs are x:Uid values that are placed by the developer in the original UI
after the localizer begins localizing, you can merge the development change with the already
completed localization work so that minimal translation work is lost.

The following graphic shows a typical localization workflow that is based on the BAML form of
XAML. This diagram assumes the developer writes the application in English. The developer creates
and globalizes the WPF application. In the project file the developer sets <UICulture>en-
US</UICulture> so that on build, a language neutral main assembly gets generated with a satellite
.resources.dll containing all localizable resources. Alternately, one could keep the source language
in the main assembly because WPF localization APIs support extraction from the main assembly.
After the build process, the XAML get compiled into BAML. The culturally neutral
MyDialog.exe.resources.dll get shipped to the English speaking customer.

Examples of WPF Localization


This section contains examples of localized applications to help you understand how to build and
localize WPF applications.
Run Dialog Box Example
The following graphics show the output of the Run dialog box sample.

English:

German:

Designing a Global Run Dialog Box

This example produces a Run dialog box by using WPF and XAML. This dialog box is equivalent to
the Run dialog box that is available from the Microsoft Windows Start menu.

Some highlights for making global dialog boxes are:

Automatic Layout

In Window1.xaml:

<Window SizeToContent="WidthAndHeight">

The previous Window property automatically resizes the window according to the size of the
content. This property prevents the window from cutting off content that increases in size after
localization; it also removes unneeded space when content decreases in size after localization.

<Grid x:Uid="Grid_1">

Uid properties are needed in order for WPF localization APIs to work correctly.

They are used by UI with an older localization of the UI. You add a Uid property by running msbuild
-t:updateuid RunDialog.csproj in a command shell. This is the recommended method of adding
Uid properties because manually adding them is typically time-consuming and less accurate. You
can check that Uid properties are correctly set by running msbuild -t:checkuid RunDialog.csproj .
The UI is structured by using the Grid control, which is a useful control for taking advantage of the
automatic layout in UI elements that are positioned in each cell can adapt to increases and
decreases in size during localization.

XAML

<Grid.ColumnDefinitions>
<ColumnDefinition x:Uid="ColumnDefinition_1" />
<ColumnDefinition x:Uid="ColumnDefinition_2" />

The first two columns where the Open: label and ComboBox are placed use 10 percent of the UI
total width.

XAML

<ColumnDefinition x:Uid="ColumnDefinition_3" SharedSizeGroup="Buttons" />


<ColumnDefinition x:Uid="ColumnDefinition_4" SharedSizeGroup="Buttons" />
<ColumnDefinition x:Uid="ColumnDefinition_5" SharedSizeGroup="Buttons" />
</Grid.ColumnDefinitions>

Note that of the example uses the shared-sizing feature of Grid. The last three columns take
advantage of this by placing themselves in the same SharedSizeGroup. As one would expect from
the name of the property, this allows the columns to share the same size. So when the "Browse…"
gets localized to the longer string "Durchsuchen…", all buttons grow in width instead of having a
small "OK" button and a disproportionately large "Durchsuchen…" button.

xml:lang

xml:lang="en-US"

Notice the xml:lang Handling in XAML placed at the root element of the UI. This property describes
the culture of a given element and its children. This value is used by several features in WPF and
should be changed appropriately during localization. This value changes what language dictionary
is use to hyphenate and spell check words. It also affects the display of digits and how the font
fallback system selects which font to use. Finally, the property affects the way numbers are
displayed and the way texts written in complex scripts are shaped. The default value is "en-US".

Building a Satellite Resource Assembly

In .csproj:

Edit the .csproj file and add the following tag to an unconditional <PropertyGroup> :

<UICulture>en-US</UICulture>

Notice the addition of a UICulture value. When this is set to a valid CultureInfo value such as en-
US, building the project will generate a satellite assembly with all localizable resources in it.

<Resource Include="RunIcon.JPG">
<Localizable>False</Localizable>

</Resource>

The RunIcon.JPG does not need to be localized because it should appear the same for all cultures.
Localizable is set to false so that it remains in the language neutral main assembly instead of the
satellite assembly. The default value of all noncompilable resources is Localizable set to true .

Localizing the Run Dialog

Parse

After building the application, the first step in localizing it is parsing the localizable resources out
of the satellite assembly. For the purposes of this topic, use the sample LocBaml tool which can be
found at LocBaml Tool Sample . Note that LocBaml is only a sample tool meant to help you get
started in building a localization tool that fits into your localization process. Using LocBaml, run the
following to parse: LocBaml /parse RunDialog.resources.dll /out: to generate a
"RunDialog.resources.dll.CSV" file.

Localize

Use your favorite CSV editor that supports Unicode to edit this file. Filter out all entries with a
localization category of "None". You should see the following entries:

Resource Key Localization Value


Category

Button_1:System.Windows.Controls.Button.$Content Button OK

Button_2:System.Windows.Controls.Button.$Content Button Cancel

Button_3:System.Windows.Controls.Button.$Content Button Browse...

ComboBox_1:System.Windows.Controls.ComboBox.$Content ComboBox

TextBlock_1:System.Windows.Controls.TextBlock.$Content Text Type the name of a program,


folder, document, or Internet
resource, and Windows will
open it for you.

TextBlock_2:System.Windows.Controls.TextBlock.$Content Text Open:

Window_1:System.Windows.Window.Title Title Run

Localizing the application to German would require the following translations:

Resource Key Localization Value


Category

Button_1:System.Windows.Controls.Button.$Content Button OK

Button_2:System.Windows.Controls.Button.$Content Button Abbrechen


Resource Key Localization Value
Category

Button_3:System.Windows.Controls.Button.$Content Button Durchsuchen…

ComboBox_1:System.Windows.Controls.ComboBox.$Content ComboBox

TextBlock_1:System.Windows.Controls.TextBlock.$Content Text Geben Sie den Namen eines


Programms, Ordners,
Dokuments oder einer
Internetresource an.

TextBlock_2:System.Windows.Controls.TextBlock.$Content Text Öffnen:

Window_1:System.Windows.Window.Title Title Run

Generate

The last step of localization involves creating the newly localized satellite assembly. This can be
accomplished with the following LocBaml command:

LocBaml.exe /generate RunDialog.resources.dll /trans:RunDialog.resources.dll.CSV /out: .


/cul:de-DE

On German Windows, if this resources.dll is placed in a de-DE folder next to the main assembly,
this resource will automatically load instead of the one in the en-US folder. If you do not have a
German version of Windows to test this, set the culture to whatever culture of Windows you are
using (for example, en-US ), and replace the original resources DLL.

Satellite Resource Loading

MyDialog.exe en-US\MyDialog.resources.dll de-DE\MyDialog.resources.dll

Code Original English BAML Localized BAML

Culturally neutral resources Other resources in English Other resources localized to German

.NET automatically chooses which satellite resources assembly to load based on the application's
Thread.CurrentUICulture. This defaults to the culture of your Windows OS. If you're using German
Windows, the de-DE\MyDialog.resources.dll file loads. If you're using English Windows, the en-
US\MyDialog.resources.dll file loads. You can set the ultimate fallback resource for your application
by specifying the NeutralResourcesLanguage attribute in your project’s AssemblyInfo file. For
example, if you specify:

[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]

then the en-US\MyDialog.resources.dll file is used with German Windows if neither of the following
files are available: de-DE\MyDialog.resources.dll or de\MyDialog.resources.dll.

Microsoft Saudi Arabia Homepage


The following graphics show an English and Arabic Homepage. For the complete sample that
produces these graphics see Globalization Homepage Sample .

English:

Arabic:
Designing a Global Microsoft home page
This mock up of the Microsoft Saudi Arabia web site illustrates the globalization features provided
for RightToLeft languages. Languages such as Hebrew and Arabic have a right-to-left reading order
so the layout of UI must often be laid out quite differently than it would be in left-to-right
languages such as English. Localizing from a left-to-right language to a right-to-left language or
vice versa can be quite challenging. WPF has been designed to make such localizations much
easier.

FlowDirection

Homepage.xaml:

XAML

<Page x:Uid="Page_1" x:Class="MicrosoftSaudiArabiaHomepage.Homepage"


xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FlowDirection="LeftToRight"
Localization.Comments="FlowDirection(This FlowDirection controls the actual
content of the homepage)"
xml:lang="en-US">
Notice the FlowDirection property on Page. Changing this property to RightToLeft will change the
FlowDirection of the Page and its children elements so that the layout of this UI is flipped to
become right-to-left as an Arabic user would expect. One can override the inheritance behavior by
specifying an explicit FlowDirection on any element. The FlowDirection property is available on any
FrameworkElement or document related element and has an implicit value of LeftToRight.

Observe that even the background gradient brushes are flipped correctly when the root
FlowDirection is changed:

FlowDirection="LeftToRight"

FlowDirection="RightToLeft"

Avoid Using Fixed Dimensions for Panels and Controls

Take a look through Homepage.xaml, notice that aside from the fixed width and height specified
for the entire UI on the top DockPanel, there are no other fixed dimensions. Avoid using fixed
dimensions to prevent clipping localized text that may be longer than the source text. WPF panels
and controls will automatically resize based on the content that they contain. Most controls also
have minimum and maximum dimensions that you can set for more control (for example,
MinWidth="20"). With Grid, you can also set relative widths and heights by using '*' (for example,
Width="0.25*" ) or use its cell size sharing feature.

Localization Comments

There are many cases where content may be ambiguous and difficult to translate. The developer or
designer has the ability to provide extra context and comments to localizers through localization
comments. For example the Localization.Comments below clarifies the usage of the character '|'.

XAML

<TextBlock
x:Uid="TextBlock_2"
DockPanel.Dock="Right"
Foreground="White"
Margin="5,0,5,0"
Localization.Comments="$Content(This character is used as a decorative rule.)">
|
</TextBlock>

This comment becomes associated with TextBlock_1's content and in the case of the LocBaml Tool,
( see Localize an Application), it can be seen in the 6th column of the TextBlock_1 row in the output
.csv file:

Resource Key Category Readable Modifiable Comment Value

TextBlock_1:System.Windows.Controls.TextBlock.$Content Text TRUE TRUE This |


character
is used as
a
decorative
rule.

Comments can be placed on the content or property of any element using the following syntax:

XAML

<TextBlock
x:Uid="TextBlock_1"
DockPanel.Dock="Right"
Foreground="White"
Margin="5,0,5,0"
Localization.Comments="$Content(This is a comment on the TextBlock's content.)
Margin(This is a comment on the TextBlock's Margin property.)">
|
</TextBlock>

Localization Attributes

Often the developer or localization manager needs control of what localizers can read and modify.
For example, you might not want the localizer to translate the name of your company or legal
wording. WPF provides attributes that enable you to set the readability, modifiability, and category
of an element's content or property which your localization tool can use to lock, hide, or sort
elements. For more information, see Attributes. For the purposes of this sample, the LocBaml Tool
just outputs the values of these attributes. WPF controls all have default values for these attributes,
but you the can override them. For example, the following example overrides the default
localization attributes for TextBlock_1 and sets the content to be readable but unmodifiable for
localizers.

XAML

<TextBlock
x:Uid="TextBlock_1"
Localization.Attributes=
"$Content(Readable Unmodifiable)">
Microsoft Corporation
</TextBlock>

In addition to the readability and modifiability attributes, WPF provides an enumeration of


common UI categories (LocalizationCategory) that can be used to give localizers more context. The
WPF default categories for platform controls can be overridden in XAML as well:

XAML
<TextBlock x:Uid="TextBlock_2">
<TextBlock.ToolTip>
<TextBlock
x:Uid="TextBlock_3"
Localization.Attributes=
"$Content(ToolTip Readable Unmodifiable)">
Microsoft Corporation
</TextBlock>
</TextBlock.ToolTip>
Windows Vista
</TextBlock>

The default localization attributes that WPF provides can also be overridden through code, so you
can correctly set the right default values for custom controls. For example:

C#

[Localizability(Readability = Readability.Readable,
Modifiability=Modifiability.Unmodifiable, LocalizationCategory.None)]
public class CorporateLogo : TextBlock
{
// ...
}

The per instance attributes set in XAML will take precedence over the values set in code on custom
controls. For more information on attributes and comments, see Localization Attributes and
Comments.

Font Fallback and Composite Fonts

If you specify a font that does not support a given codepoint range, WPF will automatically fallback
to one that does by using the Global User Interface.compositefont that is located in your
Windows\Fonts directory. Composite fonts work just as any other font and can be used explicitly
by setting an element's FontFamily (for instance, FontFamily="Global User Interface" ). You can
specify your own font fallback preference by creating your own composite font and specifying
what font to use for specific codepoint ranges and languages.

For more information on composite fonts see FontFamily.

Localizing the Microsoft Homepage

You can follow the same steps as the Run Dialog example to localize this application. The localized
.csv file for Arabic is available for you in the Globalization Homepage Sample .
Globalization for WPF
Article • 08/10/2023

This topic introduces issues that you should be aware of when writing Windows
Presentation Foundation (WPF) applications for the global market. The globalization
programming elements are defined in .NET in the System.Globalization namespace.

XAML Globalization
Extensible Application Markup Language (XAML) is based on XML and takes advantage
of the globalization support defined in the XML specification. The following sections
describe some XAML features that you should be aware of.

Character References
A character reference gives the UTF16 code unit of the particular Unicode character it
represents, in either decimal or hexadecimal. The following example shows a decimal
character reference for the COPTIC CAPITAL LETTER HORI, or 'Ϩ':

XAML

&#1000;

The following example shows a hexadecimal character reference. Notice that it has an x
in front of the hexadecimal number.

XAML

&#x3E8;

Encoding
The encoding supported by XAML are ASCII, Unicode UTF-16, and UTF-8. The encoding
statement is at the beginning of XAML document. If no encoding attribute exists and
there is no byte-order, the parser defaults to UTF-8. UTF-8 and UTF-16 are the preferred
encodings. UTF-7 is not supported. The following example demonstrates how to specify
a UTF-8 encoding in a XAML file.

XAML
?xml encoding="UTF-8"?

Language Attribute
XAML uses xml:lang to represent the language attribute of an element. To take
advantage of the CultureInfo class, the language attribute value needs to be one of the
culture names predefined by CultureInfo. xml:lang is inheritable in the element tree (by
XML rules, not necessarily because of dependency property inheritance) and its default
value is an empty string if it is not assigned explicitly.

The language attribute is very useful for specifying dialects. For example, French has
different spelling, vocabulary, and pronunciation in France, Quebec, Belgium, and
Switzerland. Also Chinese, Japanese, and Korean share code points in Unicode, but the
ideographic shapes are different and they use totally different fonts.

The following Extensible Application Markup Language (XAML) example uses the fr-CA
language attribute to specify Canadian French.

XAML

<TextBlock xml:lang="fr-CA">Découvrir la France</TextBlock>

Unicode
XAML supports all Unicode features including surrogates. As long as the character set
can be mapped to Unicode, it is supported. For example, GB18030 introduces some
characters that are mapped to the Chinese, Japanese, and Korean (CFK) extension A and
B and surrogate pairs, therefore it is fully supported. A WPF application can use
StringInfo to manipulate strings without understanding whether they have surrogate
pairs or combining characters.

Designing an International User Interface with


XAML
This section describes user interface (UI) features that you should consider when writing
an application.

International Text
WPF includes built-in processing for all Microsoft .NET Framework supported writing
systems.

The following scripts are currently supported:

Arabic

Bengali

Devanagari

Cyrillic

Greek

Gujarati

Gurmukhi

Hebrew

Ideographic scripts

Kannada

Lao

Latin

Malayalam

Mongolian

Odia

Syriac

Tamil

Telugu

Thaana

Thai*

Tibetan

*In this release the display and editing of Thai text is supported; word breaking is not.
The following scripts are not currently supported:

Khmer

Korean Old Hangul

Myanmar

Sinhala

All the writing system engines support OpenType fonts. OpenType fonts can include the
OpenType layout tables that enable font creators to design better international and
high-end typographic fonts. The OpenType font layout tables contain information about
glyph substitutions, glyph positioning, justification, and baseline positioning, enabling
text-processing applications to improve text layout.

OpenType fonts allow the handling of large glyph sets using Unicode encoding. Such
encoding enables broad international support as well as for typographic glyph variants.

WPF text rendering is powered by Microsoft ClearType sub-pixel technology that


supports resolution independence. This significantly improves legibility and provides the
ability to support high quality magazine style documents for all scripts.

International Layout
WPF provides a very convenient way to support horizontal, bidirectional, and vertical
layouts. In presentation framework the FlowDirection property can be used to define
layout. The flow direction patterns are:

LeftToRight - horizontal layout for Latin, East Asian and so forth.

RightToLeft - bidirectional for Arabic, Hebrew and so forth.

Developing Localizable Applications


When you write an application for global consumption you should keep in mind that the
application must be localizable. The following topics point out things to consider.

Multilingual User Interface


Multilingual User Interfaces (MUI) is a Microsoft support for switching UIs from one
language to another. A WPF application uses the assembly model to support MUI. One
application contains language-neutral assemblies as well as language-dependent
satellite resource assemblies. The entry point is a managed .EXE in the main assembly.
WPF resource loader takes advantage of the Framework's resource manager to support
resource lookup and fallback. Multiple language satellite assemblies work with the same
main assembly. The resource assembly that is loaded depends on the CurrentUICulture
of the current thread.

Localizable User Interface


WPF applications use XAML to define their UI. XAML allows developers to specify a
hierarchy of objects with a set of properties and logic. The primary use of XAML is to
develop WPF applications but it can be used to specify a hierarchy of any common
language runtime (CLR) objects. Most developers use XAML to specify their application's
UI and use a programming language such as C# to react to user interaction.

From a resource point of view, a UI is a resource element and therefore its final
distribution format must be localizable to support international languages. Because
XAML cannot handle events many XAML applications contain blocks of code to do this.
For more information, see XAML in WPF. Code is stripped out and compiled into
different binaries when a XAML file is tokenized into the BAML form of XAML. The BAML
form of XAML files, images, and other types of managed resource objects are
embedded in the satellite resource assembly, which can be localized into other
languages, or the main assembly when localization is not required.

7 Note

WPF applications support all the FrameworkCLR resources including string tables,
images, and so forth.

Building Localizable Applications


Localization means to adapt a UI to different cultures. To make a WPF application
localizable, developers need to build all the localizable resources into a resource
assembly. The resource assembly is localized into different languages, and the code-
behind uses resource management API to load. One of the files required for a WPF
application is a project file (.proj). All resources that you use in your application should
be included in the project file. The following example from a .csproj file shows how to
do this.

XML
<Resource Include="data\picture1.jpg"/>
<EmbeddedResource Include="data\stringtable.en-US.restext"/>

To use a resource in your application instantiate a ResourceManager and load the


resource you want to use. The following example demonstrates how to do this.

C#

void OnClick(object sender, RoutedEventArgs e)


{
ResourceManager rm = new ResourceManager ("MySampleApp.data.stringtable",
Assembly.GetExecutingAssembly());
Text1.Text = rm.GetString("Message");
}

Using ClickOnce with Localized Applications


ClickOnce is a new Windows Forms deployment technology that will ship with Visual
Studio 2005. It enables application installation and upgrading of Web applications.
When an application that was deployed with ClickOnce is localized it can only be viewed
on the localized culture. For example, if a deployed application is localized to Japanese it
can only be viewed on Japanese Microsoft Windows not on English Windows. This
presents a problem because it is a common scenario for Japanese users to run an
English version of Windows.

The solution to this problem is setting the neutral language fallback attribute. An
application developer can optionally remove resources from the main assembly and
specify that the resources can be found in a satellite assembly corresponding to a
specific culture. To control this process use the NeutralResourcesLanguageAttribute. The
constructor of the NeutralResourcesLanguageAttribute class has two signatures, one
that takes an UltimateResourceFallbackLocation parameter to specify the location where
the ResourceManager should extract the fallback resources: main assembly or satellite
assembly. The following example shows how to use the attribute. For the ultimate
fallback location, the code causes the ResourceManager to look for the resources in the
"de" subdirectory of the directory of the currently executing assembly.

C#

[assembly: NeutralResourcesLanguageAttribute(
"de" , UltimateResourceFallbackLocation.Satellite)]
See also
WPF Globalization and Localization Overview
Use Automatic Layout Overview
Article • 08/10/2023

This topic introduces guidelines for developers on how to write Windows Presentation
Foundation (WPF) applications with localizable user interfaces (UIs). In the past,
localization of a UI was a time consuming process. Each language that the UI was
adapted for required a pixel by pixel adjustment. Today with the right design and right
coding standards, UIs can be constructed so that localizers have less resizing and
repositioning to do. The approach to writing applications that can be more easily resized
and repositioned is called automatic layout, and can be achieved by using WPF
application design.

Advantages of Using Automatic Layout


Because the WPF presentation system is powerful and flexible, it provides the ability to
layout elements in an application that can be adjusted to fit the requirements of
different languages. The following list points out some of the advantages of automatic
layout.

UI displays well in any language.

Reduces the need to readjust position and size of controls after text is translated.

Reduces the need to readjust window size.

UI layout renders properly in any language.

Localization can be reduced to the point that it is little more than string translation.

Automatic Layout and Controls


Automatic layout enables an application to adjust the size of a control automatically. For
example, a control can change to accommodate the length of a string. This capability
enables localizers to translate the string; they no longer need to resize the control to fit
the translated text. The following example creates a button with English content.

XAML

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ButtonLoc.Pane1"
Name="myWindow"
SizeToContent="WidthAndHeight"
>

<DockPanel>
<Button FontSize="28" Height="50">My name is Hope.</Button>
</DockPanel>
</Window>

In the example, all you have to do to make a Spanish button is change the text. For
example,

XAML

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ButtonLoc.Pane1"
Name="myWindow"
SizeToContent="WidthAndHeight"
>

<DockPanel>
<Button FontSize="28" Height="50">Me llamo Esperanza.</Button>
</DockPanel>
</Window>

The following graphic shows the output of the code samples:

Automatic Layout and Coding Standards


Using the automatic layout approach requires a set of coding and design standards and
rules to produce a fully localizable UI. The following guidelines will aid your automatic
layout coding.

Do not use absolute positions

Do not use Canvas because it positions elements absolutely.


Use DockPanel, StackPanel, and Grid to position controls.

For a discussion about various types of panels, see Panels Overview.

Do not set a fixed size for a window

Use Window.SizeToContent. For example:

XAML

<StackPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="GridLoc.Pane1"
>

Add a FlowDirection

Add a FlowDirection to the root element of your application.

WPF provides a convenient way to support horizontal, bidirectional, and vertical


layouts. In presentation framework, the FlowDirection property can be used to
define layout. The flow-direction patterns are:

FlowDirection.LeftToRight (LrTb) — horizontal layout for Latin, East Asian, and so


forth.

FlowDirection.RightToLeft (RlTb) — bidirectional for Arabic, Hebrew, and so


forth.

Use composite fonts instead of physical fonts

With composite fonts, the FontFamily property does not need to be localized.

Developers can use one of the following fonts or create their own.
Global User Interface
Global San Serif
Global Serif

Add xml:lang

Add the xml:lang attribute in the root element of your UI, such as xml:lang="en-
US" for an English application.

Because composite fonts use xml:lang to determine what font to use, set this
property to support multilingual scenarios.
Automatic Layout and Grids
The Grid element, is useful for automatic layout because it enables a developer to
position elements. A Grid control is capable of distributing the available space among its
child elements, using a column and row arrangement. The UI elements can span
multiple cells, and it is possible to have grids within grids. Grids are useful because they
enable you to create and position complex UI. The following example demonstrates
using a grid to position some buttons and text. Notice that the height and width of the
cells are set to Auto; therefore, the cell that contains the button with an image adjusts to
fit the image.

XAML

<Grid Name="grid" ShowGridLines ="false">


<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<TextBlock Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="0"


FontSize="24">Grid
</TextBlock>
<TextBlock Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="1" FontSize="12"
Grid.ColumnSpan="2">The following buttons and text are positioned using
a Grid.
</TextBlock>
<Button Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="2" Background="Pink"
BorderBrush="Black" BorderThickness="10">Button 1
</Button>
<TextBlock Margin="10, 10, 5, 5" Grid.Column="1" Grid.Row="2" FontSize="12"
VerticalAlignment="Center" TextWrapping="WrapWithOverflow">Sets the
background
color.
</TextBlock>
<Button Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="3" Foreground="Red">
Button 2
</Button>
<TextBlock Margin="10, 10, 5, 5" Grid.Column="1" Grid.Row="3" FontSize="12"
VerticalAlignment="Center" TextWrapping="WrapWithOverflow">Sets the
foreground
color.
</TextBlock>
<Button Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="4">
<Image Source="data\flower.jpg"></Image>
</Button>
<TextBlock Margin="10, 10, 5, 5" Grid.Column="1" Grid.Row="4" FontSize="12"
VerticalAlignment="Center" TextWrapping="WrapWithOverflow">Adds an image
as
the button's content.
</TextBlock>
</Grid>

The following graphic shows the grid produced by the previous code.

Grid

Automatic Layout and Grids Using the


IsSharedSizeScope Property
A Grid element is useful in localizable applications to create controls that adjust to fit
content. However, at times you want controls to maintain a particular size regardless of
content. For example, if you have "OK", "Cancel" and "Browse" buttons you probably do
not want the buttons sized to fit the content. In this case the Grid.IsSharedSizeScope
attached property is useful for sharing the same sizing among multiple grid elements.
The following example demonstrates how to share column and row sizing data between
multiple Grid elements.

XAML

<StackPanel Orientation="Horizontal" DockPanel.Dock="Top">


<Button Click="setTrue" Margin="0,0,10,10">Set
IsSharedSizeScope="True"</Button>
<Button Click="setFalse" Margin="0,0,10,10">Set
IsSharedSizeScope="False"</Button>
</StackPanel>

<StackPanel Orientation="Horizontal" DockPanel.Dock="Top">

<Grid ShowGridLines="True" Margin="0,0,10,0">


<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="FirstColumn"/>
<ColumnDefinition SharedSizeGroup="SecondColumn"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" SharedSizeGroup="FirstRow"/>
</Grid.RowDefinitions>

<Rectangle Fill="Silver" Grid.Column="0" Grid.Row="0" Width="200"


Height="100"/>
<Rectangle Fill="Blue" Grid.Column="1" Grid.Row="0" Width="150"
Height="100"/>

<TextBlock Grid.Column="0" Grid.Row="0" FontWeight="Bold">First


Column</TextBlock>
<TextBlock Grid.Column="1" Grid.Row="0" FontWeight="Bold">Second
Column</TextBlock>
</Grid>

<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="FirstColumn"/>
<ColumnDefinition SharedSizeGroup="SecondColumn"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" SharedSizeGroup="FirstRow"/>
</Grid.RowDefinitions>

<Rectangle Fill="Silver" Grid.Column="0" Grid.Row="0"/>


<Rectangle Fill="Blue" Grid.Column="1" Grid.Row="0"/>

<TextBlock Grid.Column="0" Grid.Row="0" FontWeight="Bold">First


Column</TextBlock>
<TextBlock Grid.Column="1" Grid.Row="0" FontWeight="Bold">Second
Column</TextBlock>
</Grid>

</StackPanel>

<TextBlock Margin="10" DockPanel.Dock="Top" Name="txt1"/>

7 Note

For the complete code sample, see Share Sizing Properties Between Grids.

See also
Globalization for WPF
Use Automatic Layout to Create a Button
Use a Grid for Automatic Layout
Localization Attributes and Comments
Article • 02/06/2023

WPF Localization API to indicate which resources are to be localized. Free-form


comments are any information that the application author wants to include.

Add Localization Comments


If markup application authors have requirements for specific elements in XAML, such as
constraints on text length, font family, or font size, they can convey this information to
localizers with comments in the XAML code. The process for adding comments to
source code is as follows:

1. Application developer adds localization comments to XAML source code.

2. During the build process, you can specify in the .proj file whether to leave the free-
form localization comments in the assembly, strip out part of the comments, or
strip out all the comments. The stripped-out comments are placed in a separate
file. You specify your option using a LocalizationDirectivesToLocFile tag, eg:

<LocalizationDirectivesToLocFile> value </LocalizationDirectivesToLocFile>

3. The values that can be assigned are:

None - Both comments and attributes stay inside the assembly and no
separate file is generated.

CommentsOnly - Strips only the comments from the assembly and places
them in the separate LocFile.

All - Strips both the comments and the attributes from the assembly and
places them both in a separate LocFile.

4. When localizable resources are extracted from BAML, the localizability attributes
are respected by the BAML Localization API.

5. Localization comment files, containing only free-form comments, are incorporated


into the localization process at a later time.

The following example shows how to add localization comments to a XAML file.

<TextBlock x:Id = "text01"


FontFamily = "Microsoft Sans Serif"

FontSize = "12"

Localization.Attributes = "$Content (Unmodifiable Readable Text)

FontFamily (Unmodifiable Readable)"

Localization.Comments = "$Content (Trademark)

FontSize (Trademark font size)" >

Microsoft

</TextBlock>

In the previous sample the Localization.Attributes section contains the localization


attributes and the Localization.Comments section the free-form comments. The
following tables show the attributes and comments and their meaning to the localizer.

Localization Meaning
attributes

$Content Contents of the TextBlock element cannot be modified. Localizers cannot


(Unmodifiable change the word "Microsoft". The content is visible (Readable) to the localizer.
Readable Text) The category of the content is text.

FontFamily The font family property of the TextBlock element cannot be changed but it is
(Unmodifiable visible to the localizer.
Readable)

Localization free-form Meaning


comments

$Content (Trademark) The application author tells the localizer that the content in the
TextBlock element is a trademark.

FontSize (Trademark The application author indicates that the font size property should
font size) follow the standard trademark size.

Localizability Attributes
The information in Localization.Attributes contains a list of pairs: the targeted value
name and the associated localizability values. The target name can be a property name
or the special $Content name. If it is a property name, the targeted value is the value of
the property. If it is $Content, the target value is the content of the element.
There are three types of attributes:

Category. This specifies whether a value should be modifiable from a localizer tool.
See Category.

Readability. This specifies whether a localizer tool should read (and display) a
value. See Readability.

Modifiability. This specifies whether a localizer tool allows a value to be modified.


See Modifiability.

These attributes can be specified in any order delimited by a space. In case duplicate
attributes are specified, the last attribute will override former ones. For example,
Localization.Attributes = "Unmodifiable Modifiable" sets Modifiability to Modifiable
because it is the last value.

Modifiability and Readability are self-explanatory. The Category attribute provides


predefined categories that help the localizer when translating text. Categories, such as,
Text, Label, and Title give the localizer information about how to translate the text. There
are also special categories: None, Inherit, Ignore, and NeverLocalize.

The following table shows the meaning of the special categories.

Category Meaning

None Targeted value has no defined category.

Inherit Targeted value inherits its category from its parent.

Ignore Targeted value is ignored in the localization process. Ignore affects only the
current value. It will not affect child nodes.

NeverLocalize Current value cannot be localized. This category is inherited by the children of an
element.

Localization Comments
Localization.Comments contains free-form strings concerning the targeted value.
Application developers can add information to give localizers hints about how the
applications text should be translated. The format of the comments can be any string
surrounded by "()". Use '\' to escape characters.

See also
Globalization for WPF
Use Automatic Layout to Create a Button
Use a Grid for Automatic Layout
Localize an Application
Bidirectional Features in WPF Overview
Article • 07/19/2022

Unlike any other development platform, WPF has many features that support rapid
development of bidirectional content, for example, mixed left to right and right to left
data in the same document. At the same time, WPF creates an excellent experience for
users who require bidirectional features such as Arabic and Hebrew speaking users.

The following sections explain many bidirectional features together with examples
illustrating how to achieve the best display of bidirectional content. Most of the samples
use XAML, though you can easily apply the concepts to C# or Microsoft Visual Basic
code.

FlowDirection
The basic property that defines the content flow direction in a WPF application is
FlowDirection. This property can be set to one of two enumeration values, LeftToRight or
RightToLeft. The property is available to all WPF elements that inherit from
FrameworkElement.

The following examples set the flow direction of a TextBox element.

Left-to-right flow direction

XAML

<TextBlock Background="DarkBlue" Foreground="LightBlue"


FontSize="20" FlowDirection="LeftToRight">
This is a left-to-right TextBlock
</TextBlock>

Right-to-left flow direction

XAML

<TextBlock Background="LightBlue" Foreground="DarkBlue"


FontSize="20" FlowDirection="RightToLeft">
This is a right-to-left TextBlock
</TextBlock>

The following graphic shows how the previous code renders.


An element within a user interface (UI) tree will inherit the FlowDirection from its
container. In the following example, the TextBlock is inside a Grid, which resides in a
Window. Setting the FlowDirection for the Window implies setting it for the Grid and
TextBlock as well.

The following example demonstrates setting FlowDirection.

XAML

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="FlowDirectionApp.Window1"
Title="BidiFeatures" Height="200" Width="700"
FlowDirection="RightToLeft">

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" >
This is a right-to-left TextBlock
</TextBlock>

<TextBlock Grid.Column="1" FlowDirection="LeftToRight">


This is a left-to-right TextBlock
</TextBlock>
</Grid>
</Window>

The top level Window has a RightToLeftFlowDirection, so all elements contained within it
also inherit the same FlowDirection. For an element to override a specified FlowDirection
it must add an explicit direction change such as the second TextBlock in the previous
example which changes to LeftToRight. When no FlowDirection is defined, the default
LeftToRight applies.

The following graphic shows the output of the previous example:


FlowDocument
Many development platforms such as HTML, Win32 and Java provide special support for
bidirectional content development. Markup languages such as HTML give content
writers the necessary markup to display text in any required direction, for example the
HTML 4.0 tag, "dir" that takes "rtl" or "ltr" as values. This tag is similar to the
FlowDirection property, but the FlowDirection property works in a more advanced way
to layout textual content and can be used for content other than text.

In UI element that can host a combination of text, tables, images and other elements.
The samples in the following sections use this element.

Adding text to a FlowDocument can be done in more that one way. A simple way to do
so is through a Paragraph which is a block-level element used to group content such as
text. To add text to inline-level elements the samples use Span and Run. Span is an
inline-level flow content element used for grouping other inline elements, while a Run is
an inline-level flow content element intended to contain a run of unformatted text. A
Span can contain multiple Run elements.

The first document example contains a document that has a number of network share
names; for example \\server1\folder\file.ext . Whether you have this network link in
an Arabic or English document, you always want it to appear in the same way. The
following graphic illustrates using the Span element and shows the link in an Arabic
RightToLeft document:
Because the text is RightToLeft, all special characters, such as the "\", separate the text in
a right to left order. That results in the link not being shown in the correct order,
therefore to solve the problem, the text must be embedded to preserve a separate Run
flowing LeftToRight. Instead of having a separate Run for each language, a better way to
solve the problem is to embed the less frequently used English text into a larger Arabic
Span.

The following graphic illustrates this by using the Run element embedded in a Span
element:
The following example demonstrates using Run and Span elements in documents.

XAML

<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FlowDirection="RightToLeft">

<FlowDocument>
<Paragraph>
<Span FlowDirection="RightToLeft" >
‫ستجد الملف هنا‬:
<Run FlowDirection="LeftToRight">
\\server1\filename\filename1.txt</Run>
‫!ثم باقى النص‬
</Span>
</Paragraph>
</FlowDocument>
</Page>

Span Elements
The Span element works as a boundary separator between texts with different flow
directions. Even Span elements with the same flow direction are considered to have
different bidirectional scopes which means that the Span elements are ordered in the
container’s FlowDirection, only the content within the Span element follows the
FlowDirection of the Span.

The following graphic shows the flow direction of several TextBlock elements.

The following example shows how to use the Span and Run elements to produce the
results shown in the previous graphic.

XAML

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<StackPanel >

<TextBlock FontSize="20" FlowDirection="RightToLeft">


<Run FlowDirection="LeftToRight">‫<العالم‬/Run>
<Run FlowDirection="LeftToRight" Foreground="Red" >‫<فى سالم‬/Run>
</TextBlock>

<TextBlock FontSize="20" FlowDirection="LeftToRight">


<Run FlowDirection="RightToLeft">‫<العالم‬/Run>
<Run FlowDirection="RightToLeft" Foreground="Red" >‫<فى سالم‬/Run>
</TextBlock>

<TextBlock FontSize="20" Foreground="Blue">‫<العالم فى سالم‬/TextBlock>

<Separator/>

<TextBlock FontSize="20" FlowDirection="RightToLeft">


<Span Foreground="Red" FlowDirection="LeftToRight">Hello</Span>
<Span FlowDirection="LeftToRight">World</Span>
</TextBlock>

<TextBlock FontSize="20" FlowDirection="LeftToRight">


<Span Foreground="Red" FlowDirection="RightToLeft">Hello</Span>
<Span FlowDirection="RightToLeft">World</Span>
</TextBlock>

<TextBlock FontSize="20" Foreground="Blue">Hello World</TextBlock>


</StackPanel>

</Page>

In the TextBlock elements in the sample, the Span elements are laid out according to the
FlowDirection of their parents, but the text within each Span element flows according to
its own FlowDirection. This is applicable to Latin and Arabic – or any other language.

Adding xml:lang
The following graphic shows another example that uses numbers and arithmetic
expressions, such as "200.0+21.4=221.4" . Notice that only the FlowDirection is set.

Users of this application will be disappointed by the output, even though the
FlowDirection is correct the numbers are not shaped as Arabic numbers should be
shaped.

XAML elements can include an XML attribute ( xml:lang ) that defines the language of
each element. XAML also supports a XML language principle whereby xml:lang values
applied to parent elements in the tree are used by child elements. In the previous
example, because a language was not defined for the Run element or any of its top level
elements, the default xml:lang was used, which is en-US for XAML. The internal number
shaping algorithm of Windows Presentation Foundation (WPF) selects numbers in the
corresponding language – in this case English. To make the Arabic numbers render
correctly xml:lang needs to be set.
The following graphic shows the example with xml:lang added.

The following example adds xml:lang to the application.

XAML

<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FlowDirection="RightToLeft">
<FlowDocument>
<Paragraph>
<Span FlowDirection="RightToLeft" Language="ar-SA">
221.4=21.4+200.0" :‫"العملية الحسابية‬
</Span>
</Paragraph>
</FlowDocument>
</Page>

Be aware that many languages have different xml:lang values depending on the
targeted region, for example, "ar-SA" and "ar-EG" represent two variations of Arabic.
The previous examples illustrate that you need to define both the xml:lang and
FlowDirection values.

FlowDirection with Non-text Elements


FlowDirection defines not only how text flows in a textual element but also the flow
direction of almost every other UI element. The following graphic shows a ToolBar that
uses a horizontal LinearGradientBrush to draw its background with a left to right
gradient.

After setting the FlowDirection to RightToLeft, not only the ToolBar buttons are arranged
from right to left, but even the LinearGradientBrush realigns its offsets to flow from right
to left.

The following graphic shows the realignment of the LinearGradientBrush.

The following example draws a RightToLeftToolBar. (To draw it left to right, remove the
FlowDirection attribute on the ToolBar.

XAML
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<ToolBar FlowDirection="RightToLeft" Height="50" DockPanel.Dock="Top">


<ToolBar.Background>
<LinearGradientBrush StartPoint="0,0.5" EndPoint="1,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="DarkRed" Offset="0" />
<GradientStop Color="DarkBlue" Offset="0.3" />
<GradientStop Color="LightBlue" Offset="0.6" />
<GradientStop Color="White" Offset="1" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</ToolBar.Background>

<Button FontSize="12" Foreground="White">Button1</Button>


<Rectangle Width="20"/>
<Button FontSize="12" Foreground="White">Button2</Button>
<Rectangle Width="20"/>
<Button FontSize="12" Foreground="White">Button3</Button>
<Rectangle Width="20"/>
<Button FontSize="12" Foreground="White">Button4</Button>
<Rectangle Width="20"/>
</ToolBar>
</Page>

FlowDirection Exceptions
There are a few cases where FlowDirection does not behave as expected. This section
covers two of these exceptions.

Image

An Image represents a control that displays an image. In XAML it can be used with a
Source property that defines the uniform resource identifier (URI) of the Image to
display.

Unlike other UI elements, an Image does not inherit the FlowDirection from the
container. However, if the FlowDirection is set explicitly to RightToLeft, an Image is
displayed flipped horizontally. This is implemented as a convenient feature for
developers of bidirectional content; because in some cases, horizontally flipping the
image produces the desired effect.

The following graphic shows a flipped Image.


The following example demonstrates that the Image fails to inherit the FlowDirection
from the StackPanel that contains it.

7 Note

You must have a file named ms_logo.jpg on your C:\ drive to run this example.

XAML

<StackPanel
xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
FlowDirection="RightToLeft">

<Image Source="file://c:/ms_logo.jpg"
Width="147" Height="50"/>
<Separator Height="10"/>
<Image Source="file://c:/ms_logo.jpg"
Width="147" Height="50" FlowDirection="LeftToRight" />
<Separator Height="10"/>
<Image Source="file://c:/ms_logo.jpg"
Width="147" Height="50" FlowDirection="RightToLeft"/>
</StackPanel>

7 Note

Included in the download files is an ms_logo.jpg file. The code assumes that the
.jpg file is not inside your project but somewhere on the C:\ drive. You must copy
the .jpg from the project files to your C:\ drive or change the code to look for the
file inside the project. To do this change Source="file://c:/ms_logo.jpg" to
Source="ms_logo.jpg" .

Paths

In addition to an Image, another interesting element is Path. A Path is an object that can
draw a series of connected lines and curves. It behaves in a manner similar to an Image
regarding its FlowDirection; for example its RightToLeftFlowDirection is a horizontal
mirror of its LeftToRight one. However, unlike an Image, Path inherits its FlowDirection
from the container and one does not need to specify it explicitly.

The following example draws a simple arrow using 3 lines. The first arrow inherits the
RightToLeft flow direction from the StackPanel so that its start and end points are
measured from a root on the right side. The second arrow which has an explicit
RightToLeftFlowDirection also starts on the right side. However, the third arrow has its
starting root on the left side. For more information on drawing see LineGeometry and
GeometryGroup.

XAML

<StackPanel
xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
FlowDirection="RightToLeft">

<Path Stroke="Blue" StrokeThickness="4">


<Path.Data>
<GeometryGroup >
<LineGeometry StartPoint="300,10" EndPoint="350,30" />
<LineGeometry StartPoint="10,30" EndPoint="352,30" />
<LineGeometry StartPoint="300,50" EndPoint="350,30" />
</GeometryGroup>
</Path.Data>
</Path>

<Path Stroke="Red" StrokeThickness="4" FlowDirection="RightToLeft">


<Path.Data>
<GeometryGroup >
<LineGeometry StartPoint="300,10" EndPoint="350,30" />
<LineGeometry StartPoint="10,30" EndPoint="352,30" />
<LineGeometry StartPoint="300,50" EndPoint="350,30" />
</GeometryGroup>
</Path.Data>
</Path>

<Path Stroke="Green" StrokeThickness="4" FlowDirection="LeftToRight">


<Path.Data>
<GeometryGroup >
<LineGeometry StartPoint="300,10" EndPoint="350,30" />
<LineGeometry StartPoint="10,30" EndPoint="352,30" />
<LineGeometry StartPoint="300,50" EndPoint="350,30" />
</GeometryGroup>
</Path.Data>
</Path>
</StackPanel>

The following graphic shows the output of the previous example with arrows drawn
using the Path element:

The Image and Path are two examples of a how UI elements in a specific direction within
a container, FlowDirection can be used with elements such as InkPresenter which
renders ink on a surface, LinearGradientBrush, RadialGradientBrush. Whenever you need
a right to left behavior for your content that mimics a left to right behavior, or vice
versa, Windows Presentation Foundation (WPF) provides that capability.

Number Substitution
Historically, Windows has supported number substitution by allowing the representation
of different cultural shapes for the same digits while keeping the internal storage of
these digits unified among different locales, for example numbers are stored in their
well known hexadecimal values, 0x40, 0x41, but displayed according to the selected
language.

This has allowed applications to process numerical values without the need to convert
them from one language to another, for example a user can open an Microsoft Excel
spreadsheet in a localized Arabic Windows and see the numbers shaped in Arabic, but
open it in a European version of Windows and see European representation of the same
numbers. This is also necessary for other symbols such as comma separators and
percentage symbol because they usually accompany numbers in the same document.

Windows Presentation Foundation (WPF) continues the same tradition, and adds further
support for this feature that allows more user control over when and how substitution is
used. While this feature is designed for any language, it is particularly useful in
bidirectional content where shaping digits for a specific language is usually a challenge
for application developers because of the various cultures an application might run on.

The core property controlling how number substitution works in Windows Presentation
Foundation (WPF) is the Substitution dependency property. The NumberSubstitution
class specifies how numbers in text are to be displayed. It has three public properties
that define its behavior. The following is a summary of each of the properties:

CultureSource:

This property specifies how the culture for numbers is determined. It takes one of three
NumberCultureSource enumeration values.

Override: Number culture is that of CultureOverride property.

Text: Number culture is the culture of the text run. In markup, this would be
xml:lang , or its alias Language property (Language or Language). Also, it is the

default for classes deriving from FrameworkContentElement. Such classes include


System.Windows.Documents.Paragraph, System.Windows.Documents.Table,
System.Windows.Documents.TableCell and so forth.

User: Number culture is the culture of the current thread. This property is the
default for all subclasses of FrameworkElement such as Page, Window and
TextBlock.

CultureOverride:

The CultureOverride property is used only if the CultureSource property is set to


Override and is ignored otherwise. It specifies the number culture. A value of null , the
default value, is interpreted as en-US.

Substitution:

This property specifies the type of number substitution to perform. It takes one of the
following NumberSubstitutionMethod enumeration values:

AsCulture: The substitution method is determined based on the number culture's


NumberFormatInfo.DigitSubstitution property. This is the default.

Context: If the number culture is an Arabic or Persian culture, it specifies that the
digits depend on the context.

European: Numbers are always rendered as European digits.


NativeNational: Numbers are rendered using the national digits for the number
culture, as specified by the culture's NumberFormat.

Traditional: Numbers are rendered using the traditional digits for the number
culture. For most cultures, this is the same as NativeNational. However,
NativeNational results in Latin digits for some Arabic cultures, whereas this value
results in Arabic digits for all Arabic cultures.

What do those values mean for a bidirectional content developer? In most cases, the
developer might need only to define FlowDirection and the language of each textual UI
element, for example Language="ar-SA" and the NumberSubstitution logic takes care of
displaying the numbers according to the correct UI. The following example
demonstrates using Arabic and English numbers in a Windows Presentation Foundation
(WPF) application running in an Arabic version of Windows.

XAML

<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<StackPanel>
<TextBlock Background="LightGreen" FontSize="32"
Language="ar-SA" FlowDirection="RightToLeft">1+2=3</TextBlock>
<TextBox Background="LightGreen" FontSize="32"
Language="ar-SA" FlowDirection="RightToLeft">1+2=3</TextBox>
<TextBlock Background="LightBlue" FontSize="32">1+2=3</TextBlock>
<TextBox Background="LightBlue" FontSize="32">1+2=3</TextBox>
</StackPanel>
</Page>

The following graphic shows the output of the previous sample if you're running in an
Arabic version of Windows with Arabic and English numbers displayed:
The FlowDirection was important in this case because setting the FlowDirection to
LeftToRight instead would have yielded European digits. The following sections discuss
how to have a unified display of digits throughout your document. If this example is not
running on Arabic Windows, all the digits display as European digits.

Defining Substitution Rules

In a real application you might need to set the Language programmatically. For
example, you want to set the xml:lang attribute to be the same as the one used by the
system’s UI, or maybe change the language depending on the application state.

If you want to make changes based on the application's state, make use of other
features provided by Windows Presentation Foundation (WPF).

First, set the application component’s NumberSubstitution.CultureSource="Text" . Using


this setting makes sure that the settings do not come from the UI for text elements that
have "User" as the default, such as TextBlock.

For example:
XAML

<TextBlock
Name="text1" NumberSubstitution.CultureSource="Text">
1234+5679=6913
</TextBlock>

In the corresponding C# code, set the Language property, for example, to "ar-SA" .

C#

text1.Language = System.Windows.Markup.XmlLanguage.GetLanguage("ar-SA");

If you need to set the Language property to the current user’s UI language use the
following code.

C#

text1.Language =
System.Windows.Markup.XmlLanguage.GetLanguage(System.Globalization.CultureIn
fo.CurrentUICulture.IetfLanguageTag);

CultureInfo.CurrentCulture represents the current culture used by the current thread at


run time.

Your final XAML example should be similar to the following example.

XAML

<Page x:Class="WindowsApplication.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Code Sample" Height="300" Width="300"
>
<StackPanel>
<TextBlock Language="ar-SA"
FlowDirection="RightToLeft">3=2+1 :‫عربى‬
</TextBlock>
<TextBlock Language="ar-SA"
FlowDirection="RightToLeft"
NumberSubstitution.Substitution="European">3=2+1 :‫عربى‬
</TextBlock>
</StackPanel>
</Page>

Your final C# example should be similar to the following.


C#

namespace BidiTest
{
public partial class Window1 : Window
{

public Window1()
{
InitializeComponent();

string currentLanguage =

System.Globalization.CultureInfo.CurrentCulture.IetfLanguageTag;

text1.Language =
System.Windows.Markup.XmlLanguage.GetLanguage(currentLanguage);

if (currentLanguage.ToLower().StartsWith("ar"))
{
text1.FlowDirection = FlowDirection.RightToLeft;
}
else
{
text1.FlowDirection = FlowDirection.LeftToRight;
}
}
}
}

The following graphic shows what the window looks like for either programming
language, displaying Arabic numbers:

Using the Substitution Property

The way number substitution works in Windows Presentation Foundation (WPF)


depends on both the Language of the text element and its FlowDirection. If the
FlowDirection is left to right, then European digits are rendered. However if it is
preceded by Arabic text, or has the language set to "ar" and the FlowDirection is
RightToLeft, Arabic digits are rendered instead.

In some cases, however, you might want to create a unified application, for example
European digits for all users. Or Arabic digits in Table cells with a specific Style. One easy
way to do that is using the Substitution property.
In the following example, the first TextBlock does not have the Substitution property set,
so the algorithm displays Arabic digits as expected. However in the second TextBlock,
the substitution is set to European overriding the default substitution for Arabic
numbers, and European digits are displayed.

XAML

<Page x:Class="WindowsApplication.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Code Sample" Height="300" Width="300"
>
<StackPanel>
<TextBlock Language="ar-SA"
FlowDirection="RightToLeft">3=2+1 :‫عربى‬
</TextBlock>
<TextBlock Language="ar-SA"
FlowDirection="RightToLeft"
NumberSubstitution.Substitution="European">3=2+1 :‫عربى‬
</TextBlock>
</StackPanel>
</Page>
How to: Localize an application
Article • 02/24/2022

This tutorial explains how to create a localized application by using the LocBaml tool.

7 Note

The LocBaml tool is not a production-ready application. It is presented as a sample that uses some of the localization APIs and
illustrates how you might write a localization tool.

Overview
This article gives you a step-by-step approach to localizing an application. First, you prepare your application so that the text that will be
translated can be extracted. After the text is translated, you merge the translated text into a new copy of the original application.

Create a sample application


In this step, you prepare your app for localization. In the Windows Presentation Foundation (WPF) samples, a HelloApp sample is supplied
that will be used for the code examples in this discussion. If you would like to use this sample, download the Extensible Application Markup
Language (XAML) files from the LocBaml Tool Sample .

1. Develop your application to the point where you want to start localization.

2. Specify the development language in the project file so that MSBuild generates a main assembly and a satellite assembly (a file with
the .resources.dll extension) to contain the neutral language resources. The project file in the HelloApp sample is HelloApp.csproj. In
that file, you will find the development language identified as follows:

<UICulture>en-US</UICulture>

3. Add Uids to your XAML files. Uids are used to keep track of changes to files and to identify items that must be translated. To add Uids
to your files, run updateuid on your project file:

msbuild -t:updateuid helloapp.csproj

To verify that you have no missing or duplicate Uids, run checkuid :

msbuild -t:checkuid helloapp.csproj

After running updateuid , your files should contain Uids. For example, in the Pane1.xaml file of HelloApp, you should find the
following:

XAML

<StackPanel x:Uid="StackPanel_1">
<TextBlock x:Uid="TextBlock_1">Hello World</TextBlock>
<TextBlock x:Uid="TextBlock_2">Goodbye World</TextBlock>
</StackPanel>

Create the neutral-language resources satellite assembly


After the application is configured to generate a neutral-language resources satellite assembly, you build the application. This generates
the main application assembly as well as the neutral-language resources satellite assembly that's required by LocBaml for localization.

To build the application:

1. Compile HelloApp to create a dynamic-link library (DLL):

msbuild helloapp.csproj

2. The newly created main application assembly, HelloApp.exe, is created in the following folder: C:\HelloApp\Bin\Debug

3. The newly created neutral-language resources satellite assembly, HelloApp.resources.dll, is created in the following folder:
C:\HelloApp\Bin\Debug\en-US
Build the LocBaml tool
1. All the files necessary to build LocBaml are located in the WPF samples. Download the C# files from the LocBaml Tool Sample .

2. From the command line, run the project file (locbaml.csproj) to build the tool:

msbuild locbaml.csproj

3. Go to the Bin\Release directory to find the newly created executable file (locbaml.exe). Example: C:\LocBaml\Bin\Release\locbaml.exe

4. The options that you can specify when you run LocBaml are as follows.

Option Description

parse or -p Parses Baml, resources, or DLL files to generate a .csv or .txt file.

generate or -g Generates a localized binary file by using a translated file.

out or -o {filedirectory] Output file name.

culture or -cul {culture] Locale of output assemblies.

translation or -trans {translation.csv] Translated or localized file.

asmpath or -asmpath {filedirectory] If your XAML code contains custom controls, you must supply the asmpath to the custom control assembly.

nologo Displays no logo or copyright information.

verbose Displays verbose mode information.

7 Note

If you need a list of the options when you are running the tool, enter LocBaml.exe and then press Enter.

Use LocBaml to parse a file


Now that you have created the LocBaml tool, you are ready to use it to parse HelloApp.resources.dll to extract the text content that will be
localized.

1. Copy LocBaml.exe to your application's bin\debug folder, where the main application assembly was created.

2. To parse the satellite assembly file and store the output as a .csv file, use the following command:

LocBaml.exe /parse HelloApp.resources.dll /out:Hello.csv

7 Note

If the input file, HelloApp.resources.dll, is not in the same directory as LocBaml.exe move one of the files so that both files are in
the same directory.

3. When you run LocBaml to parse files, the output consists of seven fields delimited by commas (.csv files) or tabs (.txt files). The
following shows the parsed .csv file for the HelloApp.resources.dll:

Parsed .csv file

HelloApp.g.en-US.resources:window1.baml,Stack1:System.Windows.Controls.StackPanel.$Content,Ignore,FALSE, FALSE,,#Text1;#Text2;

HelloApp.g.en-US.resources:window1.baml,Text1:System.Windows.Controls.TextBlock.$Content,None,TRUE, TRUE,,Hello World

HelloApp.g.en-US.resources:window1.baml,Text2:System.Windows.Controls.TextBlock.$Content,None,TRUE, TRUE,,Goodbye World

The seven fields are:

BAML Name. The name of the BAML resource with respect to the source language satellite assembly.

Resource Key. The localized resource identifier.

Category. The value type. See Localization Attributes and Comments.


Readability. Whether the value can be read by a localizer. See Localization Attributes and Comments.

Modifiability. Whether the value can be modified by a localizer. See Localization Attributes and Comments.

Comments. Additional description of the value to help determine how a value is localized. See Localization Attributes and
Comments.

Value. The text value to translate to the desired culture.

The following table shows how these fields map to the delimited values of the .csv file:

BAML name Resource key Category Readability Modifiability Comments Value

HelloApp.g.en- Stack1:System.Windows.Controls.StackPanel.$Content Ignore FALSE FALSE #Text1;#Text2


US.resources:window1.baml

HelloApp.g.en- Text1:System.Windows.Controls.TextBlock.$Content None TRUE TRUE Hello World


US.resources:window1.baml

HelloApp.g.en- Text2:System.Windows.Controls.TextBlock.$Content None TRUE TRUE Goodbye


US.resources:window1.baml World

Notice that all the values for the Comments field contain no values; if a field doesn't have a value, it is empty. Also notice that the
item in the first row is neither readable nor modifiable, and has "Ignore" as its Category value, all of which indicates that the value is
not localizable.

4. To facilitate discovery of localizable items in parsed files, particularly in large files, you can sort or filter the items by Category,
Readability, and Modifiability. For example, you can filter out unreadable and unmodifiable values.

Translate the localizable content


Use any tool that you have available to translate the extracted content. A good way to do this is to write the resources to a .csv file and
view them in Microsoft Excel, making translation changes to the last column (value).

Use LocBaml to generate a new .resources.dll file


The content that was identified by parsing HelloApp.resources.dll with LocBaml has been translated and must be merged back into the
original application. Use the generate or -g option to generate a new .resources.dll file.

1. Use the following syntax to generate a new HelloApp.resources.dll file. Mark the culture as en-US (/cul:en-US).

LocBaml.exe /generate HelloApp.resources.dll /trans:Hello.csv /out:c:\ /cul:en-US

7 Note

If the input file, Hello.csv, is not in the same directory as the executable, LocBaml.exe, move one of the files so that both files are
in the same directory.

2. Replace the old HelloApp.resources.dll file in the C:\HelloApp\Bin\Debug\en-US\HelloApp.resources.dll directory with your newly
created HelloApp.resources.dll file.

3. "Hello World" and "Goodbye World" should now be translated in your application.

4. To translate to a different culture, use the culture of the language that you are translating to. The following example shows how to
translate to French-Canadian:

LocBaml.exe /generate HelloApp.resources.dll /trans:Hellofr-CA.csv /out:c:\ /cul:fr-CA

5. In the same assembly as the main application assembly, create a new culture-specific folder to house the new satellite assembly. For
French-Canadian, the folder would be fr-CA.

6. Copy the generated satellite assembly to the new folder.

7. To test the new satellite assembly, you need to change the culture under which your application will run. You can do this in one of two
ways:

Change your operating system's regional settings.


In your application, add the following code to App.xaml.cs:

XAML

<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App"
x:Uid="Application_1"
StartupUri="Window1.xaml">
</Application>

C#

using System.Windows;
using System.Globalization;
using System.Threading;

namespace SDKSample
{
public partial class App : Application
{
public App()
{
// Change culture under which this application runs
CultureInfo ci = new CultureInfo("fr-CA");
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
}
}
}

Tips for Using LocBaml


All dependent assemblies that define custom controls must be copied into the local directory of LocBaml or installed into the GAC.
This is necessary because the localization API must have access to the dependent assemblies when it reads the binary XAML (BAML).

If the main assembly is signed, the generated resource DLL must also be signed in order for it to be loaded.

The version of the localized resource DLL needs to be synchronized with the main assembly.

See also
Globalization for WPF
Use Automatic Layout Overview
How to: Use Automatic Layout to Create
a Button
Article • 08/10/2023

This example describes how to use the automatic layout approach to create a button in
a localizable application.

Localization of a user interface (UI) can be a time consuming process. Often localizers
need to resize and reposition elements in addition to translating text. In the past each
language that a UI was adapted for required adjustment. Now with the capabilities of
Windows Presentation Foundation (WPF) you can design elements that reduce the need
for adjustment. The approach to writing applications that can be more easily resized and
repositioned is called automatic layout .

Example
The following two Extensible Application Markup Language (XAML) examples create
applications that instantiate a button; one with English text and one with Spanish text.
Notice that the code is the same except for the text; the button adjusts to fit the text.

XAML

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ButtonLoc.Pane1"
Name="myWindow"
SizeToContent="WidthAndHeight"
>

<DockPanel>
<Button FontSize="28" Height="50">My name is Hope.</Button>
</DockPanel>
</Window>

XAML

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ButtonLoc.Pane1"
Name="myWindow"
SizeToContent="WidthAndHeight"
>
<DockPanel>
<Button FontSize="28" Height="50">Me llamo Esperanza.</Button>
</DockPanel>
</Window>

The following graphic shows the output of the code samples with auto-resizable
buttons:

See also
Use Automatic Layout Overview
Use a Grid for Automatic Layout
How to: Use a Grid for Automatic
Layout
Article • 08/10/2023

This example describes how to use a grid in the automatic layout approach to creating a
localizable application.

Localization of a user interface (UI) can be a time consuming process. Often localizers
need to re-size and reposition elements in addition to translating text. In the past each
language that a UI was adapted for required adjustment. Now with the capabilities of
Windows Presentation Foundation (WPF) you can design elements that reduce the need
for adjustment. The approach to writing applications that can be more easily re-sized
and repositioned is called auto layout .

The following Extensible Application Markup Language (XAML) example demonstrates


using a grid to position some buttons and text. Notice that the height and width of the
cells are set to Auto ; therefore the cell that contains the button with an image adjusts to
fit the image. Because the Grid element can adjust to its content it can be useful when
taking the automatic layout approach to designing applications that can be localized.

Example
The following example shows how to use a grid.

XAML

<Grid Name="grid" ShowGridLines ="false">


<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<TextBlock Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="0"


FontSize="24">Grid
</TextBlock>
<TextBlock Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="1" FontSize="12"
Grid.ColumnSpan="2">The following buttons and text are positioned using
a Grid.
</TextBlock>
<Button Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="2" Background="Pink"
BorderBrush="Black" BorderThickness="10">Button 1
</Button>
<TextBlock Margin="10, 10, 5, 5" Grid.Column="1" Grid.Row="2" FontSize="12"
VerticalAlignment="Center" TextWrapping="WrapWithOverflow">Sets the
background
color.
</TextBlock>
<Button Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="3" Foreground="Red">
Button 2
</Button>
<TextBlock Margin="10, 10, 5, 5" Grid.Column="1" Grid.Row="3" FontSize="12"
VerticalAlignment="Center" TextWrapping="WrapWithOverflow">Sets the
foreground
color.
</TextBlock>
<Button Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="4">
<Image Source="data\flower.jpg"></Image>
</Button>
<TextBlock Margin="10, 10, 5, 5" Grid.Column="1" Grid.Row="4" FontSize="12"
VerticalAlignment="Center" TextWrapping="WrapWithOverflow">Adds an image
as
the button's content.
</TextBlock>
</Grid>

The following graphic shows the output of the code sample.

Grid

See also
Use Automatic Layout Overview
Use Automatic Layout to Create a Button
How to: Use a ResourceDictionary to
Manage Localizable String Resources
Article • 06/02/2023

This example shows how to use a ResourceDictionary to package localizable string


resources for Windows Presentation Foundation (WPF) applications.

To use a ResourceDictionary to manage localizable string


resources
1. Create a ResourceDictionary file in the root of your project named
StringResources.xaml that contains the strings you would like to localize. The
following code shows an example.

XAML

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">

<!-- String resource that can be localized -->


<system:String x:Key="localizedMessage">en-US Message</system:String>

</ResourceDictionary>

This code defines a string resource, localizedMessage , of type String, from the
System namespace in mscorlib.dll.

2. Add the ResourceDictionary to your application, using the following code.

XAML

<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="StringResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>

3. Use the string resource from markup, using Extensible Application Markup
Language (XAML) like the following.
XAML

<!-- Declarative use of string resource from StringResources.xaml


resource dictionary -->
<TextBox DockPanel.Dock="Top" Text="{StaticResource localizedMessage}"
/>

4. Use the string resource from code-behind, using code like the following.

C#

// Programmatic use of string resource from StringResources.xaml


resource dictionary
string localizedMessage =
(string)Application.Current.FindResource("localizedMessage");
MessageBox.Show(localizedMessage);

5. Localize the application. For more information, see Localize an Application.


How to: Use resources in localizable
apps
Article • 08/18/2022

Localization means to adapt a user interface to different cultures. To do this, text such as
titles, captions, and list box items must be translated. To make translation easier, the
items to be translated are collected into resource files. See Localize an app for
information on how to create a resource file for localization. To make a WPF application
localizable, developers need to build all the localizable resources into a resource
assembly. The resource assembly is localized into different languages, and the code-
behind uses resource management API to load.

Example
One of the files required for a WPF application is a project file (.proj). All resources that
you use in your application should be included in the project file. The following XAML
example shows this.

XAML

<Resource Include="data\picture1.jpg"/>
<EmbeddedResource Include="data\stringtable.en-US.restext"/>

To use a resource in your application, instantiate ResourceManager and load the


resource you want to use. The following C# code demonstrates how to do this.

C#

void OnClick(object sender, RoutedEventArgs e)


{
ResourceManager rm = new ResourceManager ("MySampleApp.data.stringtable",
Assembly.GetExecutingAssembly());
Text1.Text = rm.GetString("Message");
}

See also
Localize an app
Layout
Article • 03/17/2022

This topic describes the Windows Presentation Foundation (WPF) layout system.
Understanding how and when layout calculations occur is essential for creating user
interfaces in WPF.

This topic contains the following sections:

Element Bounding Boxes

The Layout System

Measuring and Arranging Children

Panel Elements and Custom Layout Behaviors

Layout Performance Considerations

Sub-pixel Rendering and Layout Rounding

What's Next

Element Bounding Boxes


When thinking about layout in WPF, it is important to understand the bounding box
that surrounds all elements. Each FrameworkElement consumed by the layout system
can be thought of as a rectangle that is slotted into the layout. The LayoutInformation
class returns the boundaries of an element's layout allocation, or slot. The size of the
rectangle is determined by calculating the available screen space, the size of any
constraints, layout-specific properties (such as margin and padding), and the individual
behavior of the parent Panel element. Processing this data, the layout system is able to
calculate the position of all the children of a particular Panel. It is important to
remember that sizing characteristics defined on the parent element, such as a Border,
affect its children.

The following illustration shows a simple layout.


This layout can be achieved by using the following XAML.

XAML

<Grid Name="myGrid" Background="LightSteelBlue" Height="150">


<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Name="txt1" Margin="5" FontSize="16" FontFamily="Verdana"
Grid.Column="0" Grid.Row="0">Hello World!</TextBlock>
<Button Click="getLayoutSlot1" Width="125" Height="25" Grid.Column="0"
Grid.Row="1">Show Bounding Box</Button>
<TextBlock Name="txt2" Grid.Column="1" Grid.Row="2"/>
</Grid>

A single TextBlock element is hosted within a Grid. While the text fills only the upper-left
corner of the first column, the allocated space for the TextBlock is actually much larger.
The bounding box of any FrameworkElement can be retrieved by using the
GetLayoutSlot method. The following illustration shows the bounding box for the
TextBlock element.

As shown by the yellow rectangle, the allocated space for the TextBlock element is
actually much larger than it appears. As additional elements are added to the Grid, this
allocation could shrink or expand, depending on the type and size of elements that are
added.

The layout slot of the TextBlock is translated into a Path by using the GetLayoutSlot
method. This technique can be useful for displaying the bounding box of an element.

C#

private void getLayoutSlot1(object sender, System.Windows.RoutedEventArgs e)


{
RectangleGeometry myRectangleGeometry = new RectangleGeometry();
myRectangleGeometry.Rect = LayoutInformation.GetLayoutSlot(txt1);
Path myPath = new Path();
myPath.Data = myRectangleGeometry;
myPath.Stroke = Brushes.LightGoldenrodYellow;
myPath.StrokeThickness = 5;
Grid.SetColumn(myPath, 0);
Grid.SetRow(myPath, 0);
myGrid.Children.Add(myPath);
txt2.Text = "LayoutSlot is equal to " +
LayoutInformation.GetLayoutSlot(txt1).ToString();
}

The Layout System


At its simplest, layout is a recursive system that leads to an element being sized,
positioned, and drawn. More specifically, layout describes the process of measuring and
arranging the members of a Panel element's Children collection. Layout is an intensive
process. The larger the Children collection, the greater the number of calculations that
must be made. Complexity can also be introduced based on the layout behavior defined
by the Panel element that owns the collection. A relatively simple Panel, such as Canvas,
can have significantly better performance than a more complex Panel, such as Grid.

Each time that a child UIElement changes its position, it has the potential to trigger a
new pass by the layout system. Therefore, it is important to understand the events that
can invoke the layout system, as unnecessary invocation can lead to poor application
performance. The following describes the process that occurs when the layout system is
invoked.

1. A child UIElement begins the layout process by first having its core properties
measured.

2. Sizing properties defined on FrameworkElement are evaluated, such as Width,


Height, and Margin.

3. Panel-specific logic is applied, such as Dock direction or stacking Orientation.

4. Content is arranged after all children have been measured.

5. The Children collection is drawn on the screen.

6. The process is invoked again if additional Children are added to the collection, a
LayoutTransform is applied, or the UpdateLayout method is called.

This process and how it is invoked are defined in more detail in the following sections.

Measuring and Arranging Children


The layout system completes two passes for each member of the Children collection, a
measure pass and an arrange pass. Each child Panel provides its own MeasureOverride
and ArrangeOverride methods to achieve its own specific layout behavior.

During the measure pass, each member of the Children collection is evaluated. The
process begins with a call to the Measure method. This method is called within the
implementation of the parent Panel element, and does not have to be called explicitly
for layout to occur.

First, native size properties of the UIElement are evaluated, such as Clip and Visibility.
This generates a value named constraintSize that is passed to MeasureCore.

Secondly, framework properties defined on FrameworkElement are processed, which


affects the value of constraintSize . These properties generally describe the sizing
characteristics of the underlying UIElement, such as its Height, Width, Margin, and Style.
Each of these properties can change the space that is necessary to display the element.
MeasureOverride is then called with constraintSize as a parameter.

7 Note

There is a difference between the properties of Height and Width and


ActualHeight and ActualWidth. For example, the ActualHeight property is a
calculated value based on other height inputs and the layout system. The value is
set by the layout system itself, based on an actual rendering pass, and may
therefore lag slightly behind the set value of properties, such as Height, that are
the basis of the input change.

Because ActualHeight is a calculated value, you should be aware that there could
be multiple or incremental reported changes to it as a result of various operations
by the layout system. The layout system may be calculating required measure space
for child elements, constraints by the parent element, and so on.

The ultimate goal of the measure pass is for the child to determine its DesiredSize,
which occurs during the MeasureCore call. The DesiredSize value is stored by Measure
for use during the content arrange pass.

The arrange pass begins with a call to the Arrange method. During the arrange pass, the
parent Panel element generates a rectangle that represents the bounds of the child. This
value is passed to the ArrangeCore method for processing.

The ArrangeCore method evaluates the DesiredSize of the child and evaluates any
additional margins that may affect the rendered size of the element. ArrangeCore
generates an arrangeSize , which is passed to the ArrangeOverride method of the Panel
as a parameter. ArrangeOverride generates the finalSize of the child. Finally, the
ArrangeCore method does a final evaluation of offset properties, such as margin and
alignment, and puts the child within its layout slot. The child does not have to (and
frequently does not) fill the entire allocated space. Control is then returned to the parent
Panel and the layout process is complete.

Panel Elements and Custom Layout Behaviors


WPF includes a group of elements that derive from Panel. These Panel elements enable
many complex layouts. For example, stacking elements can easily be achieved by using
the StackPanel element, while more complex and free flowing layouts are possible by
using a Canvas.

The following table summarizes the available layout Panel elements.

Panel name Description

Canvas Defines an area within which you can explicitly position child elements by
coordinates relative to the Canvas area.

DockPanel Defines an area within which you can arrange child elements either
horizontally or vertically, relative to each other.

Grid Defines a flexible grid area that consists of columns and rows.

StackPanel Arranges child elements into a single line that can be oriented horizontally or
vertically.

VirtualizingPanel Provides a framework for Panel elements that virtualize their child data
collection. This is an abstract class.

WrapPanel Positions child elements in sequential position from left to right, breaking
content to the next line at the edge of the containing box. Subsequent
ordering occurs sequentially from top to bottom or right to left, depending on
the value of the Orientation property.

For applications that require a layout that is not possible by using any of the predefined
Panel elements, custom layout behaviors can be achieved by inheriting from Panel and
overriding the MeasureOverride and ArrangeOverride methods.

Layout Performance Considerations


Layout is a recursive process. Each child element in a Children collection gets processed
during each invocation of the layout system. As a result, triggering the layout system
should be avoided when it is not necessary. The following considerations can help you
achieve better performance.

Be aware of which property value changes will force a recursive update by the
layout system.

Dependency properties whose values can cause the layout system to be initialized
are marked with public flags. AffectsMeasure and AffectsArrange provide useful
clues as to which property value changes will force a recursive update by the
layout system. In general, any property that can affect the size of an element's
bounding box should have a AffectsMeasure flag set to true. For more information,
see Dependency Properties Overview.

When possible, use a RenderTransform instead of a LayoutTransform.

A LayoutTransform can be a very useful way to affect the content of a user


interface (UI). However, if the effect of the transform does not have to impact the
position of other elements, it is best to use a RenderTransform instead, because
RenderTransform does not invoke the layout system. LayoutTransform applies its
transformation and forces a recursive layout update to account for the new
position of the affected element.

Avoid unnecessary calls to UpdateLayout.

The UpdateLayout method forces a recursive layout update, and is frequently not
necessary. Unless you are sure that a full update is required, rely on the layout
system to call this method for you.

When working with a large Children collection, consider using a


VirtualizingStackPanel instead of a regular StackPanel.

By virtualizing the child collection, the VirtualizingStackPanel only keeps objects in


memory that are currently within the parent's ViewPort. As a result, performance is
substantially improved in most scenarios.

Sub-pixel Rendering and Layout Rounding


The WPF graphics system uses device-independent units to enable resolution and
device independence. Each device independent pixel automatically scales with the
system's dots per inch (dpi) setting. This provides WPF applications proper scaling for
different dpi settings and makes the application automatically dpi-aware.

However, this dpi independence can create irregular edge rendering because of anti-
aliasing. These artifacts, typically seen as blurry or semi-transparent edges, can occur
when the location of an edge falls in the middle of a device pixel instead of between
device pixels. The layout system provides a way to adjust for this with layout rounding.
Layout rounding is where the layout system rounds any non-integral pixel values during
the layout pass.

Layout rounding is disabled by default. To enable layout rounding, set the


UseLayoutRounding property to true on any FrameworkElement. Because it is a
dependency property, the value will propagate to all the children in the visual tree. To
enable layout rounding for the entire UI, set UseLayoutRounding to true on the root
container. For an example, see UseLayoutRounding.

What's Next
Understanding how elements are measured and arranged is the first step in
understanding layout. For more information about the available Panel elements, see
Panels Overview. To better understand the various positioning properties that can affect
layout, see Alignment, Margins, and Padding Overview. When you are ready to put it all
together in a lightweight application, see Walkthrough: My first WPF desktop
application.

See also
FrameworkElement
UIElement
Panels Overview
Alignment, Margins, and Padding Overview
Layout and Design
Migration and Interoperability
Article • 08/18/2022

This page contains links to documents that discuss how to implement interoperation
between Windows Presentation Foundation (WPF) applications and other types of
Microsoft Windows applications.

In This Section
Types migrated from WPF to System.Xaml
WPF and Windows Forms Interoperation
WPF and Win32 Interoperation
WPF and Direct3D9 Interoperation

Reference
Term Definition

WindowsFormsHost An element that you can use to host a Windows Forms control as an
element of a WPF page.

ElementHost A Windows Forms control that you can use to host a Windows
Presentation Foundation (WPF) control.

HwndSource Hosts a WPF region within a Win32 application.

HwndHost Base class for WindowsFormsHost, defines some basic functionality that
all HWND-based technologies use when hosted by a WPF application.
Subclass this to host a Win32 window within a WPF application.

BrowserInteropHelper A helper class for reporting conditions of the browser environment for a
WPF application that is hosted by a browser.

Related Sections
Types migrated from WPF to
System.Xaml
Article • 08/18/2022

In .NET Framework 3.5 and .NET Framework 3.0, both Windows Presentation Foundation
(WPF) and Windows Workflow Foundation included a XAML language implementation.
Many of the public types that provided extensibility for the WPF XAML implementation
existed in the WindowsBase, PresentationCore, and PresentationFramework assemblies.
Likewise, public types that provided extensibility for Windows Workflow Foundation
XAML existed in the System.Workflow.ComponentModel assembly. In the .NET
Framework 4, some of the XAML-related types were migrated to the System.Xaml
assembly. A common .NET Framework implementation of XAML language services
enables many XAML extensibility scenarios that were originally defined by a specific
framework's XAML implementation but are now part of overall .NET Framework 4 XAML
language support. This article lists the types that were migrated and discusses issues
related to the migration.

Assemblies and Namespaces


In .NET Framework 3.5 and .NET Framework 3.0, the types that WPF implemented to
support XAML were generally in the System.Windows.Markup namespace. Most of these
types were in the WindowsBase assembly.

In .NET Framework 4, there is a new System.Xaml namespace and a new System.Xaml


assembly. Many of the types that were originally implemented for WPF XAML are now
provided as extensibility points or services for any implementation of XAML. As part of
making them available for more general scenarios, the types are type-forwarded from
their original WPF assembly to the System.Xaml assembly. This enables XAML
extensibility scenarios without having to include the assemblies of other frameworks
(such as WPF and Windows Workflow Foundation).

For migrated types, most of the types remain in the System.Windows.Markup


namespace. This was partially to avoid breaking CLR namespace mappings in existing
implementations on a per-file basis. As a result, the System.Windows.Markup
namespace in .NET Framework 4 contains a mixture of general XAML language support
types (from the System.Xaml assembly) and types that are specific to the WPF XAML
implementation (from WindowsBase and other WPF assemblies). Any type that was
migrated to System.Xaml, but existed previously in a WPF assembly, has type-forwarding
support in version 4 of the WPF assembly.
Workflow XAML Support Types
Windows Workflow Foundation also provided XAML support types, and in many cases
these had identical short names to a WPF equivalent. The following is a list of Windows
Workflow Foundation XAML support types:

ContentPropertyAttribute

RuntimeNamePropertyAttribute

XmlnsPrefixAttribute

These support types still exist in the Windows Workflow Foundation assemblies for .NET
Framework 4 and can still be used for specific Windows Workflow Foundation
applications; however, they should not be referenced by applications or frameworks that
do not use Windows Workflow Foundation.

MarkupExtension
In the .NET Framework 3.5 and .NET Framework 3.0, the MarkupExtension class for WPF
was in the WindowsBase assembly. A parallel class for Windows Workflow Foundation,
MarkupExtension, existed in the System.Workflow.ComponentModel assembly. In the
.NET Framework 4, the MarkupExtension class is migrated to the System.Xaml assembly.
In the .NET Framework 4, MarkupExtension is intended for any XAML extensibility
scenario that uses .NET XAML Services, not just for those that build on specific
frameworks. When possible, specific frameworks or user code in the framework should
also build on the MarkupExtension class for XAML extension.

MarkupExtension Supporting Service Classes


.NET Framework 3.5 and .NET Framework 3.0 for WPF provided several services that
were available to MarkupExtension implementers and TypeConverter implementations
to support type/property usage in XAML. These services are the following:

IProvideValueTarget

IUriContext

IXamlTypeResolver

7 Note
Another service from .NET Framework 3.5 that is related to markup extensions is
the IReceiveMarkupExtension interface. IReceiveMarkupExtension was not
migrated and is marked [Obsolete] for .NET Framework 4. Scenarios that
previously used IReceiveMarkupExtension should instead use
XamlSetMarkupExtensionAttribute attributed callbacks.
AcceptedMarkupExtensionExpressionTypeAttribute is also marked [Obsolete] .

XAML Language Features


Several XAML language features and components for WPF previously existed in the
PresentationFramework assembly. These were implemented as a MarkupExtension
subclass to expose markup extension usages in XAML markup. In .NET Framework 4,
these exist in the System.Xaml assembly so that projects that do not include WPF
assemblies can use these XAML language-level features. WPF uses these same
implementations for .NET Framework 4 applications. As with the other cases that are
listed in this topic, the supporting types continue to exist in the
System.Windows.Markup namespace to avoid breaking previous references.

The following table contains a list of the XAML feature-support classes that are defined
in System.Xaml.

XAML Language Feature Usage

ArrayExtension <x:Array ...>

NullExtension {x:Null}

StaticExtension {x:Static ...}

TypeExtension {x:Type ...}

Although System.Xaml may not have specific support classes, the general logic for
processing language features for the XAML language now resides in System.Xaml and
its implemented XAML readers and XAML writers. For example, x:TypeArguments is an
attribute that is processed by XAML readers and XAML writers from System.Xaml
implementations; it can be noted in the XAML node stream, has handling in the default
(CLR-based) XAML schema context, has a XAML type-system representation, and so on.
For more information about the reference documentation for XAML, see XAML Services.

ValueSerializer and Supporting Classes


The ValueSerializer class supports type conversion to a string, particularly for XAML
serialization cases where serialization may require multiple modes or nodes in the
output. In .NET Framework 3.5 and .NET Framework 3.0, the ValueSerializer for WPF was
in the WindowsBase assembly. In the .NET Framework 4, the ValueSerializer class is in
System.Xaml and is intended for any XAML extensibility scenario, not just for those that
build on WPF. IValueSerializerContext (a supporting service) and DateTimeValueSerializer
(a specific subclass) are also migrated to System.Xaml.

XAML-Related Attributes
WPF XAML included several attributes that can be applied to CLR types to indicate
something about their XAML behavior. The following is a list of the attributes that
existed in WPF assemblies in .NET Framework 3.5 and .NET Framework 3.0. These
attributes are migrated to System.Xaml in .NET Framework 4.

AmbientAttribute

ContentPropertyAttribute

ContentWrapperAttribute

DependsOnAttribute

MarkupExtensionReturnTypeAttribute

NameScopePropertyAttribute

RootNamespaceAttribute

RuntimeNamePropertyAttribute

TrimSurroundingWhitespaceAttribute

ValueSerializerAttribute

WhitespaceSignificantCollectionAttribute

XmlLangPropertyAttribute

XmlnsCompatibleWithAttribute

XmlnsDefinitionAttribute

XmlnsPrefixAttribute
Miscellaneous Classes
The IComponentConnector interface existed in WindowsBase in .NET Framework 3.5 and
.NET Framework 3.0, but exists in System.Xaml in .NET Framework 4.
IComponentConnector is primarily intended for tooling support and XAML markup
compilers.

The INameScope interface existed in WindowsBase in .NET Framework 3.5 and .NET
Framework 3.0, but exists in System.Xaml in .NET Framework 4. INameScope defines
basic operations for a XAML namescope.

XAML-related Classes with Shared Names that


Exist in WPF and System.Xaml
The following classes exist in both the WPF assemblies and the System.Xaml assembly in
.NET Framework 4:

XamlReader

XamlWriter

XamlParseException

The WPF implementation is found in the System.Windows.Markup namespace, and


PresentationFramework assembly. The System.Xaml implementation is found in the
System.Xaml namespace. If you are using WPF types or are deriving from WPF types,
you should typically use the WPF implementations of XamlReader and XamlWriter
instead of the System.Xaml implementations. For more information, see Remarks in
System.Windows.Markup.XamlReader and System.Windows.Markup.XamlWriter.

If you are including references to both WPF assemblies and System.Xaml, and you also
are using include statements for both the System.Windows.Markup and System.Xaml
namespaces, you may need to fully qualify the calls to these APIs in order to resolve the
types without ambiguity.
WPF and Windows Forms
Interoperation
Article • 02/06/2023

WPF and Windows Forms present two different architectures for creating application
interfaces. The System.Windows.Forms.Integration namespace provides classes that
enable common interoperation scenarios. The two key classes that implement
interoperation capabilities are WindowsFormsHost and ElementHost. This topic
describes which interoperation scenarios are supported and which scenarios are not
supported.

7 Note

Special consideration is given to the hybrid control scenario. A hybrid control has a
control from one technology nested in a control from the other technology. This is
also called a nested interoperation. A multilevel hybrid control has more than one
level of hybrid control nesting. An example of a multilevel nested interoperation is
a Windows Forms control that contains a WPF control, which contains another
Windows Forms control. Multilevel hybrid controls are not supported.

Hosting Windows Forms Controls in WPF


The following interoperation scenarios are supported when a WPF control hosts a
Windows Forms control:

The WPF control may host one or more Windows Forms controls using XAML.

It may host one or more Windows Forms controls using code.

It may host Windows Forms container controls that contain other Windows Forms
controls.

It may host a master/detail form with a WPF master and Windows Forms details.

It may host a master/detail form with a Windows Forms master and WPF details.

It may host one or more ActiveX controls.

It may host one or more composite controls.

It may host hybrid controls using Extensible Application Markup Language (XAML).
It may host hybrid controls using code.

Layout Support
The following list describes the known limitations when the WindowsFormsHost element
attempts to integrate its hosted Windows Forms control into the WPF layout system.

In some cases, Windows Forms controls cannot be resized, or can be sized only to
specific dimensions. For example, a Windows Forms ComboBox control supports
only a single height, which is defined by the control's font size. In a WPF dynamic
layout, which assumes that elements can stretch vertically, a hosted ComboBox
control will not stretch as expected.

Windows Forms controls cannot be rotated or skewed. For example, when you
rotate your user interface by 90 degrees, hosted Windows Forms controls will
maintain their upright position.

In most cases, Windows Forms controls do not support proportional scaling.


Although the overall dimensions of the control will scale, child controls and
component elements of the control may not resize as expected. This limitation
depends on how well each Windows Forms control supports scaling.

In a WPF user interface, you can change the z-order of elements to control
overlapping behavior. A hosted Windows Forms control is drawn in a separate
HWND, so it is always drawn on top of WPF elements.

Windows Forms controls support autoscaling based on the font size. In a WPF user
interface, changing the font size does not resize the entire layout, although
individual elements may dynamically resize.

Ambient Properties
Some of the ambient properties of WPF controls have Windows Forms equivalents.
These ambient properties are propagated to the hosted Windows Forms controls and
exposed as public properties on the WindowsFormsHost control. The
WindowsFormsHost control translates each WPF ambient property into its Windows
Forms equivalent.

For more information, see Windows Forms and WPF Property Mapping.

Behavior
The following table describes interoperation behavior.

Behavior Supported Not supported

Transparency Windows Forms control rendering Some Windows Forms controls do


supports transparency. The background not support transparency. For
of the parent WPF control can become example, the TextBox and ComboBox
the background of hosted Windows controls will not be transparent when
Forms controls. hosted by WPF.

Tabbing Tab order for hosted Windows Forms Not applicable.


controls is the same as when those
controls are hosted in a Windows
Forms-based application.

Tabbing from a WPF control to a


Windows Forms control with the TAB
key and SHIFT+TAB keys works as
usual.

Windows Forms controls that have a


TabStop property value of false do not
receive focus when the user tabs
through controls.

- Each WindowsFormsHost control has


a TabIndex value, which determines
when that WindowsFormsHost control
will receive focus.
- Windows Forms controls that are
contained inside a WindowsFormsHost
container follow the order specified by
the TabIndex property. Tabbing from
the last tab index puts focus on the
next WPF control, if one exists. If no
other focusable WPF control exists,
tabbing returns to the first Windows
Forms control in the tab order.
- TabIndex values for controls inside the
WindowsFormsHost are relative to
sibling Windows Forms controls that
are contained in the
WindowsFormsHost control.
- Tabbing honors control-specific
behavior. For example, pressing the TAB
key in a TextBox control that has a
AcceptsTab property value of true
enters a tab in the text box instead of
moving the focus.
Behavior Supported Not supported

Navigation - Navigation with arrow keys in the Not applicable.


with arrow WindowsFormsHost control is the same
keys as in an ordinary Windows Forms
container control: The UP ARROW and
LEFT ARROW keys select the previous
control, and the DOWN ARROW and
RIGHT ARROW keys select the next
control.
- The UP ARROW and LEFT ARROW
keys from the first control that is
contained in the WindowsFormsHost
control perform the same action as the
SHIFT+TAB keyboard shortcut. If there
is a focusable WPF control, focus moves
outside the WindowsFormsHost
control. This behavior differs from the
standard ContainerControl behavior in
that no wrapping to the last control
occurs. If no other focusable WPF
control exists, focus returns to the last
Windows Forms control in the tab
order.
- The DOWN ARROW and RIGHT
ARROW keys from the last control that
is contained in the WindowsFormsHost
control perform the same action as the
TAB key. If there is a focusable WPF
control, focus moves outside the
WindowsFormsHost control. This
behavior differs from the standard
ContainerControl behavior in that no
wrapping to the first control occurs. If
no other focusable WPF control exists,
focus returns to the first Windows
Forms control in the tab order.

Accelerators Accelerators work as usual, except Duplicate accelerators across


where noted in the "Not supported" technologies do not work like
column. ordinary duplicate accelerators. When
an accelerator is duplicated across
technologies, with at least one on a
Windows Forms control and the other
on a WPF control, the Windows
Forms control always receives the
accelerator. Focus does not toggle
between the controls when the
duplicate accelerator is pressed.
Behavior Supported Not supported

Shortcut keys Shortcut keys work as usual, except - Windows Forms shortcut keys that
where noted in the "Not supported" are handled at the preprocessing
column. stage always take precedence over
WPF shortcut keys. For example, if
you have a ToolStrip control with
CTRL+S shortcut keys defined, and
there is a WPF command bound to
CTRL+S, the ToolStrip control handler
is always invoked first, regardless of
focus.
- Windows Forms shortcut keys that
are handled by the KeyDown event
are processed last in WPF. You can
prevent this behavior by overriding
the Windows Forms control's
IsInputKey method or handling the
PreviewKeyDown event. Return true
from the IsInputKey method, or set
the value of the
PreviewKeyDownEventArgs.IsInputKey
property to true in your
PreviewKeyDown event handler.

AcceptsReturn, Properties that change the default Windows Forms controls that change
AcceptsTab, keyboard behavior work as usual, default keyboard behavior by
and other assuming that the Windows Forms handling the KeyDown event are
control- control overrides the IsInputKey processed last in the host WPF
specific method to return true . control. Because these controls are
behavior processed last, they can produce
unexpected behavior.

Enter and When focus is not going to the Enter and Leave events are not raised
Leave Events containing ElementHost control, the when the following focus changes
Enter and Leave events are raised as occur:
usual when focus changes in a single
WindowsFormsHost control. - From inside to outside a
WindowsFormsHost control.
- From outside to inside a
WindowsFormsHost control.
- Outside a WindowsFormsHost
control.
- From a Windows Forms control
hosted in a WindowsFormsHost
control to an ElementHost control
hosted inside the same
WindowsFormsHost.
Behavior Supported Not supported

Multithreading All varieties of multithreading are Both the Windows Forms and WPF
supported. technologies assume a single-
threaded concurrency model. During
debugging, calls to framework
objects from other threads will raise
an exception to enforce this
requirement.

Security All interoperation scenarios require full No interoperation scenarios are


trust. allowed in partial trust.

Accessibility All accessibility scenarios are supported. Not applicable.


Assistive technology products function
correctly when they are used for hybrid
applications that contain both Windows
Forms and WPF controls.

Clipboard All Clipboard operations work as usual. Not applicable.


This includes cutting and pasting
between Windows Forms and WPF
controls.

Drag-and- All drag-and-drop operations work as Not applicable.


drop feature usual. This includes operations between
Windows Forms and WPF controls.

Hosting WPF Controls in Windows Forms


The following interoperation scenarios are supported when a Windows Forms control
hosts a WPF control:

Hosting one or more WPF controls using code.

Associating a property sheet with one or more hosted WPF controls.

Hosting one or more WPF pages in a form.

Starting a WPF window.

Hosting a master/detail form with a Windows Forms master and WPF details.

Hosting a master/detail form with a WPF master and Windows Forms details.

Hosting custom WPF controls.

Hosting hybrid controls.


Ambient Properties
Some of the ambient properties of Windows Forms controls have WPF equivalents.
These ambient properties are propagated to the hosted WPF controls and exposed as
public properties on the ElementHost control. The ElementHost control translates each
Windows Forms ambient property to its WPF equivalent.

For more information, see Windows Forms and WPF Property Mapping.

Behavior
The following table describes interoperation behavior.

Behavior Supported Not supported

Transparency WPF control rendering supports Not applicable.


transparency. The background of
the parent Windows Forms control
can become the background of
hosted WPF controls.

Multithreading All varieties of multithreading are Both the Windows Forms and WPF
supported. technologies assume a single-threaded
concurrency model. During debugging,
calls to framework objects from other
threads will raise an exception to enforce
this requirement.

Security All interoperation scenarios require No interoperation scenarios are allowed


full trust. in partial trust.

Accessibility All accessibility scenarios are Not applicable.


supported. Assistive technology
products function correctly when
they are used for hybrid
applications that contain both
Windows Forms and WPF controls.

Clipboard All Clipboard operations work as Not applicable.


usual. This includes cutting and
pasting between Windows Forms
and WPF controls.

Drag-and- All drag-and-drop operations work Not applicable.


drop feature as usual. This includes operations
between Windows Forms and WPF
controls.
See also
ElementHost
WindowsFormsHost
Walkthrough: Hosting a Windows Forms Control in WPF
Walkthrough: Hosting a Windows Forms Composite Control in WPF
Walkthrough: Hosting a WPF Composite Control in Windows Forms
Windows Forms and WPF Property Mapping
Windows Forms and WPF
Interoperability Input Architecture
Article • 02/06/2023

Interoperation between the WPF and Windows Forms requires that both technologies
have the appropriate keyboard input processing. This topic describes how these
technologies implement keyboard and message processing to enable smooth
interoperation in hybrid applications.

This topic contains the following subsections:

Modeless Forms and Dialog Boxes

WindowsFormsHost Keyboard and Message Processing

ElementHost Keyboard and Message Processing

Modeless Forms and Dialog Boxes


Call the EnableWindowsFormsInterop method on the WindowsFormsHost element to
open a modeless form or dialog box from a WPF-based application.

Call the EnableModelessKeyboardInterop method on the ElementHost control to open a


modeless WPF page in a Windows Forms-based application.

WindowsFormsHost Keyboard and Message


Processing
When hosted by a WPF-based application, Windows Forms keyboard and message
processing consists of the following:

The WindowsFormsHost class acquires messages from the WPF message loop,
which is implemented by the ComponentDispatcher class.

The WindowsFormsHost class creates a surrogate Windows Forms message loop


to ensure that ordinary Windows Forms keyboard processing occurs.

The WindowsFormsHost class implements the IKeyboardInputSink interface to


coordinate focus management with WPF.
The WindowsFormsHost controls register themselves and start their message
loops.

The following sections describe these parts of the process in more detail.

Acquiring Messages from the WPF Message Loop


The ComponentDispatcher class implements the message loop manager for WPF. The
ComponentDispatcher class provides hooks to enable external clients to filter messages
before WPF processes them.

The interoperation implementation handles the


ComponentDispatcher.ThreadFilterMessage event, which enables Windows Forms
controls to process messages before WPF controls.

Surrogate Windows Forms Message Loop


By default, the System.Windows.Forms.Application class contains the primary message
loop for Windows Forms applications. During interoperation, the Windows Forms
message loop does not process messages. Therefore, this logic must be reproduced.
The handler for the ComponentDispatcher.ThreadFilterMessage event performs the
following steps:

1. Filters the message using the IMessageFilter interface.

2. Calls the Control.PreProcessMessage method.

3. Translates and dispatches the message, if it is required.

4. Passes the message to the hosting control, if no other controls process the
message.

IKeyboardInputSink Implementation
The surrogate message loop handles keyboard management. Therefore, the
IKeyboardInputSink.TabInto method is the only IKeyboardInputSink member that
requires an implementation in the WindowsFormsHost class.

By default, the HwndHost class returns false for its IKeyboardInputSink.TabInto


implementation. This prevents tabbing from a WPF control to a Windows Forms control.

The WindowsFormsHost implementation of the IKeyboardInputSink.TabInto method


performs the following steps:
1. Finds the first or last Windows Forms control that is contained by the
WindowsFormsHost control and that can receive focus. The control choice
depends on traversal information.

2. Sets focus to the control and returns true .

3. If no control can receive focus, returns false .

WindowsFormsHost Registration
When the window handle to a WindowsFormsHost control is created, the
WindowsFormsHost control calls an internal static method that registers its presence for
the message loop.

During registration, the WindowsFormsHost control examines the message loop. If the
message loop has not been started, the ComponentDispatcher.ThreadFilterMessage
event handler is created. The message loop is considered to be running when the
ComponentDispatcher.ThreadFilterMessage event handler is attached.

When the window handle is destroyed, the WindowsFormsHost control removes itself
from registration.

ElementHost Keyboard and Message


Processing
When hosted by a Windows Forms application, WPF keyboard and message processing
consists of the following:

HwndSource, IKeyboardInputSink, and IKeyboardInputSite interface


implementations.

Tabbing and arrow keys.

Command keys and dialog box keys.

Windows Forms accelerator processing.

The following sections describe these parts in more detail.

Interface Implementations
In Windows Forms, keyboard messages are routed to the window handle of the control
that has focus. In the ElementHost control, these messages are routed to the hosted
element. To accomplish this, the ElementHost control provides an HwndSource instance.
If the ElementHost control has focus, the HwndSource instance routes most keyboard
input so that it can be processed by the WPF InputManager class.

The HwndSource class implements the IKeyboardInputSink and IKeyboardInputSite


interfaces.

Keyboard interoperation relies on implementing the OnNoMoreTabStops method to


handle TAB key and arrow key input that moves focus out of hosted elements.

Tabbing and Arrow Keys


The Windows Forms selection logic is mapped to the IKeyboardInputSink.TabInto and
OnNoMoreTabStops methods to implement TAB and arrow key navigation. Overriding
the Select method accomplishes this mapping.

Command Keys and Dialog Box Keys


To give WPF the first opportunity to process command keys and dialog keys, Windows
Forms command preprocessing is connected to the TranslateAccelerator method.
Overriding the Control.ProcessCmdKey method connects the two technologies.

With the TranslateAccelerator method, the hosted elements can handle any key
message, such as WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP,
including command keys, such as TAB, ENTER, ESC, and arrow keys. If a key message is
not handled, it is sent up the Windows Forms ancestor hierarchy for handling.

Accelerator Processing
To process accelerators correctly, Windows Forms accelerator processing must be
connected to the WPF AccessKeyManager class. Additionally, all WM_CHAR messages
must be correctly routed to hosted elements.

Because the default HwndSource implementation of the TranslateChar method returns


false , WM_CHAR messages are processed using the following logic:

The Control.IsInputChar method is overridden to ensure that all WM_CHAR


messages are forwarded to hosted elements.

If the ALT key is pressed, the message is WM_SYSCHAR. Windows Forms does not
preprocess this message through the IsInputChar method. Therefore, the
ProcessMnemonic method is overridden to query the WPF AccessKeyManager for
a registered accelerator. If a registered accelerator is found, AccessKeyManager
processes it.

If the ALT key is not pressed, the WPF InputManager class processes the unhandled
input. If the input is an accelerator, the AccessKeyManager processes it. The
PostProcessInput event is handled for WM_CHAR messages that were not
processed.

When the user presses the ALT key, accelerator visual cues are shown on the whole
form. To support this behavior, all ElementHost controls on the active form receive
WM_SYSKEYDOWN messages, regardless of which control has focus.

Messages are sent only to ElementHost controls in the active form.

See also
EnableWindowsFormsInterop
EnableModelessKeyboardInterop
ElementHost
WindowsFormsHost
Walkthrough: Hosting a Windows Forms Composite Control in WPF
Walkthrough: Hosting a WPF Composite Control in Windows Forms
WPF and Win32 Interoperation
Layout Considerations for the
WindowsFormsHost Element
Article • 02/06/2023

This topic describes how the WindowsFormsHost element interacts with the WPF layout
system.

WPF and Windows Forms support different, but similar, logic for sizing and positioning
elements on a form or page. When you create a hybrid user interface (UI) that hosts
Windows Forms controls in WPF, the WindowsFormsHost element integrates the two
layout schemes.

Differences in Layout Between WPF and


Windows Forms
WPF uses resolution-independent layout. All WPF layout dimensions are specified using
device-independent pixels. A device-independent pixel is one ninety-sixth of an inch in
size and resolution-independent, so you get similar results regardless of whether you
are rendering to a 72-dpi monitor or a 19,200-dpi printer.

WPF is also based on dynamic layout. This means that a UI element arranges itself on a
form or page according to its content, its parent layout container, and the available
screen size. Dynamic layout facilitates localization by automatically adjusting the size
and position of UI elements when the strings they contain change length.

Layout in Windows Forms is device-dependent and more likely to be static. Typically,


Windows Forms controls are positioned absolutely on a form using dimensions specified
in hardware pixels. However, Windows Forms does support some dynamic layout
features, as summarized in the following table.

Layout Description
feature

Autosizing Some Windows Forms controls resize themselves to display their contents properly.
For more information, see AutoSize Property Overview.

Anchoring Windows Forms controls support positioning and sizing based on the parent
and container. For more information, see Control.Anchor and Control.Dock.
docking
Layout Description
feature

Autoscaling Container controls resize themselves and their children based on the resolution of
the output device or the size, in pixels, of the default container font. For more
information, see Automatic Scaling in Windows Forms.

Layout The FlowLayoutPanel and TableLayoutPanel controls arrange their child controls
containers and size themselves according to their contents.

Layout Limitations
In general, Windows Forms controls cannot be scaled and transformed to the extent
possible in WPF. The following list describes the known limitations when the
WindowsFormsHost element attempts to integrate its hosted Windows Forms control
into the WPF layout system.

In some cases, Windows Forms controls cannot be resized, or can be sized only to
specific dimensions. For example, a Windows Forms ComboBox control supports
only a single height, which is defined by the control's font size. In a WPF dynamic
layout where elements can stretch vertically, a hosted ComboBox control will not
stretch as expected.

Windows Forms controls cannot be rotated or skewed. The WindowsFormsHost


element raises the LayoutError event if you apply a skew or rotation
transformation. If you do not handle the LayoutError event, an
InvalidOperationException is raised.

In most cases, Windows Forms controls do not support proportional scaling.


Although the overall dimensions of the control will scale, child controls and
component elements of the control may not resize as expected. This limitation
depends on how well each Windows Forms control supports scaling. In addition,
you cannot scale Windows Forms controls down to a size of 0 pixels.

Windows Forms controls support autoscaling, in which the form will automatically
resize itself and its controls based on the font size. In a WPF user interface,
changing the font size does not resize the entire layout, although individual
elements may dynamically resize.

Z-order
In a WPF user interface, you can change the z-order of elements to control overlapping
behavior. A hosted Windows Forms control is drawn in a separate HWND, so it is always
drawn on top of WPF elements.

A hosted Windows Forms control is also drawn on top of any Adorner elements.

Layout Behavior
The following sections describe specific aspects of layout behavior when hosting
Windows Forms controls in WPF.

Scaling, Unit Conversion, and Device Independence


Whenever the WindowsFormsHost element performs operations involving WPF and
Windows Forms dimensions, two coordinate systems are involved: device-independent
pixels for WPF and hardware pixels for Windows Forms. Therefore, you must apply
proper unit and scaling conversions to achieve a consistent layout.

Conversion between the coordinate systems depends on the current device resolution
and any layout or rendering transforms applied to the WindowsFormsHost element or
to its ancestors.

If the output device is 96 dpi and no scaling has been applied to the
WindowsFormsHost element, one device-independent pixel is equal to one hardware
pixel.

All other cases require coordinate system scaling. The hosted control is not resized.
Instead, the WindowsFormsHost element attempts to scale the hosted control and all of
its child controls. Because Windows Forms does not fully support scaling, the
WindowsFormsHost element scales to the degree supported by particular controls.

Override the ScaleChild method to provide custom scaling behavior for the hosted
Windows Forms control.

In addition to scaling, the WindowsFormsHost element handles rounding and overflow


cases as described in the following table.

Conversion Description
issue

Rounding WPF device-independent pixel dimensions are specified as double , and Windows
Forms hardware pixel dimensions are specified as int . In cases where double -
based dimensions are converted to int -based dimensions, the WindowsFormsHost
element uses standard rounding, so that fractional values less than 0.5 are rounded
down to 0.
Conversion Description
issue

Overflow When the WindowsFormsHost element converts from double values to int values,
overflow is possible. Values that are larger than MaxValue are set to MaxValue.

Layout-related Properties
Properties that control layout behavior in Windows Forms controls and WPF elements
are mapped appropriately by the WindowsFormsHost element. For more information,
see Windows Forms and WPF Property Mapping.

Layout Changes in the Hosted Control


Layout changes in the hosted Windows Forms control are propagated to WPF to trigger
layout updates. The InvalidateMeasure method on WindowsFormsHost ensures that
layout changes in the hosted control cause the WPF layout engine to run.

Continuously Sized Windows Forms Controls


Windows Forms controls that support continuous scaling fully interact with the WPF
layout system. The WindowsFormsHost element uses the MeasureOverride and
ArrangeOverride methods as usual to size and arrange the hosted Windows Forms
control.

Sizing Algorithm
The WindowsFormsHost element uses the following procedure to size the hosted
control:

1. The WindowsFormsHost element overrides the MeasureOverride and


ArrangeOverride methods.

2. To determine the size of the hosted control, the MeasureOverride method calls the
hosted control's GetPreferredSize method with a constraint translated from the
constraint passed to the MeasureOverride method.

3. The ArrangeOverride method attempts to set the hosted control to the given size
constraint.

4. If the hosted control's Size property matches the specified constraint, the hosted
control is sized to the constraint.
If the Size property does not match the specified constraint, the hosted control does not
support continuous sizing. For example, the MonthCalendar control allows only discrete
sizes. The permitted sizes for this control consist of integers (representing the number of
months) for both height and width. In cases such as this, the WindowsFormsHost
element behaves as follows:

If the Size property returns a larger size than the specified constraint, the
WindowsFormsHost element clips the hosted control. Height and width are
handled separately, so the hosted control may be clipped in either direction.

If the Size property returns a smaller size than the specified constraint,
WindowsFormsHost accepts this size value and returns the value to the WPF layout
system.

See also
ElementHost
WindowsFormsHost
Walkthrough: Arranging Windows Forms Controls in WPF
Arranging Windows Forms Controls in WPF Sample
Windows Forms and WPF Property Mapping
Migration and Interoperability
Windows Forms Controls and Equivalent WPF
Controls
Article • 08/18/2022

Many Windows Forms controls have equivalent WPF controls, but some Windows Forms controls have
no equivalents in WPF. This topic compares control types provided by the two technologies.

You can always use interoperation to host Windows Forms controls that do not have equivalents in your
WPF-based applications.

The following table shows which Windows Forms controls and components have equivalent WPF
control functionality.

Windows Forms control WPF equivalent control Remarks

BindingNavigator No equivalent control.

BindingSource CollectionViewSource

Button Button

CheckBox CheckBox

CheckedListBox ListBox with composition.

ColorDialog No equivalent control.

ComboBox ComboBox ComboBox does not support auto-complete.

ContextMenuStrip ContextMenu

DataGridView DataGrid

DateTimePicker DatePicker

DomainUpDown TextBox and two RepeatButton


controls.

ErrorProvider No equivalent control.

FlowLayoutPanel WrapPanel or StackPanel

FolderBrowserDialog No equivalent control.

FontDialog No equivalent control.

Form Window Window does not support child windows.

GroupBox GroupBox

HelpProvider No equivalent control. No F1 Help. "What's This" Help is replaced by


ToolTips.

HScrollBar ScrollBar Scrolling is built into container controls.

ImageList No equivalent control.


Windows Forms control WPF equivalent control Remarks

Label Label

LinkLabel No equivalent control. You can use the Hyperlink class to host hyperlinks
within flow content.

ListBox ListBox

ListView ListView The ListView control provides a read-only details


view.

MaskedTextBox No equivalent control.

MenuStrip Menu Menu control styling can approximate the behavior


and appearance of the
System.Windows.Forms.ToolStripProfessionalRenderer
class.

MonthCalendar Calendar

NotifyIcon No equivalent control.

NumericUpDown TextBox and two RepeatButton


controls.

OpenFileDialog OpenFileDialog The OpenFileDialog class is a WPF wrapper around


the Win32 control.

PageSetupDialog No equivalent control.

Panel Canvas

PictureBox Image

PrintDialog PrintDialog

PrintDocument No equivalent control.

PrintPreviewControl DocumentViewer

PrintPreviewDialog No equivalent control.

ProgressBar ProgressBar

PropertyGrid No equivalent control.

RadioButton RadioButton

RichTextBox RichTextBox

SaveFileDialog SaveFileDialog The SaveFileDialog class is a WPF wrapper around the


Win32 control.

ScrollableControl ScrollViewer

SoundPlayer MediaPlayer

SplitContainer GridSplitter

StatusStrip StatusBar
Windows Forms control WPF equivalent control Remarks

TabControl TabControl

TableLayoutPanel Grid

TextBox TextBox

Timer DispatcherTimer

ToolStrip ToolBar

ToolStripContainer ToolBar with composition.

ToolStripDropDown ToolBar with composition.

ToolStripDropDownMenu ToolBar with composition.

ToolStripPanel ToolBar with composition.

ToolTip ToolTip

TrackBar Slider

TreeView TreeView

UserControl UserControl

VScrollBar ScrollBar Scrolling is built into container controls.

WebBrowser Frame, The Frame control can host HTML pages.


System.Windows.Controls.WebBrowser
Starting in the .NET Framework 3.5 SP1, the
System.Windows.Controls.WebBrowser control can
host HTML pages and also backs the Frame control.

See also
ElementHost
WindowsFormsHost
WPF Designer for Windows Forms Developers
Walkthrough: Hosting a Windows Forms Control in WPF
Walkthrough: Hosting a WPF Composite Control in Windows Forms
Migration and Interoperability
Windows Forms and WPF Property
Mapping
Article • 02/06/2023

The Windows Forms and WPF technologies have two similar but different property
models. Property mapping supports interoperation between the two architectures and
provides the following capabilities:

Makes it easy to map relevant property changes in the host environment to the
hosted control or element.

Provides default handling for mapping the most commonly used properties.

Allows easy removal, overriding, or extending of default properties.

Ensures that property value changes on the host are automatically detected and
translated to the hosted control or element.

7 Note

Property-change events are not propagated up the hosting control or element


hierarchy. Property translation is not performed if the local value of a property does
not change because of direct setting, styles, inheritance, data binding, or other
mechanisms that change the value of the property.

Use the PropertyMap property on the WindowsFormsHost element and the


PropertyMap property on ElementHost control to access property mapping.

Property Mapping with the


WindowsFormsHost Element
The WindowsFormsHost element translates default WPF properties to their Windows
Forms equivalents using the following translation table.

Windows Presentation Windows Forms Interoperation behavior


Foundation hosting
Windows Presentation Windows Forms Interoperation behavior
Foundation hosting

Background BackColor The WindowsFormsHost


element sets the
(System.Windows.Media.Brush) (System.Drawing.Color) BackColor property of
the hosted control and
the BackgroundImage
property of the hosted
control. Mapping is
performed by using the
following rules:

- If Background is a solid
color, it is converted and
used to set the BackColor
property of the hosted
control. The BackColor
property is not set on the
hosted control, because
the hosted control can
inherit the value of the
BackColor property.
Note: The hosted control
does not support
transparency. Any color
assigned to BackColor
must be fully opaque,
with an alpha value of
0xFF.

- If Background is not a
solid color, the
WindowsFormsHost
control creates a bitmap
from the Background
property. The
WindowsFormsHost
control assigns this
bitmap to the
BackgroundImage
property of the hosted
control. This provides an
effect which is similar to
transparency. Note: You
can override this
behavior or you can
remove the Background
property mapping.
Windows Presentation Windows Forms Interoperation behavior
Foundation hosting

Cursor Cursor If the default mapping


has not been reassigned,
WindowsFormsHost
control traverses its
ancestor hierarchy until it
finds an ancestor with its
Cursor property set. This
value is translated to the
closest corresponding
Windows Forms cursor.

If the default mapping


for the ForceCursor
property has not been
reassigned, the traversal
stops on the first
ancestor with
ForceCursor set to true .

FlowDirection RightToLeft LeftToRight maps to No.

(System.Windows.FlowDirection) (System.Windows.Forms.RightToLeft) RightToLeft maps to Yes.

Inherit is not mapped.

FlowDirection.RightToLeft
maps to RightToLeft.Yes.

FontStyle Style on the hosted control's The set of WPF


System.Drawing.Font properties is translated
into a corresponding
Font. When one of these
properties changes, a
new Font is created. For
Normal: Italic is disabled.
For Italic or Oblique:
Italic is enabled.
Windows Presentation Windows Forms Interoperation behavior
Foundation hosting

FontWeight Style on the hosted control's The set of WPF


System.Drawing.Font properties is translated
into a corresponding
Font. When one of these
properties changes, a
new Font is created. For
Black, Bold, DemiBold,
ExtraBold, Heavy,
Medium, SemiBold, or
UltraBold: Bold is
enabled. For ExtraLight,
Light, Normal, Regular,
Thin, or UltraLight: Bold
is disabled.

FontFamily Font The set of WPF


properties is translated
FontSize (System.Drawing.Font) into a corresponding
Font. When one of these
FontStretch properties changes, a
new Font is created. The
FontStyle hosted Windows Forms
control resizes based on
FontWeight the font size.

Font size in WPF is


expressed as one ninety-
sixth of an inch, and in
Windows Forms as one
seventy-second of an
inch. The corresponding
conversion is:

Windows Forms font size


= WPF font size * 72.0 /
96.0.
Windows Presentation Windows Forms Interoperation behavior
Foundation hosting

Foreground ForeColor The Foreground property


mapping is performed by
(System.Windows.Media.Brush) (System.Drawing.Color) using the following rules:

- If Foreground is a
SolidColorBrush, use
Color for ForeColor.
- If Foreground is a
GradientBrush, use the
color of the GradientStop
with the lowest offset
value for ForeColor.
- For any other Brush
type, leave ForeColor
unchanged. This means
the default is used.

IsEnabled Enabled When IsEnabled is set,


WindowsFormsHost
element sets the Enabled
property on the hosted
control.

Padding Padding All four values of the


Padding property on the
hosted Windows Forms
control are set to the
same Thickness value.

- Values greater than


MaxValue are set to
MaxValue.
- Values less than
MinValue are set to
MinValue.
Windows Presentation Windows Forms Interoperation behavior
Foundation hosting

Visibility Visible - Visible maps to Visible


= true . The hosted
Windows Forms control
is visible. Explicitly setting
the Visible property on
the hosted control to
false is not
recommended.
- Collapsed maps to
Visible = true or false .
The hosted Windows
Forms control is not
drawn, and its area is
collapsed.
- Hidden : The hosted
Windows Forms control
occupies space in the
layout, but is not visible.
In this case, the Visible
property is set to true .
Explicitly setting the
Visible property on the
hosted control to false
is not recommended.

Attached properties on container elements are fully supported by the


WindowsFormsHost element.

For more information, see Walkthrough: Mapping Properties Using the


WindowsFormsHost Element.

Updates to Parent Properties


Changes to most parent properties cause notifications to the hosted child control. The
following list describes properties which do not cause notifications when their values
change.

Background

Cursor

ForceCursor

Visibility
For example, if you change the value of the Background property of the
WindowsFormsHost element, the BackColor property of the hosted control does not
change.

Property Mapping with the ElementHost


Control
The following properties provide built-in change notification. Do not call the
OnPropertyChanged method when you are mapping these properties:

AutoSize

BackColor

BackgroundImage

BackgroundImageLayout

BindingContext

CausesValidation

ContextMenu

ContextMenuStrip

Cursor

Dock

Enabled

Font

ForeColor

Location

Margin

Padding

Parent

Region

RightToLeft
Size

TabIndex

TabStop

Text

Visible

The ElementHost control translates default Windows Forms properties to their WPF
equivalents by using the following translation table.

For more information, see Walkthrough: Mapping Properties Using the ElementHost
Control.

Windows Forms hosting Windows Presentation Interoperation


Foundation behavior

BackColor Background Setting this property


forces a repaint with an
(System.Drawing.Color) (System.Windows.Media.Brush) ImageBrush. If the
on the hosted element BackColorTransparent
property is set to false
(the default value), this
ImageBrush is based on
the appearance of the
ElementHost control,
including its BackColor,
BackgroundImage,
BackgroundImageLayout
properties, and any
attached paint handlers.

If the
BackColorTransparent
property is set to true ,
the ImageBrush is based
on the appearance of
the ElementHost
control's parent,
including the parent's
BackColor,
BackgroundImage,
BackgroundImageLayout
properties, and any
attached paint handlers.
Windows Forms hosting Windows Presentation Interoperation
Foundation behavior

BackgroundImage Background Setting this property


causes the same
(System.Drawing.Image) (System.Windows.Media.Brush) behavior described for
on the hosted element the BackColor mapping.

BackgroundImageLayout Background Setting this property


causes the same
(System.Windows.Media.Brush) behavior described for
on the hosted element the BackColor mapping.

Cursor Cursor The Windows Forms


standard cursor is
(System.Windows.Forms.Cursor) (System.Windows.Input.Cursor) translated to the
corresponding WPF
standard cursor. If the
Windows Forms is not a
standard cursor, the
default is assigned.

Enabled IsEnabled When Enabled is set, the


ElementHost control sets
the IsEnabled property
on the hosted element.

Font FontFamily The Font value is


translated into a
(System.Drawing.Font) FontSize corresponding set of
WPF font properties.
FontStretch

FontStyle

FontWeight

Bold FontWeight on hosted element If Bold is true ,


FontWeight is set to
Bold.

If Bold is false ,
FontWeight is set to
Normal.
Windows Forms hosting Windows Presentation Interoperation
Foundation behavior

Italic FontStyle on hosted element If Italic is true , FontStyle


is set to Italic.

If Italic is false ,
FontStyle is set to
Normal.

Strikeout TextDecorations on hosted Applies only when


element hosting a TextBlock
control.

Underline TextDecorations on hosted Applies only when


element hosting a TextBlock
control.

RightToLeft FlowDirection No maps to LeftToRight.

(System.Windows.Forms.RightToLeft) (FlowDirection) Yes maps to RightToLeft.

Visible Visibility The ElementHost control


sets the Visibility
property on the hosted
element by using the
following rules:

- Visible = true maps to


Visible.
- Visible = false maps
to Hidden.

See also
ElementHost
WindowsFormsHost
WPF and Win32 Interoperation
WPF and Windows Forms Interoperation
Walkthrough: Mapping Properties Using the WindowsFormsHost Element
Walkthrough: Mapping Properties Using the ElementHost Control
Troubleshooting Hybrid Applications
Article • 08/18/2022

This topic lists some common problems that can occur when authoring hybrid
applications, which use both WPF and Windows Forms technologies.

Overlapping Controls
Controls may not overlap as you would expect. Windows Forms uses a separate HWND
for each control. WPF uses one HWND for all content on a page. This implementation
difference causes unexpected overlapping behaviors.

A Windows Forms control hosted in WPF always appears on top of the WPF content.

WPF content hosted in an ElementHost control appears at the z-order of the


ElementHost control. It is possible to overlap ElementHost controls, but the hosted WPF
content does not combine or interact.

Child Property
The WindowsFormsHost and ElementHost classes can host only a single child control or
element. To host more than one control or element, you must use a container as the
child content. For example, you could add Windows Forms button and check box
controls to a System.Windows.Forms.Panel control, and then assign the panel to a
WindowsFormsHost control's Child property. However, you cannot add the button and
check box controls separately to the same WindowsFormsHost control.

Scaling
WPF and Windows Forms have different scaling models. Some WPF scaling
transformations are meaningful to Windows Forms controls, but others are not. For
example, scaling a Windows Forms control to 0 will work, but if you try to scale the same
control back to a non-zero value, the control's size remains 0. For more information, see
Layout Considerations for the WindowsFormsHost Element.

Adapter
There may be confusion when working the WindowsFormsHost and ElementHost
classes, because they include a hidden container. Both the WindowsFormsHost and
ElementHost classes have a hidden container, called an adapter, which they use to host
content. For the WindowsFormsHost element, the adapter derives from the
System.Windows.Forms.ContainerControl class. For the ElementHost control, the adapter
derives from the DockPanel element. When you see references to the adapter in other
interoperation topics, this container is what is being discussed.

Nesting
Nesting a WindowsFormsHost element inside an ElementHost control is not supported.
Nesting an ElementHost control inside a WindowsFormsHost element is also not
supported.

Focus
Focus works differently in WPF and Windows Forms, which means that focus issues may
occur in a hybrid application. For example, if you have focus inside a
WindowsFormsHost element, and you either minimize and restore the page or show a
modal dialog box, focus inside the WindowsFormsHost element may be lost. The
WindowsFormsHost element still has focus, but the control inside it may not.

Data validation is also affected by focus. Validation works in a WindowsFormsHost


element, but it does not work as you tab out of the WindowsFormsHost element, or
between two different WindowsFormsHost elements.

Property Mapping
Some property mappings require extensive interpretation to bridge dissimilar
implementations between the WPF and Windows Forms technologies. Property
mappings enable your code to react to changes in fonts, colors, and other properties. In
general, property mappings work by listening for either PropertyChanged events or
OnPropertyChanged calls, and setting appropriate properties on either the child control
or its adapter. For more information, see Windows Forms and WPF Property Mapping.

Layout-related Properties on Hosted Content


When the WindowsFormsHost.Child or ElementHost.Child property is assigned, several
layout-related properties on the hosted content are set automatically. Changing these
content properties can cause unexpected layout behaviors.
Your hosted content is docked to fill the WindowsFormsHost and ElementHost parent.
To enable this fill behavior, several properties are set when you set the child property.
The following table lists which content properties are set by the ElementHost and
WindowsFormsHost classes.

Host Class Content Properties

ElementHost Height

Width

Margin

VerticalAlignment

HorizontalAlignment

WindowsFormsHost Margin

Dock

AutoSize

Location

MaximumSize

Do not set these properties directly on the hosted content. For more information, see
Layout Considerations for the WindowsFormsHost Element.

Navigation Applications
Navigation applications may not maintain user state. The WindowsFormsHost element
recreates its controls when it is used in a navigation application. Recreating child
controls occurs when the user navigates away from the page hosting the
WindowsFormsHost element and then returns to it. Any content that has been typed in
by the user will be lost.

Message Loop Interoperation


When working with Windows Forms message loops, messages may not be processed as
expected. The EnableWindowsFormsInterop method is called by the WindowsFormsHost
constructor. This method adds a message filter to the WPF message loop. This filter calls
the Control.PreProcessMessage method if a System.Windows.Forms.Control was the
target of the message and translates/dispatches the message.

If you show a Window in a Windows Forms message loop with Application.Run, you
cannot type anything unless you call the EnableModelessKeyboardInterop method. The
EnableModelessKeyboardInterop method takes a Window and adds a
System.Windows.Forms.IMessageFilter, which reroutes key-related messages to the WPF
message loop. For more information, see Windows Forms and WPF Interoperability
Input Architecture.

Opacity and Layering


The HwndHost class does not support layering. This means that setting the Opacity
property on the WindowsFormsHost element has no effect, and no blending will occur
with other WPF windows which have AllowsTransparency set to true .

Dispose
Not disposing classes properly can leak resources. In your hybrid applications, make
sure that the WindowsFormsHost and ElementHost classes are disposed, or you could
leak resources. Windows Forms disposes ElementHost controls when its non-modal
Form parent closes. WPF disposes WindowsFormsHost elements when your application
shuts down. It is possible to show a WindowsFormsHost element in a Window in a
Windows Forms message loop. In this case, your code may not receive notification that
your application is shutting down.

Enabling Visual Styles


Microsoft Windows XP visual styles on a Windows Forms control may not be enabled.
The Application.EnableVisualStyles method is called in the template for a Windows
Forms application. Although this method is not called by default, if you use Visual Studio
to create a project, you will get Microsoft Windows XP visual styles for controls, if
version 6.0 of Comctl32.dll is available. You must call the EnableVisualStyles method
before handles are created on the thread. For more information, see How to: Enable
Visual Styles in a Hybrid Application.

Licensed Controls
Licensed Windows Forms controls that display licensing information in a message box to
the user might cause unexpected behavior for a hybrid application. Some licensed
controls show a dialog box in response to handle creation. For example, a licensed
control might inform the user that a license is required, or that the user has three
remaining trial uses of the control.

The WindowsFormsHost element derives from the HwndHost class, and the child
control’s handle is created inside the BuildWindowCore method. The HwndHost class
does not allow messages to be processed in the BuildWindowCore method, but
displaying a dialog box causes messages to be sent. To enable this licensing scenario,
call the Control.CreateControl method on the control before assigning it as the
WindowsFormsHost element's child.

WPF Designer
You can design your WPF content by using the WPF Designer for Visual Studio. The
following sections list some common problems that can occur when authoring hybrid
applications with the WPF Designer.

BackColorTransparent is ignored at design time


The BackColorTransparent property might not work as expected at design time.

If a WPF control is not on a visible parent, the WPF runtime ignores the
BackColorTransparent value. The reason that BackColorTransparent might be ignored is
because ElementHost object is created in a separate AppDomain. However, when you
run the application, BackColorTransparent does work as expected.

Design-time Error List appears when the obj folder is


deleted
If the obj folder is deleted, the Design-time Error List appears.

When you design using ElementHost, the Windows Forms Designer uses generated files
in the Debug or Release folder within your project's obj folder. If you delete these files,
the Design-time Error List appears. To fix this problem, rebuild your project. For more
information, see Design-Time Errors in the Windows Forms Designer.

ElementHost and IME


WPF controls hosted in an ElementHost currently do not support the ImeMode
property. Changes to ImeMode will be ignored by the hosted controls.

See also
ElementHost
WindowsFormsHost
Interoperability in the WPF Designer
Windows Forms and WPF Interoperability Input Architecture
How to: Enable Visual Styles in a Hybrid Application
Layout Considerations for the WindowsFormsHost Element
Windows Forms and WPF Property Mapping
Design-Time Errors in the Windows Forms Designer
Migration and Interoperability
Walkthrough: Hosting a Windows Forms
Control in WPF
Article • 03/17/2022

WPF provides many controls with a rich feature set. However, you may sometimes want
to use Windows Forms controls on your WPF pages. For example, you may have a
substantial investment in existing Windows Forms controls, or you may have a Windows
Forms control that provides unique functionality.

This walkthrough shows you how to host a Windows Forms


System.Windows.Forms.MaskedTextBox control on a WPF page by using code.

For a complete code listing of the tasks shown in this walkthrough, see Hosting a
Windows Forms Control in WPF Sample .

Prerequisites
You need Visual Studio to complete this walkthrough.

Hosting the Windows Forms Control

To host the MaskedTextBox control


1. Create a WPF Application project named HostingWfInWpf .

2. Add references to the following assemblies.

WindowsFormsIntegration

System.Windows.Forms

3. Open MainWindow.xaml in the WPF Designer.

4. Name the Grid element grid1 .

XAML

<Grid Name="grid1">

</Grid>
5. In Design view or XAML view, select the Window element.

6. In the Properties window, click the Events tab.

7. Double-click the Loaded event.

8. Insert the following code to handle the Loaded event.

C#

private void Window_Loaded(object sender, RoutedEventArgs e)


{
// Create the interop host control.
System.Windows.Forms.Integration.WindowsFormsHost host =
new System.Windows.Forms.Integration.WindowsFormsHost();

// Create the MaskedTextBox control.


MaskedTextBox mtbDate = new MaskedTextBox("00/00/0000");

// Assign the MaskedTextBox control as the host control's child.


host.Child = mtbDate;

// Add the interop host control to the Grid


// control's collection of child controls.
this.grid1.Children.Add(host);
}

9. At the top of the file, add the following Imports or using statement.

C#

using System.Windows.Forms;

10. Press F5 to build and run the application.

See also
ElementHost
WindowsFormsHost
Design XAML in Visual Studio
Walkthrough: Hosting a Windows Forms Control in WPF by Using XAML
Walkthrough: Hosting a Windows Forms Composite Control in WPF
Walkthrough: Hosting a WPF Composite Control in Windows Forms
Windows Forms Controls and Equivalent WPF Controls
Hosting a Windows Forms Control in WPF Sample
Walkthrough: Hosting a Windows Forms
Control in WPF by Using XAML
Article • 02/06/2023

WPF provides many controls with a rich feature set. However, you may sometimes want
to use Windows Forms controls on your WPF pages. For example, you may have a
substantial investment in existing Windows Forms controls, or you may have a Windows
Forms control that provides unique functionality.

This walkthrough shows you how to host a Windows Forms


System.Windows.Forms.MaskedTextBox control on a WPF page by using XAML.

For a complete code listing of the tasks shown in this walkthrough, see Hosting a
Windows Forms Control in WPF by Using XAML Sample .

Prerequisites
You need Visual Studio to complete this walkthrough.

Hosting the Windows Forms Control

To host the MaskedTextBox control

1. Create a WPF Application project named HostingWfInWpfWithXaml .

2. Add references to the following assemblies.

WindowsFormsIntegration

System.Windows.Forms

3. Open MainWindow.xaml in the WPF Designer.

4. In the Window element, add the following namespace mapping. The wf


namespace mapping establishes a reference to the assembly that contains the
Windows Forms control.

XAML

xmlns:wf="clr-
namespace:System.Windows.Forms;assembly=System.Windows.Forms"
5. In the Grid element add the following XAML.

The MaskedTextBox control is created as a child of the WindowsFormsHost control.

XAML

<Grid>

<WindowsFormsHost>
<wf:MaskedTextBox x:Name="mtbDate" Mask="00/00/0000"/>
</WindowsFormsHost>

</Grid>

6. Press F5 to build and run the application.

See also
ElementHost
WindowsFormsHost
Design XAML in Visual Studio
Walkthrough: Hosting a Windows Forms Control in WPF
Walkthrough: Hosting a Windows Forms Composite Control in WPF
Walkthrough: Hosting a WPF Composite Control in Windows Forms
Windows Forms Controls and Equivalent WPF Controls
Hosting a Windows Forms Control in WPF by Using XAML Sample
Walkthrough: Hosting a Windows Forms
Composite Control in WPF
Article • 08/18/2022

WPF application rather than to rewrite it from scratch. The most common scenario is
when you have existing Windows Forms controls. In some cases, you might not even
have access to the source code for these controls. WPF provides a straightforward
procedure for hosting such controls in a WPF application. For example, you can use WPF
for most of your programming while hosting your specialized DataGridView controls.

This walkthrough steps you through an application that hosts a Windows Forms
composite control to perform data entry in a WPF application. The composite control is
packaged in a DLL. This general procedure can be extended to more complex
applications and controls. This walkthrough is designed to be nearly identical in
appearance and functionality to Walkthrough: Hosting a WPF Composite Control in
Windows Forms. The primary difference is that the hosting scenario is reversed.

The walkthrough is divided into two sections. The first section briefly describes the
implementation of the Windows Forms composite control. The second section discusses
in detail how to host the composite control in a WPF application, receive events from
the control, and access some of the control's properties.

Tasks illustrated in this walkthrough include:

Implementing the Windows Forms composite control.

Implementing the WPF host application.

For a complete code listing of the tasks illustrated in this walkthrough, see Hosting a
Windows Forms Composite Control in WPF Sample .

Prerequisites
You need Visual Studio to complete this walkthrough.

Implementing the Windows Forms Composite


Control
The Windows Forms composite control used in this example is a simple data-entry form.
This form takes the user's name and address and then uses a custom event to return
that information to the host. The following illustration shows the rendered control.

The following image shows a Windows Forms composite control:

Creating the Project


To start the project:

1. Launch Visual Studio, and open the New Project dialog box.

2. In the Window category, select the Windows Forms Control Library template.

3. Name the new project MyControls .

4. For the location, specify a conveniently named top-level folder, such as


WpfHostingWindowsFormsControl . Later, you will put the host application in this
folder.

5. Click OK to create the project. The default project contains a single control named
UserControl1 .

6. In Solution Explorer, rename UserControl1 to MyControl1 .

Your project should have references to the following system DLLs. If any of these DLLs
are not included by default, add them to the project.

System

System.Data

System.Drawing

System.Windows.Forms
System.Xml

Adding Controls to the Form


To add controls to the form:

Open MyControl1 in the designer.

Add five Label controls and their corresponding TextBox controls, sized and arranged as
they are in the preceding illustration, on the form. In the example, the TextBox controls
are named:

txtName

txtAddress

txtCity

txtState

txtZip

Add two Button controls labeled OK and Cancel. In the example, the button names are
btnOK and btnCancel , respectively.

Implementing the Supporting Code


Open the form in code view. The control returns the collected data to its host by raising
the custom OnButtonClick event. The data is contained in the event argument object.
The following code shows the event and delegate declaration.

Add the following code to the MyControl1 class.

C#

public delegate void MyControlEventHandler(object sender, MyControlEventArgs


args);
public event MyControlEventHandler OnButtonClick;

The MyControlEventArgs class contains the information to be returned to the host.

Add the following class to the form.

C#
public class MyControlEventArgs : EventArgs
{
private string _Name;
private string _StreetAddress;
private string _City;
private string _State;
private string _Zip;
private bool _IsOK;

public MyControlEventArgs(bool result,


string name,
string address,
string city,
string state,
string zip)
{
_IsOK = result;
_Name = name;
_StreetAddress = address;
_City = city;
_State = state;
_Zip = zip;
}

public string MyName


{
get { return _Name; }
set { _Name = value; }
}
public string MyStreetAddress
{
get { return _StreetAddress; }
set { _StreetAddress = value; }
}
public string MyCity
{
get { return _City; }
set { _City = value; }
}
public string MyState
{
get { return _State; }
set { _State = value; }
}
public string MyZip
{
get { return _Zip; }
set { _Zip = value; }
}
public bool IsOK
{
get { return _IsOK; }
set { _IsOK = value; }
}
}

When the user clicks the OK or Cancel button, the Click event handlers create a
MyControlEventArgs object that contains the data and raises the OnButtonClick event.
The only difference between the two handlers is the event argument's IsOK property.
This property enables the host to determine which button was clicked. It is set to true
for the OK button, and false for the Cancel button. The following code shows the two
button handlers.

Add the following code to the MyControl1 class.

C#

private void btnOK_Click(object sender, System.EventArgs e)


{

MyControlEventArgs retvals = new MyControlEventArgs(true,


txtName.Text,
txtAddress.Text,
txtCity.Text,
txtState.Text,
txtZip.Text);
OnButtonClick(this, retvals);
}

private void btnCancel_Click(object sender, System.EventArgs e)


{
MyControlEventArgs retvals = new MyControlEventArgs(false,
txtName.Text,
txtAddress.Text,
txtCity.Text,
txtState.Text,
txtZip.Text);
OnButtonClick(this, retvals);
}

Giving the Assembly a Strong Name and Building the


Assembly
For this assembly to be referenced by a WPF application, it must have a strong name. To
create a strong name, create a key file with Sn.exe and add it to your project.

1. Open a Visual Studio command prompt. To do so, click the Start menu, and then
select All Programs/Microsoft Visual Studio 2010/Visual Studio Tools/Visual
Studio Command Prompt. This launches a console window with customized
environment variables.

2. At the command prompt, use the cd command to go to your project folder.

3. Generate a key file named MyControls.snk by running the following command.

Console

Sn.exe -k MyControls.snk

4. To include the key file in your project, right-click the project name in Solution
Explorer and then click Properties. In the Project Designer, click the Signing tab,
select the Sign the assembly check box and then browse to your key file.

5. Build the solution. The build will produce a DLL named MyControls.dll.

Implementing the WPF Host Application


The WPF host application uses the WindowsFormsHost control to host MyControl1 . The
application handles the OnButtonClick event to receive the data from the control. It also
has a collection of option buttons that enable you to change some of the control's
properties from the WPF application. The following illustration shows the finished
application.

The following image shows the complete application, including the control embedded
in the WPF application:
Creating the Project
To start the project:

1. Open Visual Studio, and select New Project.

2. In the Window category, select the WPF Application template.

3. Name the new project WpfHost .

4. For the location, specify the same top-level folder that contains the MyControls
project.

5. Click OK to create the project.

You also need to add references to the DLL that contains MyControl1 and other
assemblies.

1. Right-click the project name in Solution Explorer and select Add Reference.
2. Click the Browse tab, and browse to the folder that contains MyControls.dll. For
this walkthrough, this folder is MyControls\bin\Debug.

3. Select MyControls.dll, and then click OK.

4. Add a reference to the WindowsFormsIntegration assembly, which is named


WindowsFormsIntegration.dll.

Implementing the Basic Layout


The user interface (UI) of the host application is implemented in MainWindow.xaml. This
file contains Extensible Application Markup Language (XAML) markup that defines the
layout, and hosts the Windows Forms control. The application is divided into three
regions:

The Control Properties panel, which contains a collection of option buttons that
you can use to modify various properties of the hosted control.

The Data from Control panel, which contains several TextBlock elements that
display the data returned from the hosted control.

The hosted control itself.

The basic layout is shown in the following XAML. The markup that is needed to host
MyControl1 is omitted from this example, but will be discussed later.

Replace the XAML in MainWindow.xaml with the following. If you are using Visual Basic,
change the class to x:Class="MainWindow" .

XAML

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfHost.MainWindow"
xmlns:mcl="clr-namespace:MyControls;assembly=MyControls"
Loaded="Init">
<DockPanel>
<DockPanel.Resources>
<Style x:Key="inlineText" TargetType="{x:Type Inline}">
<Setter Property="FontWeight" Value="Normal"/>
</Style>
<Style x:Key="titleText" TargetType="{x:Type TextBlock}">
<Setter Property="DockPanel.Dock" Value="Top"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Margin" Value="10,5,10,0"/>
</Style>
</DockPanel.Resources>
<StackPanel Orientation="Vertical"
DockPanel.Dock="Left"
Background="Bisque"
Width="250">

<TextBlock Margin="10,10,10,10"
FontWeight="Bold"
FontSize="12">Control Properties</TextBlock>
<TextBlock Style="{StaticResource titleText}">Background
Color</TextBlock>
<StackPanel Margin="10,10,10,10">
<RadioButton Name="rdbtnOriginalBackColor"
IsChecked="True"
Click="BackColorChanged">Original</RadioButton>
<RadioButton Name="rdbtnBackGreen"
Click="BackColorChanged">LightGreen</RadioButton>
<RadioButton Name="rdbtnBackSalmon"
Click="BackColorChanged">LightSalmon</RadioButton>
</StackPanel>

<TextBlock Style="{StaticResource titleText}">Foreground


Color</TextBlock>
<StackPanel Margin="10,10,10,10">
<RadioButton Name="rdbtnOriginalForeColor"
IsChecked="True"
Click="ForeColorChanged">Original</RadioButton>
<RadioButton Name="rdbtnForeRed"
Click="ForeColorChanged">Red</RadioButton>
<RadioButton Name="rdbtnForeYellow"
Click="ForeColorChanged">Yellow</RadioButton>
</StackPanel>

<TextBlock Style="{StaticResource titleText}">Font Family</TextBlock>


<StackPanel Margin="10,10,10,10">
<RadioButton Name="rdbtnOriginalFamily"
IsChecked="True"
Click="FontChanged">Original</RadioButton>
<RadioButton Name="rdbtnTimes"
Click="FontChanged">Times New Roman</RadioButton>
<RadioButton Name="rdbtnWingdings"
Click="FontChanged">Wingdings</RadioButton>
</StackPanel>

<TextBlock Style="{StaticResource titleText}">Font Size</TextBlock>


<StackPanel Margin="10,10,10,10">
<RadioButton Name="rdbtnOriginalSize"
IsChecked="True"
Click="FontSizeChanged">Original</RadioButton>
<RadioButton Name="rdbtnTen"
Click="FontSizeChanged">10</RadioButton>
<RadioButton Name="rdbtnTwelve"
Click="FontSizeChanged">12</RadioButton>
</StackPanel>

<TextBlock Style="{StaticResource titleText}">Font Style</TextBlock>


<StackPanel Margin="10,10,10,10">
<RadioButton Name="rdbtnNormalStyle"
IsChecked="True"
Click="StyleChanged">Original</RadioButton>
<RadioButton Name="rdbtnItalic"
Click="StyleChanged">Italic</RadioButton>
</StackPanel>

<TextBlock Style="{StaticResource titleText}">Font Weight</TextBlock>


<StackPanel Margin="10,10,10,10">
<RadioButton Name="rdbtnOriginalWeight"
IsChecked="True"
Click="WeightChanged">
Original
</RadioButton>
<RadioButton Name="rdbtnBold"
Click="WeightChanged">Bold</RadioButton>
</StackPanel>
</StackPanel>

<WindowsFormsHost Name="wfh"
DockPanel.Dock="Top"
Height="300">
<mcl:MyControl1 Name="mc"/>
</WindowsFormsHost>

<StackPanel Orientation="Vertical"
Height="Auto"
Background="LightBlue">
<TextBlock Margin="10,10,10,10"
FontWeight="Bold"
FontSize="12">Data From Control</TextBlock>
<TextBlock Style="{StaticResource titleText}">
Name: <Span Name="txtName" Style="{StaticResource inlineText}"/>
</TextBlock>
<TextBlock Style="{StaticResource titleText}">
Street Address: <Span Name="txtAddress" Style="{StaticResource
inlineText}"/>
</TextBlock>
<TextBlock Style="{StaticResource titleText}">
City: <Span Name="txtCity" Style="{StaticResource inlineText}"/>
</TextBlock>
<TextBlock Style="{StaticResource titleText}">
State: <Span Name="txtState" Style="{StaticResource inlineText}"/>
</TextBlock>
<TextBlock Style="{StaticResource titleText}">
Zip: <Span Name="txtZip" Style="{StaticResource inlineText}"/>
</TextBlock>
</StackPanel>
</DockPanel>
</Window>
The first StackPanel element contains several sets of RadioButton controls that enable
you to modify various default properties of the hosted control. That is followed by a
WindowsFormsHost element, which hosts MyControl1 . The final StackPanel element
contains several TextBlock elements that display the data that is returned by the hosted
control. The ordering of the elements and the Dock and Height attribute settings embed
the hosted control into the window with no gaps or distortion.

Hosting the Control


The following edited version of the previous XAML focuses on the elements that are
needed to host MyControl1 .

XAML

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfHost.MainWindow"
xmlns:mcl="clr-namespace:MyControls;assembly=MyControls"
Loaded="Init">

XAML

<WindowsFormsHost Name="wfh"
DockPanel.Dock="Top"
Height="300">
<mcl:MyControl1 Name="mc"/>
</WindowsFormsHost>

The xmlns namespace mapping attribute creates a reference to the MyControls


namespace that contains the hosted control. This mapping enables you to represent
MyControl1 in XAML as <mcl:MyControl1> .

Two elements in the XAML handle the hosting:

WindowsFormsHost represents the WindowsFormsHost element that enables you to

host a Windows Forms control in a WPF application.

mcl:MyControl1 , which represents MyControl1 , is added to the WindowsFormsHost


element's child collection. As a result, this Windows Forms control is rendered as
part of the WPF window, and you can communicate with the control from the
application.

Implementing the Code-Behind File


The code-behind file, MainWindow.xaml.vb or MainWindow.xaml.cs, contains the
procedural code that implements the functionality of the UI discussed in the preceding
section. The primary tasks are:

Attaching an event handler to MyControl1 's OnButtonClick event.

Modifying various properties of MyControl1 , based on how the collection of option


buttons are set.

Displaying the data collected by the control.

Initializing the Application

The initialization code is contained in an event handler for the window's Loaded event
and attaches an event handler to the control's OnButtonClick event.

In MainWindow.xaml.vb or MainWindow.xaml.cs, add the following code to the


MainWindow class.

C#

private Application app;


private Window myWindow;
FontWeight initFontWeight;
Double initFontSize;
FontStyle initFontStyle;
SolidColorBrush initBackBrush;
SolidColorBrush initForeBrush;
FontFamily initFontFamily;
bool UIIsReady = false;

private void Init(object sender, EventArgs e)


{
app = System.Windows.Application.Current;
myWindow = (Window)app.MainWindow;
myWindow.SizeToContent = SizeToContent.WidthAndHeight;
wfh.TabIndex = 10;
initFontSize = wfh.FontSize;
initFontWeight = wfh.FontWeight;
initFontFamily = wfh.FontFamily;
initFontStyle = wfh.FontStyle;
initBackBrush = (SolidColorBrush)wfh.Background;
initForeBrush = (SolidColorBrush)wfh.Foreground;
(wfh.Child as MyControl1).OnButtonClick += new
MyControl1.MyControlEventHandler(Pane1_OnButtonClick);
UIIsReady = true;
}
Because the XAML discussed previously added MyControl1 to the WindowsFormsHost
element's child element collection, you can cast the WindowsFormsHost element's Child
to get the reference to MyControl1 . You can then use that reference to attach an event
handler to OnButtonClick .

In addition to providing a reference to the control itself, WindowsFormsHost exposes a


number of the control's properties, which you can manipulate from the application. The
initialization code assigns those values to private global variables for later use in the
application.

So that you can easily access the types in the MyControls DLL, add the following
Imports or using statement to the top of the file.

C#

using MyControls;

Handling the OnButtonClick Event


MyControl1 raises the OnButtonClick event when the user clicks either of the control's

buttons.

Add the following code to the MainWindow class.

C#

//Handle button clicks on the Windows Form control


private void Pane1_OnButtonClick(object sender, MyControlEventArgs args)
{
txtName.Inlines.Clear();
txtAddress.Inlines.Clear();
txtCity.Inlines.Clear();
txtState.Inlines.Clear();
txtZip.Inlines.Clear();

if (args.IsOK)
{
txtName.Inlines.Add( " " + args.MyName );
txtAddress.Inlines.Add( " " + args.MyStreetAddress );
txtCity.Inlines.Add( " " + args.MyCity );
txtState.Inlines.Add( " " + args.MyState );
txtZip.Inlines.Add( " " + args.MyZip );
}
}
The data in the text boxes is packed into the MyControlEventArgs object. If the user
clicks the OK button, the event handler extracts the data and displays it in the panel
below MyControl1 .

Modifying the Control’s Properties


The WindowsFormsHost element exposes several of the hosted control's default
properties. As a result, you can change the appearance of the control to match the style
of your application more closely. The sets of option buttons in the left panel enable the
user to modify several color and font properties. Each set of buttons has a handler for
the Click event, which detects the user's option button selections and changes the
corresponding property on the control.

Add the following code to the MainWindow class.

C#

private void BackColorChanged(object sender, RoutedEventArgs e)


{
if (sender == rdbtnBackGreen)
wfh.Background = new SolidColorBrush(Colors.LightGreen);
else if (sender == rdbtnBackSalmon)
wfh.Background = new SolidColorBrush(Colors.LightSalmon);
else if (UIIsReady == true)
wfh.Background = initBackBrush;
}

private void ForeColorChanged(object sender, RoutedEventArgs e)


{
if (sender == rdbtnForeRed)
wfh.Foreground = new SolidColorBrush(Colors.Red);
else if (sender == rdbtnForeYellow)
wfh.Foreground = new SolidColorBrush(Colors.Yellow);
else if (UIIsReady == true)
wfh.Foreground = initForeBrush;
}

private void FontChanged(object sender, RoutedEventArgs e)


{
if (sender == rdbtnTimes)
wfh.FontFamily = new FontFamily("Times New Roman");
else if (sender == rdbtnWingdings)
wfh.FontFamily = new FontFamily("Wingdings");
else if (UIIsReady == true)
wfh.FontFamily = initFontFamily;
}
private void FontSizeChanged(object sender, RoutedEventArgs e)
{
if (sender == rdbtnTen)
wfh.FontSize = 10;
else if (sender == rdbtnTwelve)
wfh.FontSize = 12;
else if (UIIsReady == true)
wfh.FontSize = initFontSize;
}
private void StyleChanged(object sender, RoutedEventArgs e)
{
if (sender == rdbtnItalic)
wfh.FontStyle = FontStyles.Italic;
else if (UIIsReady == true)
wfh.FontStyle = initFontStyle;
}
private void WeightChanged(object sender, RoutedEventArgs e)
{
if (sender == rdbtnBold)
wfh.FontWeight = FontWeights.Bold;
else if (UIIsReady == true)
wfh.FontWeight = initFontWeight;
}

Build and run the application. Add some text in the Windows Forms composite control
and then click OK. The text appears in the labels. Click the different radio buttons to see
the effect on the control.

See also
ElementHost
WindowsFormsHost
Design XAML in Visual Studio
Walkthrough: Hosting a Windows Forms Control in WPF
Walkthrough: Hosting a WPF Composite Control in Windows Forms
Walkthrough: Hosting an ActiveX
Control in WPF
Article • 02/06/2023

To enable improved interaction with browsers, you can use Microsoft ActiveX controls in
your WPF-based application. This walkthrough demonstrates how you can host the
Microsoft Windows Media Player as a control on a WPF page.

Tasks illustrated in this walkthrough include:

Creating the project.

Creating the ActiveX control.

Hosting the ActiveX control on a WPF Page.

When you have completed this walkthrough, you will understand how to use Microsoft
ActiveX controls in your WPF-based application.

Prerequisites
You need the following components to complete this walkthrough:

Microsoft Windows Media Player installed on the computer where Visual Studio is
installed.

Visual Studio 2010.

Creating the Project

To create and set up the project


1. Create a WPF Application project named HostingAxInWpf .

2. Add a Windows Forms Control Library project to the solution, and name the
project WmpAxLib .

3. In the WmpAxLib project, add a reference to the Windows Media Player assembly,
which is named wmp.dll.

4. Open the Toolbox.


5. Right-click in the Toolbox, and then click Choose Items.

6. Click the COM Components tab, select the Windows Media Player control, and
then click OK.

The Windows Media Player control is added to the Toolbox.

7. In Solution Explorer, right-click the UserControl1 file, and then click Rename.

8. Change the name to WmpAxControl.vb or WmpAxControl.cs , depending on the


language.

9. If you are prompted to rename all references, click Yes.

Creating the ActiveX Control


Visual Studio automatically generates an AxHost wrapper class for a Microsoft ActiveX
control when the control is added to a design surface. The following procedure creates a
managed assembly named AxInterop.WMPLib.dll.

To create the ActiveX control


1. Open WmpAxControl.vb or WmpAxControl.cs in the Windows Forms Designer.

2. From the Toolbox, add the Windows Media Player control to the design surface.

3. In the Properties window, set the value of the Windows Media Player control's
Dock property to Fill.

4. Build the WmpAxLib control library project.

Hosting the ActiveX Control on a WPF Page

To host the ActiveX control


1. In the HostingAxInWpf project, add a reference to the generated ActiveX
interoperability assembly.

This assembly is named AxInterop.WMPLib.dll and was added to the Debug folder
of the WmpAxLib project when you imported the Windows Media Player control.

2. Add a reference to the WindowsFormsIntegration assembly, which is named


WindowsFormsIntegration.dll.
3. Add a reference to the Windows Forms assembly, which is named
System.Windows.Forms.dll.

4. Open MainWindow.xaml in the WPF Designer.

5. Name the Grid element grid1 .

XAML

<Grid Name="grid1">

</Grid>

6. In Design view or XAML view, select the Window element.

7. In the Properties window, click the Events tab.

8. Double-click the Loaded event.

9. Insert the following code to handle the Loaded event.

This code creates an instance of the WindowsFormsHost control and adds an


instance of the AxWindowsMediaPlayer control as its child.

C#

private void Window_Loaded(object sender, RoutedEventArgs e)


{
// Create the interop host control.
System.Windows.Forms.Integration.WindowsFormsHost host =
new System.Windows.Forms.Integration.WindowsFormsHost();

// Create the ActiveX control.


WmpAxLib.AxWindowsMediaPlayer axWmp = new
WmpAxLib.AxWindowsMediaPlayer();

// Assign the ActiveX control as the host control's child.


host.Child = axWmp;

// Add the interop host control to the Grid


// control's collection of child controls.
this.grid1.Children.Add(host);

// Play a .wav file with the ActiveX control.


axWmp.URL = @"C:\Windows\Media\tada.wav";
}

10. Press F5 to build and run the application.


See also
ElementHost
WindowsFormsHost
Design XAML in Visual Studio
Walkthrough: Hosting a Windows Forms Composite Control in WPF
Walkthrough: Hosting a WPF Composite Control in Windows Forms
How to: Enable Visual Styles in a Hybrid
Application
Article • 07/27/2022

This topic shows how to enable visual styles on a Windows Forms control hosted in a
WPF-based application.

If your application calls the EnableVisualStyles method, most of your Windows Forms
controls will automatically use visual styles. For more information, see Rendering
Controls with Visual Styles.

For a complete code listing of the tasks illustrated in this topic, see Enabling Visual
Styles in a Hybrid Application Sample .

Enabling Windows Forms Visual Styles

To enable Windows Forms visual styles

1. Create a WPF Application project named HostingWfWithVisualStyles .

2. In Solution Explorer, add references to the following assemblies.

WindowsFormsIntegration

System.Windows.Forms

3. In the Toolbox, double-click the Grid icon to place a Grid element on the design
surface.

4. In the Properties window, set the values of the Height and Width properties to
Auto.

5. In Design view or XAML view, select the Window.

6. In the Properties window, click the Events tab.

7. Double-click the Loaded event.

8. In MainWindow.xaml.vb or MainWindow.xaml.cs, insert the following code to


handle the Loaded event.

C#
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Comment out the following line to disable visual
// styles for the hosted Windows Forms control.
System.Windows.Forms.Application.EnableVisualStyles();

// Create a WindowsFormsHost element to host


// the Windows Forms control.
System.Windows.Forms.Integration.WindowsFormsHost host =
new System.Windows.Forms.Integration.WindowsFormsHost();

// Create a Windows Forms tab control.


System.Windows.Forms.TabControl tc = new
System.Windows.Forms.TabControl();
tc.TabPages.Add("Tab1");
tc.TabPages.Add("Tab2");

// Assign the Windows Forms tab control as the hosted control.


host.Child = tc;

// Assign the host element to the parent Grid element.


this.grid1.Children.Add(host);
}

9. Press F5 to build and run the application.

The Windows Forms control is painted with visual styles.

Disabling Windows Forms Visual Styles


To disable visual styles, simply remove the call to the EnableVisualStyles method.

To disable Windows Forms visual styles


1. Open MainWindow.xaml.vb or MainWindow.xaml.cs in the Code Editor.

2. Comment out the call to the EnableVisualStyles method.

3. Press F5 to build and run the application.

The Windows Forms control is painted with the default system style.

See also
EnableVisualStyles
System.Windows.Forms.VisualStyles
WindowsFormsHost
Rendering Controls with Visual Styles
Walkthrough: Hosting a Windows Forms Control in WPF
Walkthrough: Arranging Windows
Forms Controls in WPF
Article • 08/18/2022

This walkthrough shows you how to use WPF layout features to arrange Windows Forms
controls in a hybrid application.

Tasks illustrated in this walkthrough include:

Creating the project.


Using default layout settings.
Sizing to content.
Using absolute positioning.
Specifying size explicitly.
Setting layout properties.
Understanding z-order limitations.
Docking.
Setting visibility.
Hosting a control that does not stretch.
Scaling.
Rotating.
Setting padding and margins.
Using dynamic layout containers.

For a complete code listing of the tasks illustrated in this walkthrough, see Arranging
Windows Forms Controls in WPF Sample .

When you are finished, you will have an understanding of Windows Forms layout
features in WPF-based applications.

Prerequisites
You need Visual Studio to complete this walkthrough.

Creating the Project


To create and set up the project, follow these steps:

1. Create a WPF Application project named WpfLayoutHostingWf .


2. In Solution Explorer, add references to the following assemblies:

WindowsFormsIntegration
System.Windows.Forms
System.Drawing

3. Double-click MainWindow.xaml to open it in XAML view.

4. In the Window element, add the following Windows Forms namespace mapping.

XAML

xmlns:wf="clr-
namespace:System.Windows.Forms;assembly=System.Windows.Forms"

5. In the Grid element set the ShowGridLines property to true and define five rows
and three columns.

XAML

<Grid ShowGridLines="true">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>

Using Default Layout Settings


By default, the WindowsFormsHost element handles the layout for the hosted Windows
Forms control.

To use default layout settings, follow these steps:

1. Copy the following XAML into the Grid element:

XAML
<!-- Default layout. -->
<Canvas Grid.Row="0" Grid.Column="0">
<WindowsFormsHost Background="Yellow">
<wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
</WindowsFormsHost>
</Canvas>

2. Press F5 to build and run the application. The Windows Forms


System.Windows.Forms.Button control appears in the Canvas. The hosted control is
sized based on its content, and the WindowsFormsHost element is sized to
accommodate the hosted control.

Sizing to Content
The WindowsFormsHost element ensures that the hosted control is sized to display its
content properly.

To size to content, follow these steps:

1. Copy the following XAML into the Grid element:

XAML

<!-- Sizing to content. -->


<Canvas Grid.Row="1" Grid.Column="0">
<WindowsFormsHost Background="Orange">
<wf:Button Text="Windows Forms control with more content"
FlatStyle="Flat"/>
</WindowsFormsHost>
</Canvas>

<Canvas Grid.Row="2" Grid.Column="0">


<WindowsFormsHost FontSize="24" Background="Yellow">
<wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
</WindowsFormsHost>
</Canvas>

2. Press F5 to build and run the application. The two new button controls are sized
to display the longer text string and larger font size properly, and the
WindowsFormsHost elements are resized to accommodate the hosted controls.

Using Absolute Positioning


You can use absolute positioning to place the WindowsFormsHost element anywhere in
the user interface (UI).
To use absolute positioning, follow these steps:

1. Copy the following XAML into the Grid element:

XAML

<!-- Absolute positioning. -->


<Canvas Grid.Row="3" Grid.Column="0">
<WindowsFormsHost Canvas.Top="20" Canvas.Left="20"
Background="Yellow">
<wf:Button Text="Windows Forms control with absolute positioning"
FlatStyle="Flat"/>
</WindowsFormsHost>
</Canvas>

2. Press F5 to build and run the application. The WindowsFormsHost element is


placed 20 pixels from the top side of the grid cell and 20 pixels from the left.

Specifying Size Explicitly


You can specify the size of the WindowsFormsHost element using the Width and Height
properties.

To specify size explicitly, follow these steps:

1. Copy the following XAML into the Grid element:

XAML

<!-- Explicit sizing. -->


<Canvas Grid.Row="4" Grid.Column="0">
<WindowsFormsHost Width="50" Height="70" Background="Yellow">
<wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
</WindowsFormsHost>
</Canvas>

2. Press F5 to build and run the application. The WindowsFormsHost element is set
to a size of 50 pixels wide by 70 pixels high, which is smaller than the default
layout settings. The content of the Windows Forms control is rearranged
accordingly.

Setting Layout Properties


Always set layout-related properties on the hosted control by using the properties of
the WindowsFormsHost element. Setting layout properties directly on the hosted
control will yield unintended results.

Setting layout-related properties on the hosted control in XAML has no effect.

To see the effects of setting properties on the hosted control, follow these steps:

1. Copy the following XAML into the Grid element:

XAML

<!-- Setting hosted control properties directly. -->


<Canvas Grid.Row="0" Grid.Column="1">
<WindowsFormsHost Width="160" Height="50" Background="Yellow">
<wf:Button Name="button1" Click="button1_Click" Text="Click me"
FlatStyle="Flat" BackColor="Green"/>
</WindowsFormsHost>
</Canvas>

2. In Solution Explorer, double-click MainWindow.xaml.vb or MainWindow.xaml.cs to


open it in the Code Editor.

3. Copy the following code into the MainWindow class definition:

C#

private void button1_Click(object sender, EventArgs e )


{
System.Windows.Forms.Button b = sender as
System.Windows.Forms.Button;

b.Top = 20;
b.Left = 20;
}

4. Press F5 to build and run the application.

5. Click the Click me button. The button1_Click event handler sets the Top and Left
properties on the hosted control. This causes the hosted control to be repositioned
within the WindowsFormsHost element. The host maintains the same screen area,
but the hosted control is clipped. Instead, the hosted control should always fill the
WindowsFormsHost element.

Understanding Z-Order Limitations


Visible WindowsFormsHost elements are always drawn on top of other WPF elements,
and they are unaffected by z-order. To see this z-order behavior, do the following:
1. Copy the following XAML into the Grid element:

XAML

<!-- Z-order demonstration. -->


<Canvas Grid.Row="1" Grid.Column="1">
<WindowsFormsHost Canvas.Top="20" Canvas.Left="20"
Background="Yellow">
<wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
</WindowsFormsHost>
<Label Content="A WPF label" FontSize="24"/>
</Canvas>

2. Press F5 to build and run the application. The WindowsFormsHost element is


painted over the label element.

Docking
WindowsFormsHost element supports WPF docking. Set the Dock attached property to
dock the hosted control in a DockPanel element.

To dock a hosted control, follow these steps:

1. Copy the following XAML into the Grid element:

XAML

<!-- Docking a WindowsFormsHost element. -->


<DockPanel LastChildFill="false" Grid.Row="2" Grid.Column="1">
<WindowsFormsHost DockPanel.Dock="Right" Canvas.Top="20"
Canvas.Left="20" Background="Yellow">
<wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
</WindowsFormsHost>
</DockPanel>

2. Press F5 to build and run the application. The WindowsFormsHost element is


docked to the right side of the DockPanel element.

Setting Visibility
You can make your Windows Forms control invisible or collapse it by setting the
Visibility property on the WindowsFormsHost element. When a control is invisible, it is
not displayed, but it occupies layout space. When a control is collapsed, it is not
displayed, nor does it occupy layout space.
To set the visibility of a hosted control, follow these steps:

1. Copy the following XAML into the Grid element:

XAML

<!-- Setting Visibility to hidden and collapsed. -->


<StackPanel Grid.Row="3" Grid.Column="1">
<Button Name="button2" Click="button2_Click" Content="Click to make
invisible" Background="OrangeRed"/>
<WindowsFormsHost Name="host1" Background="Yellow">
<wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
</WindowsFormsHost>
<Button Name="button3" Click="button3_Click" Content="Click to
collapse" Background="OrangeRed"/>
</StackPanel>

2. In MainWindow.xaml.vb or MainWindow.xaml.cs, copy the following code into the


class definition:

C#

private void button2_Click(object sender, EventArgs e)


{
this.host1.Visibility = Visibility.Hidden;
}

private void button3_Click(object sender, EventArgs e)


{
this.host1.Visibility = Visibility.Collapsed;
}

3. Press F5 to build and run the application.

4. Click the Click to make invisible button to make the WindowsFormsHost element
invisible.

5. Click the Click to collapse button to hide the WindowsFormsHost element from
the layout entirely. When the Windows Forms control is collapsed, the surrounding
elements are rearranged to occupy its space.

Hosting a Control That Does Not Stretch


Some Windows Forms controls have a fixed size and do not stretch to fill available space
in the layout. For example, the MonthCalendar control displays a month in a fixed space.

To host a control that does not stretch, follow these steps:


1. Copy the following XAML into the Grid element:

XAML

<!-- Hosting a control that does not stretch. -->


<!-- The MonthCalendar has a discrete size. -->
<StackPanel Grid.Row="4" Grid.Column="1">
<Label Content="A WPF element" Background="OrangeRed"/>
<WindowsFormsHost Background="Yellow">
<wf:MonthCalendar/>
</WindowsFormsHost>
<Label Content="Another WPF element" Background="OrangeRed"/>
</StackPanel>

2. Press F5 to build and run the application. The WindowsFormsHost element is


centered in the grid row, but it is not stretched to fill the available space. If the
window is large enough, you may see two or more months displayed by the
hosted MonthCalendar control, but these are centered in the row. The WPF layout
engine centers elements that cannot be sized to fill the available space.

Scaling
Unlike WPF elements, most Windows Forms controls are not continuously scalable. To
provide custom scaling, you override the WindowsFormsHost.ScaleChild method.

To scale a hosted control by using the default behavior, follow these steps:

1. Copy the following XAML into the Grid element:

XAML

<!-- Scaling transformation. -->


<StackPanel Grid.Row="0" Grid.Column="2">

<StackPanel.RenderTransform>
<ScaleTransform CenterX="0" CenterY="0" ScaleX="0.5" ScaleY="0.5"
/>
</StackPanel.RenderTransform>

<Label Content="A WPF UIElement" Background="OrangeRed"/>

<WindowsFormsHost Background="Yellow">
<wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
</WindowsFormsHost>

<Label Content="Another WPF UIElement" Background="OrangeRed"/>

</StackPanel>
2. Press F5 to build and run the application. The hosted control and its surrounding
elements are scaled by a factor of 0.5. However, the hosted control's font is not
scaled.

Rotating
Unlike WPF elements, Windows Forms controls do not support rotation. The
WindowsFormsHost element does not rotate with other WPF elements when a rotation
transformation is applied. Any rotation value other than 180 degrees raises the
LayoutError event.

To see the effect of rotation in a hybrid application, follow these steps:

1. Copy the following XAML into the Grid element:

XAML

<!-- Rotation transformation. -->


<StackPanel Grid.Row="1" Grid.Column="2">

<StackPanel.RenderTransform>
<RotateTransform CenterX="200" CenterY="50" Angle="180" />
</StackPanel.RenderTransform>

<Label Content="A WPF element" Background="OrangeRed"/>

<WindowsFormsHost Background="Yellow">
<wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
</WindowsFormsHost>

<Label Content="Another WPF element" Background="OrangeRed"/>

</StackPanel>

2. Press F5 to build and run the application. The hosted control is not rotated, but its
surrounding elements are rotated by an angle of 180 degrees. You may have to
resize the window to see the elements.

Setting Padding and Margins


Padding and margins in WPF layout are similar to padding and margins in Windows
Forms. Simply set the Padding and Margin properties on the WindowsFormsHost
element.

To set padding and margins for a hosted control, follow these steps:
1. Copy the following XAML into the Grid element:

XAML

<!-- Padding. -->


<Canvas Grid.Row="2" Grid.Column="2">
<WindowsFormsHost Padding="0, 20, 0, 0" Background="Yellow">
<wf:Button Text="Windows Forms control with padding"
FlatStyle="Flat"/>
</WindowsFormsHost>
</Canvas>

XAML

<!-- Margin. -->


<Canvas Grid.Row="3" Grid.Column="2">
<WindowsFormsHost Margin="20, 20, 0, 0" Background="Yellow">
<wf:Button Text="Windows Forms control with margin"
FlatStyle="Flat"/>
</WindowsFormsHost>
</Canvas>

2. Press F5 to build and run the application. The padding and margin settings are
applied to the hosted Windows Forms controls in the same way they would be
applied in Windows Forms.

Using Dynamic Layout Containers


Windows Forms provides two dynamic layout containers, FlowLayoutPanel and
TableLayoutPanel. You can also use these containers in WPF layouts.

To use a dynamic layout container, follow these steps:

1. Copy the following XAML into the Grid element:

XAML

<!-- Flow layout. -->


<DockPanel Grid.Row="4" Grid.Column="2">
<WindowsFormsHost Name="flowLayoutHost" Background="Yellow">
<wf:FlowLayoutPanel/>
</WindowsFormsHost>
</DockPanel>

2. In MainWindow.xaml.vb or MainWindow.xaml.cs, copy the following code into the


class definition:
C#

private void InitializeFlowLayoutPanel()


{
System.Windows.Forms.FlowLayoutPanel flp =
this.flowLayoutHost.Child as
System.Windows.Forms.FlowLayoutPanel;

flp.WrapContents = true;

const int numButtons = 6;

for (int i = 0; i < numButtons; i++)


{
System.Windows.Forms.Button b = new
System.Windows.Forms.Button();
b.Text = "Button";
b.BackColor = System.Drawing.Color.AliceBlue;
b.FlatStyle = System.Windows.Forms.FlatStyle.Flat;

flp.Controls.Add(b);
}
}

3. Add a call to the InitializeFlowLayoutPanel method in the constructor:

C#

public MainWindow()
{
InitializeComponent();

this.InitializeFlowLayoutPanel();
}

4. Press F5 to build and run the application. The WindowsFormsHost element fills
the DockPanel, and FlowLayoutPanel arranges its child controls in the default
FlowDirection.

See also
ElementHost
WindowsFormsHost
Design XAML in Visual Studio
Layout Considerations for the WindowsFormsHost Element
Arranging Windows Forms Controls in WPF Sample
Walkthrough: Hosting a Windows Forms Composite Control in WPF
Walkthrough: Hosting a WPF Composite Control in Windows Forms
Walkthrough: Binding to Data in Hybrid
Applications
Article • 08/18/2022

Binding a data source to a control is essential for providing users with access to
underlying data, whether you are using Windows Forms or WPF. This walkthrough
shows how you can use data binding in hybrid applications that include both Windows
Forms and WPF controls.

Tasks illustrated in this walkthrough include:

Creating the project.

Defining the data template.

Specifying the form layout.

Specifying data bindings.

Displaying data by using interoperation.

Adding the data source to the project.

Binding to the data source.

For a complete code listing of the tasks illustrated in this walkthrough, see Data Binding
in Hybrid Applications Sample .

When you are finished, you will have an understanding of data binding features in
hybrid applications.

Prerequisites
You need the following components to complete this walkthrough:

Visual Studio.

Access to the Northwind sample database running on Microsoft SQL Server.

Creating the Project

To create and set up the project


1. Create a WPF Application project named WPFWithWFAndDatabinding .

2. In Solution Explorer, add references to the following assemblies.

WindowsFormsIntegration

System.Windows.Forms

3. Open MainWindow.xaml in the WPF Designer.

4. In the Window element, add the following Windows Forms namespaces mapping.

XAML

xmlns:wf="clr-
namespace:System.Windows.Forms;assembly=System.Windows.Forms"

5. Name the default Grid element mainGrid by assigning the Name property.

XAML

<Grid x:Name="mainGrid">

Defining the Data Template


The master list of customers is displayed in a ListBox control. The following code
example defines a DataTemplate object named ListItemsTemplate that controls the
visual tree of the ListBox control. This DataTemplate is assigned to the ListBox control's
ItemTemplate property.

To define the data template


Copy the following XAML into the Grid element's declaration.

XAML

<Grid.Resources>
<DataTemplate x:Key="ListItemsTemplate">
<TextBlock Text="{Binding Path=ContactName}"/>
</DataTemplate>
</Grid.Resources>

Specifying the Form Layout


The layout of the form is defined by a grid with three rows and three columns. Label
controls are provided to identify each column in the Customers table.

To set up the Grid layout


Copy the following XAML into the Grid element's declaration.

XAML

<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>

To set up the Label controls


Copy the following XAML into the Grid element's declaration.

XAML

<StackPanel Orientation="Vertical" Grid.Row="0" Grid.Column="1">


<Label Margin="20,38,5,2">First Name:</Label>
<Label Margin="20,0,5,2">Company Name:</Label>
<Label Margin="20,0,5,2">Phone:</Label>
<Label Margin="20,0,5,2">Address:</Label>
<Label Margin="20,0,5,2">City:</Label>
<Label Margin="20,0,5,2">Region:</Label>
<Label Margin="20,0,5,2">Postal Code:</Label>
</StackPanel>

Specifying Data Bindings


The master list of customers is displayed in a ListBox control. The attached
ListItemsTemplate binds a TextBlock control to the ContactName field from the database.

The details of each customer record are displayed in several TextBox controls.

To specify data bindings


Copy the following XAML into the Grid element's declaration.

The Binding class binds the TextBox controls to the appropriate fields in the
database.

XAML

<StackPanel Orientation="Vertical" Grid.Row="0" Grid.Column="0">


<Label Margin="20,5,5,0">List of Customers:</Label>
<ListBox x:Name="listBox1" Height="200" Width="200"
HorizontalAlignment="Left"
ItemTemplate="{StaticResource ListItemsTemplate}"
IsSynchronizedWithCurrentItem="True" Margin="20,5,5,5"/>
</StackPanel>

<StackPanel Orientation="Vertical" Grid.Row="0" Grid.Column="2">


<TextBox Margin="5,38,5,2" Width="200" Text="{Binding
Path=ContactName}"/>
<TextBox Margin="5,0,5,2" Width="200" Text="{Binding
Path=CompanyName}"/>
<TextBox Margin="5,0,5,2" Width="200" Text="{Binding Path=Phone}"/>
<TextBox Margin="5,0,5,2" Width="200" Text="{Binding
Path=Address}"/>
<TextBox Margin="5,0,5,2" Width="200" Text="{Binding Path=City}"/>
<TextBox Margin="5,0,5,2" Width="30" HorizontalAlignment="Left"
Text="{Binding Path=Region}"/>
<TextBox Margin="5,0,5,2" Width="50" HorizontalAlignment="Left"
Text="{Binding Path=PostalCode}"/>
</StackPanel>

Displaying Data by Using Interoperation


The orders corresponding to the selected customer are displayed in a
System.Windows.Forms.DataGridView control named dataGridView1 . The dataGridView1
control is bound to the data source in the code-behind file. A WindowsFormsHost
control is the parent of this Windows Forms control.

To display data in the DataGridView control


Copy the following XAML into the Grid element's declaration.

XAML

<WindowsFormsHost Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3"


Margin="20,5,5,5" Height="300">
<wf:DataGridView x:Name="dataGridView1"/>
</WindowsFormsHost>
Adding the Data Source to the Project
With Visual Studio, you can easily add a data source to your project. This procedure
adds a strongly typed data set to your project. Several other support classes, such as
table adapters for each of the chosen tables, are also added.

To add the data source


1. From the Data menu, select Add New Data Source.

2. In the Data Source Configuration Wizard, create a connection to the Northwind


database by using a dataset. For more information, see How to: Connect to Data in
a Database.

3. When you are prompted by the Data Source Configuration Wizard, save the
connection string as NorthwindConnectionString .

4. When you are prompted to choose your database objects, select the Customers
and Orders tables, and name the generated data set NorthwindDataSet .

Binding to the Data Source


The System.Windows.Forms.BindingSource component provides a uniform interface for
the application's data source. Binding to the data source is implemented in the code-
behind file.

To bind to the data source


1. Open the code-behind file, which is named MainWindow.xaml.vb or
MainWindow.xaml.cs.

2. Copy the following code into the MainWindow class definition.

This code declares the BindingSource component and associated helper classes
that connect to the database.

C#

private System.Windows.Forms.BindingSource nwBindingSource;


private NorthwindDataSet nwDataSet;
private NorthwindDataSetTableAdapters.CustomersTableAdapter
customersTableAdapter =
new NorthwindDataSetTableAdapters.CustomersTableAdapter();
private NorthwindDataSetTableAdapters.OrdersTableAdapter
ordersTableAdapter =
new NorthwindDataSetTableAdapters.OrdersTableAdapter();

3. Copy the following code into the constructor.

This code creates and initializes the BindingSource component.

C#

public MainWindow()
{
InitializeComponent();

// Create a DataSet for the Customers data.


this.nwDataSet = new NorthwindDataSet();
this.nwDataSet.DataSetName = "nwDataSet";

// Create a BindingSource for the Customers data.


this.nwBindingSource = new System.Windows.Forms.BindingSource();
this.nwBindingSource.DataMember = "Customers";
this.nwBindingSource.DataSource = this.nwDataSet;
}

4. Open MainWindow.xaml.

5. In Design view or XAML view, select the Window element.

6. In the Properties window, click the Events tab.

7. Double-click the Loaded event.

8. Copy the following code into the Loaded event handler.

This code assigns the BindingSource component as the data context and populates
the Customers and Orders adapter objects.

C#

private void Window_Loaded(object sender, RoutedEventArgs e)


{
// Fill the Customers table adapter with data.
this.customersTableAdapter.ClearBeforeFill = true;
this.customersTableAdapter.Fill(this.nwDataSet.Customers);

// Fill the Orders table adapter with data.


this.ordersTableAdapter.Fill(this.nwDataSet.Orders);

// Assign the BindingSource to


// the data context of the main grid.
this.mainGrid.DataContext = this.nwBindingSource;

// Assign the BindingSource to


// the data source of the list box.
this.listBox1.ItemsSource = this.nwBindingSource;

// Because this is a master/details form, the DataGridView


// requires the foreign key relating the tables.
this.dataGridView1.DataSource = this.nwBindingSource;
this.dataGridView1.DataMember = "FK_Orders_Customers";

// Handle the currency management aspect of the data models.


// Attach an event handler to detect when the current item
// changes via the WPF ListBox. This event handler synchronizes
// the list collection with the BindingSource.
//

BindingListCollectionView cv = CollectionViewSource.GetDefaultView(
this.nwBindingSource) as BindingListCollectionView;

cv.CurrentChanged += new EventHandler(WPF_CurrentChanged);


}

9. Copy the following code into the MainWindow class definition.

This method handles the CurrentChanged event and updates the current item of
the data binding.

C#

// This event handler updates the current item


// of the data binding.
void WPF_CurrentChanged(object sender, EventArgs e)
{
BindingListCollectionView cv = sender as BindingListCollectionView;
this.nwBindingSource.Position = cv.CurrentPosition;
}

10. Press F5 to build and run the application.

See also
ElementHost
WindowsFormsHost
Design XAML in Visual Studio
Data Binding in Hybrid Applications Sample
Walkthrough: Hosting a Windows Forms Composite Control in WPF
Walkthrough: Hosting a WPF Composite Control in Windows Forms
Walkthrough: Host a 3D WPF Composite
Control in Windows Forms
Article • 06/02/2023

This walkthrough demonstrates how you can create a WPF composite control and host
it in Windows Forms controls and forms by using the ElementHost control.

In this walkthrough, you will implement a WPF UserControl that contains two child
controls. The UserControl displays a three-dimensional (3D) cone. Rendering 3D objects
is much easier with the WPF than with Windows Forms. Therefore, it makes sense to
host a WPF UserControl class to create 3D graphics in Windows Forms.

Tasks illustrated in this walkthrough include:

Creating the WPF UserControl.

Creating the Windows Forms host project.

Hosting the WPF UserControl.

Prerequisites
You need the following components to complete this walkthrough:

Visual Studio 2017

Create the UserControl


1. Create a WPF User Control Library project named HostingWpfUserControlInWf .

2. Open UserControl1.xaml in the WPF Designer.

3. Replace the generated code with the following code:

XAML

<UserControl x:Class="HostingWpfUserControlInWf.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>

<Grid>

<!-- Place a Label control at the top of the view. -->


<Label
HorizontalAlignment="Center"
TextBlock.TextAlignment="Center"
FontSize="20"
Foreground="Red"
Content="Model: Cone"/>

<!-- Viewport3D is the rendering surface. -->


<Viewport3D Name="myViewport" >

<!-- Add a camera. -->


<Viewport3D.Camera>
<PerspectiveCamera
FarPlaneDistance="20"
LookDirection="0,0,1"
UpDirection="0,1,0"
NearPlaneDistance="1"
Position="0,0,-3"
FieldOfView="45" />
</Viewport3D.Camera>

<!-- Add models. -->


<Viewport3D.Children>

<ModelVisual3D>
<ModelVisual3D.Content>

<Model3DGroup >
<Model3DGroup.Children>

<!-- Lights, MeshGeometry3D and DiffuseMaterial


objects are added to the ModelVisual3D. -->
<DirectionalLight Color="#FFFFFFFF"
Direction="3,-4,5" />

<!-- Define a red cone. -->


<GeometryModel3D>

<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="0.293893 -0.5 0.404509 0.475528 -0.5 0.154509 0 0.5 0
0.475528 -0.5 0.154509 0 0.5 0 0 0.5 0 0.475528 -0.5 0.154509
0.475528 -0.5 -0.154509 0 0.5 0 0.475528 -0.5 -0.154509 0 0.5 0 0
0.5 0 0.475528 -0.5 -0.154509 0.293893 -0.5 -0.404509 0 0.5 0
0.293893 -0.5 -0.404509 0 0.5 0 0 0.5 0 0.293893 -0.5 -0.404509 0
-0.5 -0.5 0 0.5 0 0 -0.5 -0.5 0 0.5 0 0 0.5 0 0 -0.5 -0.5
-0.293893 -0.5 -0.404509 0 0.5 0 -0.293893 -0.5 -0.404509 0 0.5 0 0
0.5 0 -0.293893 -0.5 -0.404509 -0.475528 -0.5 -0.154509 0 0.5 0
-0.475528 -0.5 -0.154509 0 0.5 0 0 0.5 0 -0.475528 -0.5 -0.154509
-0.475528 -0.5 0.154509 0 0.5 0 -0.475528 -0.5 0.154509 0 0.5 0 0
0.5 0 -0.475528 -0.5 0.154509 -0.293892 -0.5 0.404509 0 0.5 0
-0.293892 -0.5 0.404509 0 0.5 0 0 0.5 0 -0.293892 -0.5 0.404509 0
-0.5 0.5 0 0.5 0 0 -0.5 0.5 0 0.5 0 0 0.5 0 0 -0.5 0.5 0.293893
-0.5 0.404509 0 0.5 0 0.293893 -0.5 0.404509 0 0.5 0 0 0.5 0 "
Normals="0.7236065,0.4472139,0.5257313
0.2763934,0.4472138,0.8506507 0.5308242,0.4294462,0.7306172
0.2763934,0.4472138,0.8506507 0,0.4294458,0.9030925
0.5308242,0.4294462,0.7306172 0.2763934,0.4472138,0.8506507
-0.2763934,0.4472138,0.8506507 0,0.4294458,0.9030925
-0.2763934,0.4472138,0.8506507 -0.5308242,0.4294462,0.7306172
0,0.4294458,0.9030925 -0.2763934,0.4472138,0.8506507
-0.7236065,0.4472139,0.5257313 -0.5308242,0.4294462,0.7306172
-0.7236065,0.4472139,0.5257313 -0.858892,0.429446,0.279071
-0.5308242,0.4294462,0.7306172 -0.7236065,0.4472139,0.5257313
-0.8944269,0.4472139,0 -0.858892,0.429446,0.279071
-0.8944269,0.4472139,0 -0.858892,0.429446,-0.279071
-0.858892,0.429446,0.279071 -0.8944269,0.4472139,0
-0.7236065,0.4472139,-0.5257313 -0.858892,0.429446,-0.279071
-0.7236065,0.4472139,-0.5257313 -0.5308242,0.4294462,-0.7306172
-0.858892,0.429446,-0.279071 -0.7236065,0.4472139,-0.5257313
-0.2763934,0.4472138,-0.8506507 -0.5308242,0.4294462,-0.7306172
-0.2763934,0.4472138,-0.8506507 0,0.4294458,-0.9030925
-0.5308242,0.4294462,-0.7306172 -0.2763934,0.4472138,-0.8506507
0.2763934,0.4472138,-0.8506507 0,0.4294458,-0.9030925
0.2763934,0.4472138,-0.8506507 0.5308249,0.4294459,-0.7306169
0,0.4294458,-0.9030925 0.2763934,0.4472138,-0.8506507
0.7236068,0.4472141,-0.5257306 0.5308249,0.4294459,-0.7306169
0.7236068,0.4472141,-0.5257306 0.8588922,0.4294461,-0.27907
0.5308249,0.4294459,-0.7306169 0.7236068,0.4472141,-0.5257306
0.8944269,0.4472139,0 0.8588922,0.4294461,-0.27907
0.8944269,0.4472139,0 0.858892,0.429446,0.279071
0.8588922,0.4294461,-0.27907 0.8944269,0.4472139,0
0.7236065,0.4472139,0.5257313 0.858892,0.429446,0.279071
0.7236065,0.4472139,0.5257313 0.5308242,0.4294462,0.7306172
0.858892,0.429446,0.279071 " TriangleIndices="0 1 2
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
53 54 55 56 57 58 59 " />
</GeometryModel3D.Geometry>

<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<SolidColorBrush
Color="Red"
Opacity="1.0"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>

</GeometryModel3D>

</Model3DGroup.Children>
</Model3DGroup>

</ModelVisual3D.Content>

</ModelVisual3D>

</Viewport3D.Children>
</Viewport3D>
</Grid>

</UserControl>

This code defines a System.Windows.Controls.UserControl that contains two child


controls. The first child control is a System.Windows.Controls.Label control; the
second is a Viewport3D control that displays a 3D cone.

Create the host project


1. Add a Windows Forms App (.NET Framework) project named WpfUserControlHost
to the solution.

2. In Solution Explorer, add a reference to the WindowsFormsIntegration assembly,


which is named WindowsFormsIntegration.dll.

3. Add references to the following WPF assemblies:

PresentationCore

PresentationFramework

WindowsBase

4. Add a reference to the HostingWpfUserControlInWf project.

5. In Solution Explorer, set the WpfUserControlHost project to be the startup project.

Host the UserControl


1. In the Windows Forms Designer, open Form1.

2. In the Properties window, click Events, and then double-click the Load event to
create an event handler.

The Code Editor opens to the newly generated Form1_Load event handler.

3. Replace the code in Form1.cs with the following code.

The Form1_Load event handler creates an instance of UserControl1 and adds it to


the ElementHost control's collection of child controls. The ElementHost control is
added to the form's collection of child controls.
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Windows.Forms.Integration;

namespace WpfUserControlHost
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)


{
// Create the ElementHost control for hosting the
// WPF UserControl.
ElementHost host = new ElementHost();
host.Dock = DockStyle.Fill;

// Create the WPF UserControl.


HostingWpfUserControlInWf.UserControl1 uc =
new HostingWpfUserControlInWf.UserControl1();

// Assign the WPF UserControl to the ElementHost control's


// Child property.
host.Child = uc;

// Add the ElementHost control to the form's


// collection of child controls.
this.Controls.Add(host);
}
}
}

4. Press F5 to build and run the application.

See also
ElementHost
WindowsFormsHost
Design XAML in Visual Studio
Walkthrough: Hosting a WPF Composite Control in Windows Forms
Walkthrough: Hosting a Windows Forms Composite Control in WPF
Hosting a WPF Composite Control in Windows Forms Sample
Walkthrough: Hosting a WPF Composite
Control in Windows Forms
Article • 02/06/2023

WPF rather than to rewrite it from scratch. A common scenario is when you want to
embed one or more controls implemented with WPF within your Windows Forms
application. For more information about customizing WPF controls, see Control
Customization.

This walkthrough steps you through an application that hosts a WPF composite control
to perform data-entry in a Windows Forms application. The composite control is
packaged in a DLL. This general procedure can be extended to more complex
applications and controls. This walkthrough is designed to be nearly identical in
appearance and functionality to Walkthrough: Hosting a Windows Forms Composite
Control in WPF. The primary difference is that the hosting scenario is reversed.

The walkthrough is divided into two sections. The first section briefly describes the
implementation of the WPF composite control. The second section discusses in detail
how to host the composite control in a Windows Forms application, receive events from
the control, and access some of the control's properties.

Tasks illustrated in this walkthrough include:

Implementing the WPF composite control.

Implementing the Windows Forms host application.

For a complete code listing of the tasks illustrated in this walkthrough, see Hosting a
WPF Composite Control in Windows Forms Sample .

Prerequisites
You need Visual Studio to complete this walkthrough.

Implementing the WPF Composite Control


The WPF composite control used in this example is a simple data-entry form that takes
the user's name and address. When the user clicks one of two buttons to indicate that
the task is finished, the control raises a custom event to return that information to the
host. The following illustration shows the rendered control.
The following image shows a WPF composite control:

Creating the Project


To start the project:

1. Launch Visual Studio, and open the New Project dialog box.

2. In Visual C# and the Windows category, select the WPF User Control Library
template.

3. Name the new project MyControls .

4. For the location, specify a conveniently named top-level folder, such as


WindowsFormsHostingWpfControl . Later, you will put the host application in this
folder.

5. Click OK to create the project. The default project contains a single control named
UserControl1 .

6. In Solution Explorer, rename UserControl1 to MyControl1 .

Your project should have references to the following system DLLs. If any of these DLLs
are not included by default, add them to your project.

PresentationCore

PresentationFramework

System

WindowsBase

Creating the User Interface


The UI consists of five TextBox elements. Each TextBox element has an associated
TextBlock element that serves as a label. There are two Button elements at the bottom,
OK and Cancel. When the user clicks either button, the control raises a custom event to
return the information to the host.

Basic Layout

The various UI elements are contained in a Grid element. You can use Grid to arrange
the contents of the composite control in much the same way you would use a Table
element in HTML. WPF also has a Table element, but Grid is more lightweight and better
suited for simple layout tasks.

The following XAML shows the basic layout. This XAML defines the overall structure of
the control by specifying the number of columns and rows in the Grid element.

In MyControl1.xaml, replace the existing XAML with the following XAML.

XAML

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MyControls.MyControl1"
Background="#DCDCDC"
Width="375"
Height="250"
Name="rootElement"
Loaded="Init">

<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>

<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

XAML

</Grid>
Adding TextBlock and TextBox Elements to the Grid
You place a UI element in the grid by setting the element's RowProperty and
ColumnProperty attributes to the appropriate row and column number. Remember that
row and column numbering are zero-based. You can have an element span multiple
columns by setting its ColumnSpanProperty attribute. For more information about Grid
elements, see Create a Grid Element.

The following XAML shows the composite control's TextBox and TextBlock elements with
their RowProperty and ColumnProperty attributes, which are set to place the elements
properly in the grid.

In MyControl1.xaml, add the following XAML within the Grid element.

XAML

<TextBlock Grid.Column="0"
Grid.Row="0"
Grid.ColumnSpan="4"
Margin="10,5,10,0"
HorizontalAlignment="Center"
Style="{StaticResource titleText}">Simple WPF Control</TextBlock>

<TextBlock Grid.Column="0"
Grid.Row="1"
Style="{StaticResource inlineText}"
Name="nameLabel">Name</TextBlock>
<TextBox Grid.Column="1"
Grid.Row="1"
Grid.ColumnSpan="3"
Name="txtName"/>

<TextBlock Grid.Column="0"
Grid.Row="2"
Style="{StaticResource inlineText}"
Name="addressLabel">Street Address</TextBlock>
<TextBox Grid.Column="1"
Grid.Row="2"
Grid.ColumnSpan="3"
Name="txtAddress"/>

<TextBlock Grid.Column="0"
Grid.Row="3"
Style="{StaticResource inlineText}"
Name="cityLabel">City</TextBlock>
<TextBox Grid.Column="1"
Grid.Row="3"
Width="100"
Name="txtCity"/>

<TextBlock Grid.Column="2"
Grid.Row="3"
Style="{StaticResource inlineText}"
Name="stateLabel">State</TextBlock>
<TextBox Grid.Column="3"
Grid.Row="3"
Width="50"
Name="txtState"/>

<TextBlock Grid.Column="0"
Grid.Row="4"
Style="{StaticResource inlineText}"
Name="zipLabel">Zip</TextBlock>
<TextBox Grid.Column="1"
Grid.Row="4"
Width="100"
Name="txtZip"/>

Styling the UI Elements


Many of the elements on the data-entry form have a similar appearance, which means
that they have identical settings for several of their properties. Rather than setting each
element's attributes separately, the previous XAML uses Style elements to define
standard property settings for classes of elements. This approach reduces the
complexity of the control and enables you to change the appearance of multiple
elements through a single style attribute.

The Style elements are contained in the Grid element's Resources property, so they can
be used by all elements in the control. If a style is named, you apply it to an element by
adding a Style element set to the style's name. Styles that are not named become the
default style for the element. For more information about WPF styles, see Styling and
Templating.

The following XAML shows the Style elements for the composite control. To see how the
styles are applied to elements, see the previous XAML. For example, the last TextBlock
element has the inlineText style, and the last TextBox element uses the default style.

In MyControl1.xaml, add the following XAML just after the Grid start element.

XAML

<Grid.Resources>
<Style x:Key="inlineText" TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="10,5,10,0"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="FontSize" Value="12"/>
</Style>
<Style x:Key="titleText" TargetType="{x:Type TextBlock}">
<Setter Property="DockPanel.Dock" Value="Top"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Margin" Value="10,5,10,0"/>
</Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="10,5,10,0"/>
<Setter Property="Width" Value="60"/>
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="10,5,10,0"/>
</Style>
</Grid.Resources>

Adding the OK and Cancel Buttons


The final elements on the composite control are the OK and CancelButton elements,
which occupy the first two columns of the last row of the Grid. These elements use a
common event handler, ButtonClicked , and the default Button style defined in the
previous XAML.

In MyControl1.xaml, add the following XAML after the last TextBox element. The XAML
part of the composite control is now complete.

XAML

<Button Grid.Row="5"
Grid.Column="0"
Name="btnOK"
Click="ButtonClicked">OK</Button>
<Button Grid.Row="5"
Grid.Column="1"
Name="btnCancel"
Click="ButtonClicked">Cancel</Button>

Implementing the Code-Behind File


The code-behind file, MyControl1.xaml.cs, implements three essential tasks:

1. Handles the event that occurs when the user clicks one of the buttons.

2. Retrieves the data from the TextBox elements, and packages it in a custom event
argument object.

3. Raises the custom OnButtonClick event, which notifies the host that the user is
finished and passes the data back to the host.
The control also exposes a number of color and font properties that enable you to
change the appearance. Unlike the WindowsFormsHost class, which is used to host a
Windows Forms control, the ElementHost class exposes the control's Background
property only. To maintain the similarity between this code example and the example
discussed in Walkthrough: Hosting a Windows Forms Composite Control in WPF, the
control exposes the remaining properties directly.

The Basic Structure of the Code-Behind File


The code-behind file consists of a single namespace, MyControls , which will contain two
classes, MyControl1 and MyControlEventArgs .

C#

namespace MyControls
{
public partial class MyControl1 : Grid
{
//...
}
public class MyControlEventArgs : EventArgs
{
//...
}
}

The first class, MyControl1 , is a partial class containing the code that implements the
functionality of the UI defined in MyControl1.xaml. When MyControl1.xaml is parsed, the
XAML is converted to the same partial class, and the two partial classes are merged to
form the compiled control. For this reason, the class name in the code-behind file must
match the class name assigned to MyControl1.xaml, and it must inherit from the root
element of the control. The second class, MyControlEventArgs , is an event arguments
class that is used to send the data back to the host.

Open MyControl1.xaml.cs. Change the existing class declaration so that it has the
following name and inherits from Grid.

C#

public partial class MyControl1 : Grid

Initializing the Control


The following code implements several basic tasks:

Declares a private event, OnButtonClick , and its associated delegate,


MyControlEventHandler .

Creates several private global variables that store the user's data. This data is
exposed through corresponding properties.

Implements a handler, Init , for the control's Loaded event. This handler initializes
the global variables by assigning them the values defined in MyControl1.xaml. To
do this, it uses the Name assigned to a typical TextBlock element, nameLabel , to
access that element's property settings.

Delete the existing constructor and add the following code to your MyControl1 class.

C#

public delegate void MyControlEventHandler(object sender, MyControlEventArgs


args);
public event MyControlEventHandler OnButtonClick;
private FontWeight _fontWeight;
private double _fontSize;
private FontFamily _fontFamily;
private FontStyle _fontStyle;
private SolidColorBrush _foreground;
private SolidColorBrush _background;

private void Init(object sender, EventArgs e)


{
//They all have the same style, so use nameLabel to set initial values.
_fontWeight = nameLabel.FontWeight;
_fontSize = nameLabel.FontSize;
_fontFamily = nameLabel.FontFamily;
_fontStyle = nameLabel.FontStyle;
_foreground = (SolidColorBrush)nameLabel.Foreground;
_background = (SolidColorBrush)rootElement.Background;
}

Handling the Buttons' Click Events


The user indicates that the data-entry task is finished by clicking either the OK button or
the Cancel button. Both buttons use the same Click event handler, ButtonClicked . Both
buttons have a name, btnOK or btnCancel , that enables the handler to determine which
button was clicked by examining the value of the sender argument. The handler does
the following:
Creates a MyControlEventArgs object that contains the data from the TextBox
elements.

If the user clicked the Cancel button, sets the MyControlEventArgs object's IsOK
property to false .

Raises the OnButtonClick event to indicate to the host that the user is finished, and
passes back the collected data.

Add the following code to your MyControl1 class, after the Init method.

C#

private void ButtonClicked(object sender, RoutedEventArgs e)


{
MyControlEventArgs retvals = new MyControlEventArgs(true,
txtName.Text,
txtAddress.Text,
txtCity.Text,
txtState.Text,
txtZip.Text);
if (sender == btnCancel)
{
retvals.IsOK = false;
}
if (OnButtonClick != null)
OnButtonClick(this, retvals);
}

Creating Properties
The remainder of the class simply exposes properties that correspond to the global
variables discussed previously. When a property changes, the set accessor modifies the
appearance of the control by changing the corresponding element properties and
updating the underlying global variables.

Add the following code to your MyControl1 class.

C#

public FontWeight MyControl_FontWeight


{
get { return _fontWeight; }
set
{
_fontWeight = value;
nameLabel.FontWeight = value;
addressLabel.FontWeight = value;
cityLabel.FontWeight = value;
stateLabel.FontWeight = value;
zipLabel.FontWeight = value;
}
}
public double MyControl_FontSize
{
get { return _fontSize; }
set
{
_fontSize = value;
nameLabel.FontSize = value;
addressLabel.FontSize = value;
cityLabel.FontSize = value;
stateLabel.FontSize = value;
zipLabel.FontSize = value;
}
}
public FontStyle MyControl_FontStyle
{
get { return _fontStyle; }
set
{
_fontStyle = value;
nameLabel.FontStyle = value;
addressLabel.FontStyle = value;
cityLabel.FontStyle = value;
stateLabel.FontStyle = value;
zipLabel.FontStyle = value;
}
}
public FontFamily MyControl_FontFamily
{
get { return _fontFamily; }
set
{
_fontFamily = value;
nameLabel.FontFamily = value;
addressLabel.FontFamily = value;
cityLabel.FontFamily = value;
stateLabel.FontFamily = value;
zipLabel.FontFamily = value;
}
}

public SolidColorBrush MyControl_Background


{
get { return _background; }
set
{
_background = value;
rootElement.Background = value;
}
}
public SolidColorBrush MyControl_Foreground
{
get { return _foreground; }
set
{
_foreground = value;
nameLabel.Foreground = value;
addressLabel.Foreground = value;
cityLabel.Foreground = value;
stateLabel.Foreground = value;
zipLabel.Foreground = value;
}
}

Sending the Data Back to the Host


The final component in the file is the MyControlEventArgs class, which is used to send
the collected data back to the host.

Add the following code to your MyControls namespace. The implementation is


straightforward, and is not discussed further.

C#

public class MyControlEventArgs : EventArgs


{
private string _Name;
private string _StreetAddress;
private string _City;
private string _State;
private string _Zip;
private bool _IsOK;

public MyControlEventArgs(bool result,


string name,
string address,
string city,
string state,
string zip)
{
_IsOK = result;
_Name = name;
_StreetAddress = address;
_City = city;
_State = state;
_Zip = zip;
}

public string MyName


{
get { return _Name; }
set { _Name = value; }
}
public string MyStreetAddress
{
get { return _StreetAddress; }
set { _StreetAddress = value; }
}
public string MyCity
{
get { return _City; }
set { _City = value; }
}
public string MyState
{
get { return _State; }
set { _State = value; }
}
public string MyZip
{
get { return _Zip; }
set { _Zip = value; }
}
public bool IsOK
{
get { return _IsOK; }
set { _IsOK = value; }
}
}

Build the solution. The build will produce a DLL named MyControls.dll.

Implementing the Windows Forms Host


Application
The Windows Forms host application uses an ElementHost object to host the WPF
composite control. The application handles the OnButtonClick event to receive the data
from the composite control. The application also has a set of option buttons that you
can use to modify the control's appearance. The following illustration shows the
application.

The following image shows a WPF composite control hosted in a Windows Forms
application
Creating the Project
To start the project:

1. Launch Visual Studio, and open the New Project dialog box.

2. In Visual C# and the Windows category, select the Windows Forms Application
template.

3. Name the new project WFHost .

4. For the location, specify the same top-level folder that contains the MyControls
project.

5. Click OK to create the project.

You also need to add references to the DLL that contains MyControl1 and other
assemblies.

1. Right-click the project name in Solution Explorer, and select Add Reference.

2. Click the Browse tab, and browse to the folder that contains MyControls.dll. For
this walkthrough, this folder is MyControls\bin\Debug.

3. Select MyControls.dll, and then click OK.

4. Add references to the following assemblies.


PresentationCore

PresentationFramework

System.Xaml

WindowsBase

WindowsFormsIntegration

Implementing the User Interface for the Application


The UI for the Windows Form application contains several controls to interact with the
WPF composite control.

1. Open Form1 in the Windows Form Designer.

2. Enlarge the form to accommodate the controls.

3. In the upper-right corner of the form, add a System.Windows.Forms.Panel control


to hold the WPF composite control.

4. Add the following System.Windows.Forms.GroupBox controls to the form.

Name Text

groupBox1 Background Color

groupBox2 Foreground Color

groupBox3 Font Size

groupBox4 Font Family

groupBox5 Font Style

groupBox6 Font Weight

groupBox7 Data from control

5. Add the following System.Windows.Forms.RadioButton controls to the


System.Windows.Forms.GroupBox controls.

GroupBox Name Text

groupBox1 radioBackgroundOriginal Original

groupBox1 radioBackgroundLightGreen LightGreen


GroupBox Name Text

groupBox1 radioBackgroundLightSalmon LightSalmon

groupBox2 radioForegroundOriginal Original

groupBox2 radioForegroundRed Red

groupBox2 radioForegroundYellow Yellow

groupBox3 radioSizeOriginal Original

groupBox3 radioSizeTen 10

groupBox3 radioSizeTwelve 12

groupBox4 radioFamilyOriginal Original

groupBox4 radioFamilyTimes Times New Roman

groupBox4 radioFamilyWingDings WingDings

groupBox5 radioStyleOriginal Normal

groupBox5 radioStyleItalic Italic

groupBox6 radioWeightOriginal Original

groupBox6 radioWeightBold Bold

6. Add the following System.Windows.Forms.Label controls to the last


System.Windows.Forms.GroupBox. These controls display the data returned by the
WPF composite control.

GroupBox Name Text

groupBox7 lblName Name:

groupBox7 lblAddress Street Address:

groupBox7 lblCity City:

groupBox7 lblState State:

groupBox7 lblZip Zip:

Initializing the Form


You generally implement the hosting code in the form's Load event handler. The
following code shows the Load event handler, a handler for the WPF composite
control's Loaded event, and declarations for several global variables that are used later.

In the Windows Forms Designer, double-click the form to create a Load event handler.
At the top of Form1.cs, add the following using statements.

C#

using System.Windows;
using System.Windows.Forms.Integration;
using System.Windows.Media;

Replace the contents of the existing Form1 class with the following code.

C#

private ElementHost ctrlHost;


private MyControls.MyControl1 wpfAddressCtrl;
System.Windows.FontWeight initFontWeight;
double initFontSize;
System.Windows.FontStyle initFontStyle;
System.Windows.Media.SolidColorBrush initBackBrush;
System.Windows.Media.SolidColorBrush initForeBrush;
System.Windows.Media.FontFamily initFontFamily;

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)


{
ctrlHost = new ElementHost();
ctrlHost.Dock = DockStyle.Fill;
panel1.Controls.Add(ctrlHost);
wpfAddressCtrl = new MyControls.MyControl1();
wpfAddressCtrl.InitializeComponent();
ctrlHost.Child = wpfAddressCtrl;

wpfAddressCtrl.OnButtonClick +=
new MyControls.MyControl1.MyControlEventHandler(
avAddressCtrl_OnButtonClick);
wpfAddressCtrl.Loaded += new RoutedEventHandler(
avAddressCtrl_Loaded);
}

void avAddressCtrl_Loaded(object sender, EventArgs e)


{
initBackBrush = (SolidColorBrush)wpfAddressCtrl.MyControl_Background;
initForeBrush = wpfAddressCtrl.MyControl_Foreground;
initFontFamily = wpfAddressCtrl.MyControl_FontFamily;
initFontSize = wpfAddressCtrl.MyControl_FontSize;
initFontWeight = wpfAddressCtrl.MyControl_FontWeight;
initFontStyle = wpfAddressCtrl.MyControl_FontStyle;
}

The Form1_Load method in the preceding code shows the general procedure for hosting
a WPF control:

1. Create a new ElementHost object.

2. Set the control's Dock property to DockStyle.Fill.

3. Add the ElementHost control to the Panel control's Controls collection.

4. Create an instance of the WPF control.

5. Host the composite control on the form by assigning the control to the
ElementHost control's Child property.

The remaining two lines in the Form1_Load method attach handlers to two control
events:

OnButtonClick is a custom event that is fired by the composite control when the

user clicks the OK or Cancel button. You handle the event to get the user's
response and to collect any data that the user specified.

Loaded is a standard event that is raised by a WPF control when it is fully loaded.
The event is used here because the example needs to initialize several global
variables using properties from the control. At the time of the form's Load event,
the control is not fully loaded and those values are still set to null . You need to
wait until the control's Loaded event occurs before you can access those
properties.

The Loaded event handler is shown in the preceding code. The OnButtonClick handler is
discussed in the next section.

Handling OnButtonClick
The OnButtonClick event occurs when the user clicks the OK or Cancel button.

The event handler checks the event argument's IsOK field to determine which button
was clicked. The lbl data variables correspond to the Label controls that were discussed
earlier. If the user clicks the OK button, the data from the control's TextBox controls is
assigned to the corresponding Label control. If the user clicks Cancel, the Text values are
set to the default strings.
Add the following button click event handler code to the Form1 class.

C#

void avAddressCtrl_OnButtonClick(
object sender,
MyControls.MyControl1.MyControlEventArgs args)
{
if (args.IsOK)
{
lblAddress.Text = "Street Address: " + args.MyStreetAddress;
lblCity.Text = "City: " + args.MyCity;
lblName.Text = "Name: " + args.MyName;
lblState.Text = "State: " + args.MyState;
lblZip.Text = "Zip: " + args.MyZip;
}
else
{
lblAddress.Text = "Street Address: ";
lblCity.Text = "City: ";
lblName.Text = "Name: ";
lblState.Text = "State: ";
lblZip.Text = "Zip: ";
}
}

Build and run the application. Add some text in the WPF composite control and then
click OK. The text appears in the labels. At this point, code has not been added to
handle the radio buttons.

Modifying the Appearance of the Control


The RadioButton controls on the form will enable the user to change the WPF
composite control's foreground and background colors as well as several font
properties. The background color is exposed by the ElementHost object. The remaining
properties are exposed as custom properties of the control.

Double-click each RadioButton control on the form to create CheckedChanged event


handlers. Replace the CheckedChanged event handlers with the following code.

C#

private void radioBackgroundOriginal_CheckedChanged(object sender, EventArgs


e)
{
wpfAddressCtrl.MyControl_Background = initBackBrush;
}

private void radioBackgroundLightGreen_CheckedChanged(object sender,


EventArgs e)
{
wpfAddressCtrl.MyControl_Background = new
SolidColorBrush(Colors.LightGreen);
}

private void radioBackgroundLightSalmon_CheckedChanged(object sender,


EventArgs e)
{
wpfAddressCtrl.MyControl_Background = new
SolidColorBrush(Colors.LightSalmon);
}

private void radioForegroundOriginal_CheckedChanged(object sender, EventArgs


e)
{
wpfAddressCtrl.MyControl_Foreground = initForeBrush;
}

private void radioForegroundRed_CheckedChanged(object sender, EventArgs e)


{
wpfAddressCtrl.MyControl_Foreground = new
System.Windows.Media.SolidColorBrush(Colors.Red);
}

private void radioForegroundYellow_CheckedChanged(object sender, EventArgs


e)
{
wpfAddressCtrl.MyControl_Foreground = new
System.Windows.Media.SolidColorBrush(Colors.Yellow);
}

private void radioFamilyOriginal_CheckedChanged(object sender, EventArgs e)


{
wpfAddressCtrl.MyControl_FontFamily = initFontFamily;
}

private void radioFamilyTimes_CheckedChanged(object sender, EventArgs e)


{
wpfAddressCtrl.MyControl_FontFamily = new
System.Windows.Media.FontFamily("Times New Roman");
}

private void radioFamilyWingDings_CheckedChanged(object sender, EventArgs e)


{
wpfAddressCtrl.MyControl_FontFamily = new
System.Windows.Media.FontFamily("WingDings");
}

private void radioSizeOriginal_CheckedChanged(object sender, EventArgs e)


{
wpfAddressCtrl.MyControl_FontSize = initFontSize;
}

private void radioSizeTen_CheckedChanged(object sender, EventArgs e)


{
wpfAddressCtrl.MyControl_FontSize = 10;
}

private void radioSizeTwelve_CheckedChanged(object sender, EventArgs e)


{
wpfAddressCtrl.MyControl_FontSize = 12;
}

private void radioStyleOriginal_CheckedChanged(object sender, EventArgs e)


{
wpfAddressCtrl.MyControl_FontStyle = initFontStyle;
}

private void radioStyleItalic_CheckedChanged(object sender, EventArgs e)


{
wpfAddressCtrl.MyControl_FontStyle = System.Windows.FontStyles.Italic;
}

private void radioWeightOriginal_CheckedChanged(object sender, EventArgs e)


{
wpfAddressCtrl.MyControl_FontWeight = initFontWeight;
}

private void radioWeightBold_CheckedChanged(object sender, EventArgs e)


{
wpfAddressCtrl.MyControl_FontWeight = FontWeights.Bold;
}

Build and run the application. Click the different radio buttons to see the effect on the
WPF composite control.

See also
ElementHost
WindowsFormsHost
Design XAML in Visual Studio
Walkthrough: Hosting a Windows Forms Composite Control in WPF
Walkthrough: Hosting a 3D WPF Composite Control in Windows Forms
Walkthrough: Mapping Properties Using
the ElementHost Control
Article • 08/18/2022

This walkthrough shows you how to use the PropertyMap property to map Windows
Forms properties to corresponding properties on a hosted WPF element.

Tasks illustrated in this walkthrough include:

Creating the project.

Defining a new property mapping.

Removing a default property mapping.

Extending a default property mapping.

When you are finished, you will be able to map Windows Forms properties to
corresponding WPF properties on a hosted element.

Prerequisites
You need the following components to complete this walkthrough:

Visual Studio 2017

Creating the Project

To create the project


1. Create a Windows Forms App project named PropertyMappingWithElementHost .

2. In Solution Explorer, add references to the following WPF assemblies.

PresentationCore

PresentationFramework

WindowsBase

WindowsFormsIntegration
3. Copy the following code into the top of the Form1 code file.

C#

using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Forms.Integration;

4. Open Form1 in the Windows Forms Designer. Double-click the form to add an
event handler for the Load event.

5. Return to the Windows Forms Designer and add an event handler for the form's
Resize event. For more information, see How to: Create Event Handlers Using the
Designer.

6. Declare an ElementHost field in the Form1 class.

C#

ElementHost elemHost = null;

Defining New Property Mappings


The ElementHost control provides several default property mappings. You add a new
property mapping by calling the Add method on the ElementHost control's
PropertyMap.

To define new property mappings


1. Copy the following code into the definition for the Form1 class.

C#

// The AddMarginMapping method adds a new property mapping


// for the Margin property.
private void AddMarginMapping()
{
elemHost.PropertyMap.Add(
"Margin",
new PropertyTranslator(OnMarginChange));
}

// The OnMarginChange method implements the mapping


// from the Windows Forms Margin property to the
// Windows Presentation Foundation Margin property.
//
// The provided Padding value is used to construct
// a Thickness value for the hosted element's Margin
// property.
private void OnMarginChange(object h, String propertyName, object
value)
{
ElementHost host = h as ElementHost;
Padding p = (Padding)value;
System.Windows.Controls.Button wpfButton =
host.Child as System.Windows.Controls.Button;

Thickness t = new Thickness(p.Left, p.Top, p.Right, p.Bottom );

wpfButton.Margin = t;
}

The AddMarginMapping method adds a new mapping for the Margin property.

The OnMarginChange method translates the Margin property to the WPF Margin
property.

2. Copy the following code into the definition for the Form1 class.

C#

// The AddRegionMapping method assigns a custom


// mapping for the Region property.
private void AddRegionMapping()
{
elemHost.PropertyMap.Add(
"Region",
new PropertyTranslator(OnRegionChange));
}

// The OnRegionChange method assigns an EllipseGeometry to


// the hosted element's Clip property.
private void OnRegionChange(
object h,
String propertyName,
object value)
{
ElementHost host = h as ElementHost;
System.Windows.Controls.Button wpfButton =
host.Child as System.Windows.Controls.Button;

wpfButton.Clip = new EllipseGeometry(new Rect(


0,
0,
wpfButton.ActualWidth,
wpfButton.ActualHeight));
}

// The Form1_Resize method handles the form's Resize event.


// It calls the OnRegionChange method explicitly to
// assign a new clipping geometry to the hosted element.
private void Form1_Resize(object sender, EventArgs e)
{
this.OnRegionChange(elemHost, "Region", null);
}

The AddRegionMapping method adds a new mapping for the Region property.

The OnRegionChange method translates the Region property to the WPF Clip
property.

The Form1_Resize method handles the form's Resize event and sizes the clipping
region to fit the hosted element.

Removing a Default Property Mapping


Remove a default property mapping by calling the Remove method on the ElementHost
control's PropertyMap.

To remove a default property mapping


Copy the following code into the definition for the Form1 class.

C#

// The RemoveCursorMapping method deletes the default


// mapping for the Cursor property.
private void RemoveCursorMapping()
{
elemHost.PropertyMap.Remove("Cursor");
}

The RemoveCursorMapping method deletes the default mapping for the Cursor
property.

Extending a Default Property Mapping


You can use a default property mapping and also extend it with your own mapping.
To extend a default property mapping
Copy the following code into the definition for the Form1 class.

C#

// The ExtendBackColorMapping method adds a property


// translator if a mapping already exists.
private void ExtendBackColorMapping()
{
if (elemHost.PropertyMap["BackColor"] != null)
{
elemHost.PropertyMap["BackColor"] +=
new PropertyTranslator(OnBackColorChange);
}
}

// The OnBackColorChange method assigns a specific image


// to the hosted element's Background property.
private void OnBackColorChange(object h, String propertyName, object
value)
{
ElementHost host = h as ElementHost;
System.Windows.Controls.Button wpfButton =
host.Child as System.Windows.Controls.Button;

ImageBrush b = new ImageBrush(new BitmapImage(


new Uri(@"file:///C:\WINDOWS\Santa Fe Stucco.bmp")));
wpfButton.Background = b;
}

The ExtendBackColorMapping method adds a custom property translator to the


existing BackColor property mapping.

The OnBackColorChange method assigns a specific image to the hosted control's


Background property. The OnBackColorChange method is called after the default
property mapping is applied.

Initialize your property mappings


1. Copy the following code into the definition for the Form1 class.

C#

private void Form1_Load(object sender, EventArgs e)


{
// Create the ElementHost control.
elemHost = new ElementHost();
elemHost.Dock = DockStyle.Fill;
this.Controls.Add(elemHost);

// Create a Windows Presentation Foundation Button element


// and assign it as the ElementHost control's child.
System.Windows.Controls.Button wpfButton = new
System.Windows.Controls.Button();
wpfButton.Content = "Windows Presentation Foundation Button";
elemHost.Child = wpfButton;

// Map the Margin property.


this.AddMarginMapping();

// Remove the mapping for the Cursor property.


this.RemoveCursorMapping();

// Add a mapping for the Region property.


this.AddRegionMapping();

// Add another mapping for the BackColor property.


this.ExtendBackColorMapping();

// Cause the OnMarginChange delegate to be called.


elemHost.Margin = new Padding(23, 23, 23, 23);

// Cause the OnRegionChange delegate to be called.


elemHost.Region = new Region();

// Cause the OnBackColorChange delegate to be called.


elemHost.BackColor = System.Drawing.Color.AliceBlue;
}

The Form1_Load method handles the Load event and performs the following
initialization.

Creates a WPF Button element.

Calls the methods you defined earlier in the walkthrough to set up the
property mappings.

Assigns initial values to the mapped properties.

2. Press F5 to build and run the application.

See also
ElementHost.PropertyMap
WindowsFormsHost.PropertyMap
WindowsFormsHost
Windows Forms and WPF Property Mapping
Design XAML in Visual Studio
Walkthrough: Hosting a WPF Composite Control in Windows Forms
Walkthrough: Mapping Properties Using
the WindowsFormsHost Element
Article • 08/18/2022

This walkthrough shows you how to use the PropertyMap property to map WPF
properties to corresponding properties on a hosted Windows Forms control.

Tasks illustrated in this walkthrough include:

Creating the project.

Defining the application layout.

Defining a new property mapping.

Removing a default property mapping.

Replacing a default property mapping.

Extending a default property mapping.

When you are finished, you will be able to map WPF properties to corresponding
properties on a hosted Windows Forms control.

Prerequisites
You need the following components to complete this walkthrough:

Visual Studio 2017

Create and set up the project


1. Create a WPF App project named PropertyMappingWithWfhSample .

2. In Solution Explorer, add a reference to the WindowsFormsIntegration assembly,


which is named WindowsFormsIntegration.dll.

3. In Solution Explorer, add references to the System.Drawing and


System.Windows.Forms assemblies.

Defining the Application Layout


The WPF-based application uses the WindowsFormsHost element to host a Windows
Forms control.

To define the application layout


1. Open Window1.xaml in the WPF Designer.

2. Replace the existing code with the following code.

XAML

<Window x:Class="PropertyMappingWithWfh.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="PropertyMappingWithWfh" Height="300" Width="300"
Loaded="WindowLoaded">
<DockPanel Name="panel1" LastChildFill="True">
<WindowsFormsHost Name="wfHost" DockPanel.Dock="Left"
SizeChanged="Window1_SizeChanged" FontSize="20" />
</DockPanel>
</Window>

3. Open Window1.xaml.cs in the Code Editor.

4. At the top of the file, import the following namespaces.

C#

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Windows.Forms.Integration;

Defining a New Property Mapping


The WindowsFormsHost element provides several default property mappings. You add a
new property mapping by calling the Add method on the WindowsFormsHost element's
PropertyMap.

To define a new property mapping


Copy the following code into the definition for the Window1 class.

C#
// The AddClipMapping method adds a custom
// mapping for the Clip property.
private void AddClipMapping()
{
wfHost.PropertyMap.Add(
"Clip",
new PropertyTranslator(OnClipChange));
}

// The OnClipChange method assigns an elliptical clipping


// region to the hosted control's Region property.
private void OnClipChange(object h, String propertyName, object value)
{
WindowsFormsHost host = h as WindowsFormsHost;
System.Windows.Forms.CheckBox cb = host.Child as
System.Windows.Forms.CheckBox;

if (cb != null)
{
cb.Region = this.CreateClipRegion();
}
}

// The Window1_SizeChanged method handles the window's


// SizeChanged event. It calls the OnClipChange method explicitly
// to assign a new clipping region to the hosted control.
private void Window1_SizeChanged(object sender, SizeChangedEventArgs e)
{
this.OnClipChange(wfHost, "Clip", null);
}

// The CreateClipRegion method creates a Region from an


// elliptical GraphicsPath.
private Region CreateClipRegion()
{
GraphicsPath path = new GraphicsPath();

path.StartFigure();

path.AddEllipse(new System.Drawing.Rectangle(
0,
0,
(int)wfHost.ActualWidth,
(int)wfHost.ActualHeight ) );

path.CloseFigure();

return( new Region(path) );


}

The AddClipMapping method adds a new mapping for the Clip property.
The OnClipChange method translates the Clip property to the Windows
FormsRegion property.

The Window1_SizeChanged method handles the window's SizeChanged event and


sizes the clipping region to fit the application window.

Removing a Default Property Mapping


Remove a default property mapping by calling the Remove method on the
WindowsFormsHost element's PropertyMap.

To remove a default property mapping


Copy the following code into the definition for the Window1 class.

C#

// The RemoveCursorMapping method deletes the default


// mapping for the Cursor property.
private void RemoveCursorMapping()
{
wfHost.PropertyMap.Remove("Cursor");
}

The RemoveCursorMapping method deletes the default mapping for the Cursor
property.

Replacing a Default Property Mapping


Replace a default property mapping by removing the default mapping and calling the
Add method on the WindowsFormsHost element's PropertyMap.

To replace a default property mapping


Copy the following code into the definition for the Window1 class.

C#

// The ReplaceFlowDirectionMapping method replaces the


// default mapping for the FlowDirection property.
private void ReplaceFlowDirectionMapping()
{
wfHost.PropertyMap.Remove("FlowDirection");
wfHost.PropertyMap.Add(
"FlowDirection",
new PropertyTranslator(OnFlowDirectionChange));
}

// The OnFlowDirectionChange method translates a


// Windows Presentation Foundation FlowDirection value
// to a Windows Forms RightToLeft value and assigns
// the result to the hosted control's RightToLeft property.
private void OnFlowDirectionChange(object h, String propertyName,
object value)
{
WindowsFormsHost host = h as WindowsFormsHost;
System.Windows.FlowDirection fd =
(System.Windows.FlowDirection)value;
System.Windows.Forms.CheckBox cb = host.Child as
System.Windows.Forms.CheckBox;

cb.RightToLeft = (fd == System.Windows.FlowDirection.RightToLeft )


?
RightToLeft.Yes : RightToLeft.No;
}

// The cb_CheckedChanged method handles the hosted control's


// CheckedChanged event. If the Checked property is true,
// the flow direction is set to RightToLeft, otherwise it is
// set to LeftToRight.
private void cb_CheckedChanged(object sender, EventArgs e)
{
System.Windows.Forms.CheckBox cb = sender as
System.Windows.Forms.CheckBox;

wfHost.FlowDirection = ( cb.CheckState == CheckState.Checked ) ?


System.Windows.FlowDirection.RightToLeft :
System.Windows.FlowDirection.LeftToRight;
}

The ReplaceFlowDirectionMapping method replaces the default mapping for the


FlowDirection property.

The OnFlowDirectionChange method translates the FlowDirection property to the


Windows FormsRightToLeft property.

The cb_CheckedChanged method handles the CheckedChanged event on the


CheckBox control. It assigns the FlowDirection property based on the value of the
CheckState property

Extending a Default Property Mapping


You can use a default property mapping and also extend it with your own mapping.

To extend a default property mapping


Copy the following code into the definition for the Window1 class.

C#

// The ExtendBackgroundMapping method adds a property


// translator if a mapping already exists.
private void ExtendBackgroundMapping()
{
if (wfHost.PropertyMap["Background"] != null)
{
wfHost.PropertyMap["Background"] += new
PropertyTranslator(OnBackgroundChange);
}
}

// The OnBackgroundChange method assigns a specific image


// to the hosted control's BackgroundImage property.
private void OnBackgroundChange(object h, String propertyName, object
value)
{
WindowsFormsHost host = h as WindowsFormsHost;
System.Windows.Forms.CheckBox cb = host.Child as
System.Windows.Forms.CheckBox;
ImageBrush b = value as ImageBrush;

if (b != null)
{
cb.BackgroundImage = new
System.Drawing.Bitmap(@"C:\WINDOWS\Santa Fe Stucco.bmp");
}
}

The ExtendBackgroundMapping method adds a custom property translator to the


existing Background property mapping.

The OnBackgroundChange method assigns a specific image to the hosted control's


BackgroundImage property. The OnBackgroundChange method is called after the
default property mapping is applied.

Initializing Your Property Mappings


Set up your property mappings by calling the previously described methods in the
Loaded event handler.
To initialize your property mappings
1. Copy the following code into the definition for the Window1 class.

C#

// The WindowLoaded method handles the Loaded event.


// It enables Windows Forms visual styles, creates
// a Windows Forms checkbox control, and assigns the
// control as the child of the WindowsFormsHost element.
// This method also modifies property mappings on the
// WindowsFormsHost element.
private void WindowLoaded(object sender, RoutedEventArgs e)
{
System.Windows.Forms.Application.EnableVisualStyles();

// Create a Windows Forms checkbox control and assign


// it as the WindowsFormsHost element's child.
System.Windows.Forms.CheckBox cb = new
System.Windows.Forms.CheckBox();
cb.Text = "Windows Forms checkbox";
cb.Dock = DockStyle.Fill;
cb.TextAlign = ContentAlignment.MiddleCenter;
cb.CheckedChanged += new EventHandler(cb_CheckedChanged);
wfHost.Child = cb;

// Replace the default mapping for the FlowDirection property.


this.ReplaceFlowDirectionMapping();

// Remove the mapping for the Cursor property.


this.RemoveCursorMapping();

// Add the mapping for the Clip property.


this.AddClipMapping();

// Add another mapping for the Background property.


this.ExtendBackgroundMapping();

// Cause the OnFlowDirectionChange delegate to be called.


wfHost.FlowDirection = System.Windows.FlowDirection.LeftToRight;

// Cause the OnClipChange delegate to be called.


wfHost.Clip = new RectangleGeometry();

// Cause the OnBackgroundChange delegate to be called.


wfHost.Background = new ImageBrush();
}

The WindowLoaded method handles the Loaded event and performs the following
initialization.

Creates a Windows FormsCheckBox control.


Calls the methods you defined earlier in the walkthrough to set up the
property mappings.

Assigns initial values to the mapped properties.

2. Press F5 to build and run the application. Click the check box to see the effect of
the FlowDirection mapping. When you click the check box, the layout reverses its
left-right orientation.

See also
WindowsFormsHost.PropertyMap
ElementHost.PropertyMap
WindowsFormsHost
Windows Forms and WPF Property Mapping
Design XAML in Visual Studio
Walkthrough: Hosting a Windows Forms Control in WPF
Walkthrough: Localizing a Hybrid
Application
Article • 08/18/2022

This walkthrough shows you how to localize WPF elements in a Windows Forms-based
hybrid application.

Tasks illustrated in this walkthrough include:

Creating the Windows Forms host project.

Adding localizable content.

Enabling localization.

Assigning resource identifiers.

Using the LocBaml tool to produce a satellite assembly.

For a complete code listing of the tasks illustrated in this walkthrough, see Localizing a
Hybrid Application Sample .

When you are finished, you will have a localized hybrid application.

Prerequisites
You need the following components to complete this walkthrough:

Visual Studio 2017

Creating the Windows Forms Host Project


The first step is to create the Windows Forms application project and add a WPF
element with content that you will localize.

To create the host project


1. Create a WPF App project named LocalizingWpfInWf . (File > New > Project >
Visual C# or Visual Basic > Classic Desktop > WPF Application).

2. Add a WPFUserControl element called SimpleControl to the project.


3. Use the ElementHost control to place a SimpleControl element on the form. For
more information, see Walkthrough: Hosting a 3D WPF Composite Control in
Windows Forms.

Adding Localizable Content


Next, you will add a Windows Forms label control and set the WPF element's content to
a localizable string.

To add localizable content


1. In Solution Explorer, double-click SimpleControl.xaml to open it in the WPF
Designer.

2. Set the content of the Button control using the following code.

XAML

<UserControl x:Class="LocalizingWpfInWf.SimpleControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>

<Canvas>
<Button Content="Hello"/>
</Canvas>
</UserControl>

3. In Solution Explorer, double-click Form1 to open it in the Windows Forms


Designer.

4. Open the Toolbox and double-click Label to add a label control to the form. Set
the value of its Text property to "Hello" .

5. Press F5 to build and run the application.

Both the SimpleControl element and the label control display the text "Hello".

Enabling Localization
The Windows Forms Designer provides settings for enabling localization in a satellite
assembly.
To enable localization
1. In Solution Explorer, double-click Form1.cs to open it in the Windows Forms
Designer.

2. In the Properties window, set the value of the form's Localizable property to true .

3. In the Properties window, set the value of the Language property to Spanish
(Spain).

4. In the Windows Forms Designer, select the label control.

5. In the Properties window, set the value of the Text property to "Hola" .

A new resource file named Form1.es-ES.resx is added to the project.

6. In Solution Explorer, right-click Form1.cs and click View Code to open it in the
Code Editor.

7. Copy the following code into the Form1 constructor, preceding the call to
InitializeComponent .

C#

public Form1()
{
System.Threading.Thread.CurrentThread.CurrentUICulture = new
System.Globalization.CultureInfo("es-ES");

InitializeComponent();
}

8. In Solution Explorer, right-click LocalizingWpfInWf and click Unload Project.

The project name is labeled (unavailable).

9. Right-click LocalizingWpfInWf, and click Edit LocalizingWpfInWf.csproj.

The project file opens in the Code Editor.

10. Copy the following line into the first PropertyGroup in the project file.

XML

<UICulture>en-US</UICulture>

11. Save the project file and close it.


12. In Solution Explorer, right-click LocalizingWpfInWf and click Reload Project.

Assigning Resource Identifiers


You can map your localizable content to resource assemblies by using resource
identifiers. The MSBuild.exe application automatically assigns resource identifiers when
you specify the updateuid option.

To assign resource identifiers


1. From the Start Menu, open the Developer Command Prompt for Visual Studio.

2. Use the following command to assign resource identifiers to your localizable


content.

Console

msbuild -t:updateuid LocalizingWpfInWf.csproj

3. In Solution Explorer, double-click SimpleControl.xaml to open it in the Code


Editor. You will see that the msbuild command has added the Uid attribute to all
the elements. This facilitates localization through the assignment of resource
identifiers.

XAML

<UserControl x:Uid="UserControl_1"
x:Class="LocalizingWpfInWf.SimpleControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>

<Canvas x:Uid="Canvas_1">
<Button x:Uid="Button_1" Content="Hello"/>
</Canvas>
</UserControl>

4. Press F6 to build the solution.

Using LocBaml to Produce a Satellite Assembly


Your localized content is stored in a resource-only satellite assembly. Use the command-
line tool LocBaml.exe to produce a localized assembly for your WPF content.
To produce a satellite assembly
1. Copy LocBaml.exe to your project's obj\Debug folder. For more information, see
Localize an Application.

2. In the Command Prompt window, use the following command to extract resource
strings into a temporary file.

Console

LocBaml /parse LocalizingWpfInWf.g.en-US.resources /out:temp.csv

3. Open the temp.csv file with Visual Studio or another text editor. Replace the string
"Hello" with its Spanish translation, "Hola" .

4. Save the temp.csv file.

5. Use the following command to generate the localized resource file.

Console

LocBaml /generate /trans:temp.csv LocalizingWpfInWf.g.en-US.resources


/out:. /cul:es-ES

The LocalizingWpfInWf.g.es-ES.resources file is created in the obj\Debug folder.

6. Use the following command to build the localized satellite assembly.

Console

Al.exe /out:LocalizingWpfInWf.resources.dll /culture:es-ES


/embed:LocalizingWpfInWf.Form1.es-ES.resources
/embed:LocalizingWpfInWf.g.es-ES.resources

The LocalizingWpfInWf.resources.dll file is created in the obj\Debug folder.

7. Copy the LocalizingWpfInWf.resources.dll file to the project's bin\Debug\es-ES


folder. Replace the existing file.

8. Run LocalizingWpfInWf.exe, which is located in your project's bin\Debug folder. Do


not rebuild the application or the satellite assembly will be overwritten.

The application shows the localized strings instead of the English strings.
See also
ElementHost
WindowsFormsHost
Localize an Application
Walkthrough: Localizing Windows Forms
Design XAML in Visual Studio
WPF and Win32 Interoperation
Article • 08/18/2022

This topic provides an overview of how to interoperate WPF and Win32 code. Windows
Presentation Foundation (WPF) provides a rich environment for creating applications.
However, when you have a substantial investment in Win32 code, it might be more
effective to reuse some of that code.

WPF and Win32 Interoperation Basics


There are two basic techniques for interoperation between WPF and Win32 code.

Host WPF content in a Win32 window. With this technique, you can use the
advanced graphics capabilities of WPF within the framework of a standard Win32
window and application.

Host a Win32 window in WPF content. With this technique, you can use an existing
custom Win32 control in the context of other WPF content, and pass data across
the boundaries.

Each of these techniques is conceptually introduced in this topic. For a more code-
oriented illustration of hosting WPF in Win32, see Walkthrough: Hosting WPF Content in
Win32. For a more code-oriented illustration of hosting Win32 in WPF, see Walkthrough:
Hosting a Win32 Control in WPF.

WPF Interoperation Projects


WPF APIs are managed code, but most existing Win32 programs are written in
unmanaged C++. You cannot call WPF APIs from a true unmanaged program. However,
by using the /clr option with the Microsoft Visual C++ compiler, you can create a
mixed managed-unmanaged program where you can seamlessly mix managed and
unmanaged API calls.

One project-level complication is that you cannot compile Extensible Application


Markup Language (XAML) files into a C++ project. There are several project division
techniques to compensate for this.

Create a C# DLL that contains all your XAML pages as a compiled assembly, and
then have your C++ executable include that DLL as a reference.
Create a C# executable for the WPF content, and have it reference a C++ DLL that
contains the Win32 content.

Use Load to load any XAML at run time, instead of compiling your XAML.

Do not use WPF in code, building up the element tree from Application.

Use whatever approach works best for you.

7 Note

If you have not used C++/CLI before, you might notice some "new" keywords such
as gcnew and nullptr in the interoperation code examples. These keywords
supersede the older double-underscore syntax ( __gc ) and provide a more natural
syntax for managed code in C++. To learn more about the C++/CLI managed
features, see Component Extensions for Runtime Platforms.

How WPF Uses Hwnds


To make the most of WPF "HWND interop", you need to understand how WPF uses
HWNDs. For any HWND, you cannot mix WPF rendering with DirectX rendering or GDI /
GDI+ rendering. This has a number of implications. Primarily, in order to mix these
rendering models at all, you must create an interoperation solution, and use designated
segments of interoperation for each rendering model that you choose to use. Also, the
rendering behavior creates an "airspace" restriction for what your interoperation
solution can accomplish. The "airspace" concept is explained in greater detail in the
topic Technology Regions Overview.

All WPF elements on the screen are ultimately backed by a HWND. When you create a
WPF Window, WPF creates a top-level HWND, and uses an HwndSource to put the
Window and its WPF content inside the HWND. The rest of your WPF content in the
application shares that singular HWND. An exception is menus, combo box drop downs,
and other pop-ups. These elements create their own top-level window, which is why a
WPF menu can potentially go past the edge of the window HWND that contains it.
When you use HwndHost to put an HWND inside WPF, WPF informs Win32 how to
position the new child HWND relative to the WPF Window HWND.

A related concept to HWND is transparency within and between each HWND. This is
also discussed in the topic Technology Regions Overview.
Hosting WPF Content in a Microsoft Win32
Window
The key to hosting a WPF on a Win32 window is the HwndSource class. This class wraps
the WPF content in a Win32 window, so that the WPF content can be incorporated into
your WPF in a single application.

1. Implement your WPF content (the content root element) as a managed class.
Typically, the class inherits from one of the classes that can contain multiple child
elements and/or used as a root element, such as DockPanel or Page. In subsequent
steps, this class is referred to as the WPF content class, and instances of the class
are referred to as WPF content objects.

2. Implement a Windows application with C++/CLI. If you are starting with an existing
unmanaged C++ application, you can usually enable it to call managed code by
changing your project settings to include the /clr compiler flag (the full scope of
what might be necessary to support /clr compilation is not described in this
topic).

3. Set the threading model to Single Threaded Apartment (STA). WPF uses this
threading model.

4. Handle the WM_CREATE notification in your window procedure.

5. Within the handler (or a function that the handler calls), do the following:

a. Create a new HwndSource object with the parent window HWND as its parent
parameter.

b. Create an instance of your WPF content class.

c. Assign a reference to the WPF content object to the HwndSource object


RootVisual property.

d. The HwndSource object Handle property contains the window handle (HWND).
To get an HWND that you can use in the unmanaged part of your application,
cast Handle.ToPointer() to an HWND.

6. Implement a managed class that contains a static field that holds a reference to
your WPF content object. This class allows you to get a reference to the WPF
content object from your Win32 code, but more importantly it prevents your
HwndSource from being inadvertently garbage collected.
7. Receive notifications from the WPF content object by attaching a handler to one or
more of the WPF content object events.

8. Communicate with the WPF content object by using the reference that you stored
in the static field to set properties, call methods, etc.

7 Note

You can do some or all of the WPF content class definition for Step One in XAML
using the default partial class of the content class, if you produce a separate
assembly and then reference it. Although you typically include an Application
object as part of compiling the XAML into an assembly, you do not end up using
that Application as part of the interoperation, you just use one or more of the root
classes for XAML files referred to by the application and reference their partial
classes. The remainder of the procedure is essentially similar to that outlined above.

Each of these steps is illustrated through code in the topic Walkthrough: Hosting
WPF Content in Win32.

Hosting a Microsoft Win32 Window in WPF


The key to hosting a Win32 window within other WPF content is the HwndHost class.
This class wraps the window in a WPF element which can be added to a WPF element
tree. HwndHost also supports APIs that allow you to do such tasks as process messages
for the hosted window. The basic procedure is:

1. Create an element tree for a WPF application (can be through code or markup).
Find an appropriate and permissible point in the element tree where the
HwndHost implementation can be added as a child element. In the remainder of
these steps, this element is referred to as the reserving element.

2. Derive from HwndHost to create an object that holds your Win32 content.

3. In that host class, override the HwndHost method BuildWindowCore. Return the
HWND of the hosted window. You might want to wrap the actual control(s) as a
child window of the returned window; wrapping the controls in a host window
provides a simple way for your WPF content to receive notifications from the
controls. This technique helps correct for some Win32 issues regarding message
handling at the hosted control boundary.

4. Override the HwndHost methods DestroyWindowCore and WndProc. The intention


here is to process cleanup and remove references to the hosted content,
particularly if you created references to unmanaged objects.

5. In your code-behind file, create an instance of the control hosting class and make
it a child of the reserving element. Typically you would use an event handler such
as Loaded, or use the partial class constructor. But you could also add the
interoperation content through a runtime behavior.

6. Process selected window messages, such as control notifications. There are two
approaches. Both provide identical access to the message stream, so your choice is
largely a matter of programming convenience.

Implement message processing for all messages (not just shutdown


messages) in your override of the HwndHost method WndProc.

Have the hosting WPF element process the messages by handling the
MessageHook event. This event is raised for every message that is sent to the
main window procedure of the hosted window.

You cannot process messages from windows that are out of process using
WndProc.

7. Communicate with the hosted window by using platform invoke to call the
unmanaged SendMessage function.

Following these steps creates an application that works with mouse input. You can add
tabbing support for your hosted window by implementing the IKeyboardInputSink
interface.

Each of these steps is illustrated through code in the topic Walkthrough: Hosting a
Win32 Control in WPF.

Hwnds Inside WPF


You can think of HwndHost as a special control. (Technically, HwndHost is a
FrameworkElement derived class, not a Control derived class, but it can be considered a
control for purposes of interoperation.) HwndHost abstracts the underlying Win32
nature of the hosted content such that the remainder of WPF considers the hosted
content to be another control-like object, which should render and process input.
HwndHost generally behaves like any other WPF FrameworkElement, although there are
some important differences around output (drawing and graphics) and input (mouse
and keyboard) based on limitations of what the underlying HWNDs can support.

Notable Differences in Output Behavior


FrameworkElement, which is the HwndHost base class, has quite a few properties
that imply changes to the UI. These include properties such as
FrameworkElement.FlowDirection, which changes the layout of elements within
that element as a parent. However, most of these properties are not mapped to
possible Win32 equivalents, even if such equivalents might exist. Too many of
these properties and their meanings are too rendering-technology specific for
mappings to be practical. Therefore, setting properties such as FlowDirection on
HwndHost has no effect.

HwndHost cannot be rotated, scaled, skewed, or otherwise affected by a


Transform.

HwndHost does not support the Opacity property (alpha blending). If content
inside the HwndHost performs System.Drawing operations that include alpha
information, that is itself not a violation, but the HwndHost as a whole only
supports Opacity = 1.0 (100%).

HwndHost will appear on top of other WPF elements in the same top-level
window. However, a ToolTip or ContextMenu generated menu is a separate top-
level window, and so will behave correctly with HwndHost.

HwndHost does not respect the clipping region of its parent UIElement. This is
potentially an issue if you attempt to put an HwndHost class inside a scrolling
region or Canvas.

Notable Differences in Input Behavior


In general, while input devices are scoped within the HwndHost hosted Win32
region, input events go directly to Win32.

While the mouse is over the HwndHost, your application does not receive WPF
mouse events, and the value of the WPF property IsMouseOver will be false .

While the HwndHost has keyboard focus, your application will not receive WPF
keyboard events and the value of the WPF property IsKeyboardFocusWithin will be
false .

When focus is within the HwndHost and changes to another control inside the
HwndHost, your application will not receive the WPF events GotFocus or
LostFocus.

Related stylus properties and events are analogous, and do not report information
while the stylus is over HwndHost.
Tabbing, Mnemonics, and Accelerators
The IKeyboardInputSink and IKeyboardInputSite interfaces allow you to create a
seamless keyboard experience for mixed WPF and Win32 applications:

Tabbing between Win32 and WPF components

Mnemonics and accelerators that work both when focus is within a Win32
component and when it is within a WPF component.

The HwndHost and HwndSource classes both provide implementations of


IKeyboardInputSink, but they may not handle all the input messages that you want for
more advanced scenarios. Override the appropriate methods to get the keyboard
behavior you want.

The interfaces only provide support for what happens on the transition between the
WPF and Win32 regions. Within the Win32 region, tabbing behavior is entirely
controlled by the Win32 implemented logic for tabbing, if any.

See also
HwndHost
HwndSource
System.Windows.Interop
Walkthrough: Hosting a Win32 Control in WPF
Walkthrough: Hosting WPF Content in Win32
Technology Regions Overview
Article • 02/06/2023

If multiple presentation technologies are used in an application, such as WPF, Win32, or


DirectX, they must share the rendering areas within a common top-level window. This
topic describes issues that might influence the presentation and input for your WPF
interoperation application.

Regions
Within a top-level window, you can conceptualize that each HWND that comprises one
of the technologies of an interoperation application has its own region (also called
"airspace"). Each pixel within the window belongs to exactly one HWND, which
constitutes the region of that HWND. (Strictly speaking, there is more than one WPF
region if there is more than one WPF HWND, but for purposes of this discussion, you
can assume there is only one). The region implies that all layers or other windows that
attempt to render above that pixel during application lifetime must be part of the same
render-level technology. Attempting to render WPF pixels over Win32 leads to
undesirable results, and is disallowed as much as possible through the interoperation
APIs.

Region Examples
The following illustration shows an application that mixes Win32, DirectX, and WPF. Each
technology uses its own separate, non-overlapping set of pixels, and there are no region
issues.

Suppose that this application uses the mouse pointer position to create an animation
that attempts to render over any of these three regions. No matter which technology
was responsible for the animation itself, that technology would violate the region of the
other two. The following illustration shows an attempt to render a WPF circle over a
Win32 region.
Another violation is if you try to use transparency/alpha blending between different
technologies. In the following illustration, the WPF box violates the Win32 and DirectX
regions. Because pixels in that WPF box are semi-transparent, they would have to be
owned jointly by both DirectX and WPF, which is not possible. So this is another
violation and cannot be built.

The previous three examples used rectangular regions, but different shapes are possible.
For example, a region can have a hole. The following illustration shows a Win32 region
with a rectangular hole this is the size of the WPF and DirectX regions combined.

Regions can also be completely nonrectangular, or any shape describable by a Win32


HRGN (region).

Transparency and Top-Level Windows


The window manager in Windows only really processes Win32 HWNDs. Therefore, every
WPF Window is an HWND. The Window HWND must abide by the general rules for any
HWND. Within that HWND, WPF code can do whatever the overall WPF APIs support.
But for interactions with other HWNDs on the desktop, WPF must abide by Win32
processing and rendering rules. WPF supports non-rectangular windows by using Win32
APIs—HRGNs for non-rectangular windows, and layered windows for a per-pixel alpha.

Constant alpha and color keys are not supported. Win32 layered window capabilities
vary by platform.

Layered windows can make the entire window translucent (semi-transparent) by


specifying an alpha value to apply to every pixel in the window. (Win32 in fact supports
per-pixel alpha, but this is very difficult to use in practical programs because in this
mode you would need to draw any child HWND yourself, including dialogs and
dropdowns).

WPF supports HRGNs; however, there are no managed APIs for this functionality. You
can use platform invoke and HwndSource to call the relevant Win32 APIs. For more
information, see Calling Native Functions from Managed Code.

WPF layered windows have different capabilities on different operating systems. This is
because WPF uses DirectX to render, and layered windows were primarily designed for
GDI rendering, not DirectX rendering.

WPF supports hardware accelerated layered windows.

WPF does not support transparency color keys, because WPF cannot guarantee to
render the exact color you requested, particularly when rendering is hardware-
accelerated.

See also
WPF and Win32 Interoperation
Walkthrough: Hosting a WPF Clock in Win32
Hosting Win32 Content in WPF
Sharing Message Loops Between Win32
and WPF
Article • 02/06/2023

This topic describes how to implement a message loop for interoperation with Windows
Presentation Foundation (WPF), either by using existing message loop exposure in
Dispatcher or by creating a separate message loop on the Win32 side of your
interoperation code.

ComponentDispatcher and the Message Loop


A normal scenario for interoperation and keyboard event support is to implement
IKeyboardInputSink, or to subclass from classes that already implement
IKeyboardInputSink, such as HwndSource or HwndHost. However, keyboard sink
support does not address all possible message loop needs you might have when
sending and receiving messages across your interoperation boundaries. To help
formalize an application message loop architecture, Windows Presentation Foundation
(WPF) provides the ComponentDispatcher class, which defines a simple protocol for a
message loop to follow.

ComponentDispatcher is a static class that exposes several members. The scope of each
method is implicitly tied to the calling thread. A message loop must call some of those
APIs at critical times (as defined in the next section).

ComponentDispatcher provides events that other components (such as the keyboard


sink) can listen for. The Dispatcher class calls all the appropriate ComponentDispatcher
methods in an appropriate sequence. If you are implementing your own message loop,
your code is responsible for calling ComponentDispatcher methods in a similar fashion.

Calling ComponentDispatcher methods on a thread will only invoke event handlers that
were registered on that thread.

Writing Message Loops


The following is a checklist of ComponentDispatcher members you will use if you write
your own message loop:

PushModal: your message loop should call this to indicate that the thread is
modal.
PopModal:your message loop should call this to indicate that the thread has
reverted to nonmodal.

RaiseIdle: your message loop should call this to indicate that


ComponentDispatcher should raise the ThreadIdle event. ComponentDispatcher
will not raise ThreadIdle if IsThreadModal is true , but message loops may choose
to call RaiseIdle even if ComponentDispatcher cannot respond to it while in modal
state.

RaiseThreadMessage: your message loop should call this to indicate that a new
message is available. The return value indicates whether a listener to a
ComponentDispatcher event handled the message. If RaiseThreadMessage returns
true (handled), the dispatcher should do nothing further with the message. If the

return value is false , the dispatcher is expected to call the Win32 function
TranslateMessage , then call DispatchMessage .

Using ComponentDispatcher and Existing


Message Handling
The following is a checklist of ComponentDispatcher members you will use if you rely on
the inherent WPF message loop.

IsThreadModal: returns whether the application has gone modal (e.g., a modal
message loop has been pushed). ComponentDispatcher can track this state
because the class maintains a count of PushModal and PopModal calls from the
message loop.

ThreadFilterMessage and ThreadPreprocessMessage events follow the standard


rules for delegate invocations. Delegates are invoked in an unspecified order, and
all delegates are invoked even if the first one marks the message as handled.

ThreadIdle: indicates an appropriate and efficient time to do idle processing (there


are no other pending messages for the thread). ThreadIdle will not be raised if the
thread is modal.

ThreadFilterMessage: raised for all messages that the message pump processes.

ThreadPreprocessMessage: raised for all messages that were not handled during
ThreadFilterMessage.

A message is considered handled if after the ThreadFilterMessage event or


ThreadPreprocessMessage event, the handled parameter passed by reference in event
data is true . Event handlers should ignore the message if handled is true , because that
means the different handler handled the message first. Event handlers to both events
may modify the message. The dispatcher should dispatch the modified message and not
the original unchanged message. ThreadPreprocessMessage is delivered to all listeners,
but the architectural intention is that only the top-level window containing the HWND
at which the messages targeted should invoke code in response to the message.

How HwndSource Treats ComponentDispatcher


Events
If the HwndSource is a top-level window (no parent HWND), it will register with
ComponentDispatcher. If ThreadPreprocessMessage is raised, and if the message is
intended for the HwndSource or child windows, HwndSource calls its
IKeyboardInputSink.TranslateAccelerator, TranslateChar, OnMnemonic keyboard sink
sequence.

If the HwndSource is not a top-level window (has a parent HWND), there will be no
handling. Only the top level window is expected to do the handling, and there is
expected to be a top level window with keyboard sink support as part of any
interoperation scenario.

If WndProc on an HwndSource is called without an appropriate keyboard sink method


being called first, your application will receive the higher level keyboard events such as
KeyDown. However, no keyboard sink methods will be called, which circumvents
desirable keyboard input model features such as access key support. This might happen
because the message loop did not properly notify the relevant thread on the
ComponentDispatcher, or because the parent HWND did not invoke the proper
keyboard sink responses.

A message that goes to the keyboard sink might not be sent to the HWND if you added
hooks for that message by using the AddHook method. The message might have been
handled at the message pump level directly and not submitted to the DispatchMessage
function.

See also
ComponentDispatcher
IKeyboardInputSink
WPF and Win32 Interoperation
Threading Model
Input Overview
Hosting Win32 Content in WPF
Article • 07/27/2022

Prerequisites
See WPF and Win32 Interoperation.

A Walkthrough of Win32 Inside Windows


Presentation Framework (HwndHost)
To reuse Win32 content inside WPF applications, use HwndHost, which is a control that
makes HWNDs look like WPF content. Like HwndSource, HwndHost is straightforward to
use: derive from HwndHost and implement BuildWindowCore and DestroyWindowCore
methods, then instantiate your HwndHost derived class and place it inside your WPF
application.

If your Win32 logic is already packaged as a control, then your BuildWindowCore


implementation is little more than a call to CreateWindow . For example, to create a
Win32 LISTBOX control in C++:

C++

virtual HandleRef BuildWindowCore(HandleRef hwndParent) override {


HWND handle = CreateWindowEx(0, L"LISTBOX",
L"this is a Win32 listbox",
WS_CHILD | WS_VISIBLE | LBS_NOTIFY
| WS_VSCROLL | WS_BORDER,
0, 0, // x, y
30, 70, // height, width
(HWND) hwndParent.Handle.ToPointer(), // parent hwnd
0, // hmenu
0, // hinstance
0); // lparam

return HandleRef(this, IntPtr(handle));


}

virtual void DestroyWindowCore(HandleRef hwnd) override {


// HwndHost will dispose the hwnd for us
}

But suppose the Win32 code is not quite so self-contained? If so, you can create a
Win32 dialog box and embed its contents into a larger WPF application. The sample
shows this in Visual Studio and C++, although it is also possible to do this in a different
language or at the command line.

Start with a simple dialog, which is compiled into a C++ DLL project.

Next, introduce the dialog into the larger WPF application:

Compile the DLL as managed ( /clr )

Turn the dialog into a control

Define the derived class of HwndHost with BuildWindowCore and


DestroyWindowCore methods

Override TranslateAccelerator method to handle dialog keys

Override TabInto method to support tabbing

Override OnMnemonic method to support mnemonics

Instantiate the HwndHost subclass and put it under the right WPF element

Turn the Dialog into a Control


You can turn a dialog box into a child HWND using the WS_CHILD and DS_CONTROL
styles. Go into the resource file (.rc) where the dialog is defined, and find the beginning
of the definition of the dialog:

text

IDD_DIALOG1 DIALOGEX 0, 0, 303, 121


STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION |
WS_SYSMENU

Change the second line to:

text

STYLE DS_SETFONT | WS_CHILD | WS_BORDER | DS_CONTROL

This action does not fully package it into a self-contained control; you still need to call
IsDialogMessage() so Win32 can process certain messages, but the control change does

provide a straightforward way of putting those controls inside another HWND.


Subclass HwndHost
Import the following namespaces:

C++

namespace ManagedCpp
{
using namespace System;
using namespace System::Windows;
using namespace System::Windows::Interop;
using namespace System::Windows::Input;
using namespace System::Windows::Media;
using namespace System::Runtime::InteropServices;

Then create a derived class of HwndHost and override the BuildWindowCore and
DestroyWindowCore methods:

C++

public ref class MyHwndHost : public HwndHost, IKeyboardInputSink {


private:
HWND dialog;

protected:
virtual HandleRef BuildWindowCore(HandleRef hwndParent) override {
InitializeGlobals();
dialog = CreateDialog(hInstance,
MAKEINTRESOURCE(IDD_DIALOG1),
(HWND) hwndParent.Handle.ToPointer(),
(DLGPROC) About);
return HandleRef(this, IntPtr(dialog));
}

virtual void DestroyWindowCore(HandleRef hwnd) override {


// hwnd will be disposed for us
}

Here you use the CreateDialog to create the dialog box that is really a control. Since this
is one of the first methods called inside the DLL, you should also do some standard
Win32 initialization by calling a function you will define later, called
InitializeGlobals() :

C++

bool initialized = false;


void InitializeGlobals() {
if (initialized) return;
initialized = true;

// TODO: Place code here.


MSG msg;
HACCEL hAccelTable;

// Initialize global strings


LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_TYPICALWIN32DIALOG, szWindowClass,
MAX_LOADSTRING);
MyRegisterClass(hInstance);

Override TranslateAccelerator Method to Handle Dialog


Keys
If you ran this sample now, you would get a dialog control that displays, but it would
ignore all of the keyboard processing that makes a dialog box a functional dialog box.
You should now override the TranslateAccelerator implementation (which comes from
IKeyboardInputSink , an interface that HwndHost implements). This method gets called

when the application receives WM_KEYDOWN and WM_SYSKEYDOWN.

C++

#undef TranslateAccelerator
virtual bool TranslateAccelerator(System::Windows::Interop::MSG%
msg,
ModifierKeys modifiers) override
{
::MSG m = ConvertMessage(msg);

// Win32's IsDialogMessage() will handle most of our tabbing,


but doesn't know
// what to do when it reaches the last tab stop
if (m.message == WM_KEYDOWN && m.wParam == VK_TAB) {
HWND firstTabStop = GetDlgItem(dialog, IDC_EDIT1);
HWND lastTabStop = GetDlgItem(dialog, IDCANCEL);
TraversalRequest^ request = nullptr;

if (GetKeyState(VK_SHIFT) && GetFocus() == firstTabStop) {


// this code should work, but there’s a bug with interop
shift-tab in current builds
request = gcnew
TraversalRequest(FocusNavigationDirection::Last);
}
else if (!GetKeyState(VK_SHIFT) && GetFocus() ==
lastTabStop) {
request = gcnew
TraversalRequest(FocusNavigationDirection::Next);
}
if (request != nullptr)
return ((IKeyboardInputSink^) this)->KeyboardInputSite-
>OnNoMoreTabStops(request);

// Only call IsDialogMessage for keys it will do something with.


if (msg.message == WM_SYSKEYDOWN || msg.message == WM_KEYDOWN) {
switch (m.wParam) {
case VK_TAB:
case VK_LEFT:
case VK_UP:
case VK_RIGHT:
case VK_DOWN:
case VK_EXECUTE:
case VK_RETURN:
case VK_ESCAPE:
case VK_CANCEL:
IsDialogMessage(dialog, &m);
// IsDialogMessage should be called
ProcessDialogMessage --
// it processes messages without ever really telling
you
// if it handled a specific message or not
return true;
}
}

return false; // not a key we handled


}

This is a lot of code in one piece, so it could use some more detailed explanations. First,
the code using C++ and C++ macros; you need to be aware that there is already a
macro named TranslateAccelerator , which is defined in winuser.h:

C++

#define TranslateAccelerator TranslateAcceleratorW

So make sure to define a TranslateAccelerator method and not a


TranslateAcceleratorW method.

Similarly, there is both the unmanaged winuser.h MSG and the managed
Microsoft::Win32::MSG struct. You can disambiguate between the two using the C++ ::

operator.

C++
virtual bool TranslateAccelerator(System::Windows::Interop::MSG% msg,
ModifierKeys modifiers) override
{
::MSG m = ConvertMessage(msg);
}

Both MSGs have the same data, but sometimes it is easier to work with the unmanaged
definition, so in this sample you can define the obvious conversion routine:

C++

::MSG ConvertMessage(System::Windows::Interop::MSG% msg) {


::MSG m;
m.hwnd = (HWND) msg.hwnd.ToPointer();
m.lParam = (LPARAM) msg.lParam.ToPointer();
m.message = msg.message;
m.wParam = (WPARAM) msg.wParam.ToPointer();

m.time = msg.time;

POINT pt;
pt.x = msg.pt_x;
pt.y = msg.pt_y;
m.pt = pt;

return m;
}

Back to TranslateAccelerator . The basic principle is to call the Win32 function


IsDialogMessage to do as much work as possible, but IsDialogMessage does not have

access to anything outside the dialog. As a user tab around the dialog, when tabbing
runs past the last control in our dialog, you need to set focus to the WPF portion by
calling IKeyboardInputSite::OnNoMoreStops .

C++

// Win32's IsDialogMessage() will handle most of the tabbing, but doesn't


know
// what to do when it reaches the last tab stop
if (m.message == WM_KEYDOWN && m.wParam == VK_TAB) {
HWND firstTabStop = GetDlgItem(dialog, IDC_EDIT1);
HWND lastTabStop = GetDlgItem(dialog, IDCANCEL);
TraversalRequest^ request = nullptr;

if (GetKeyState(VK_SHIFT) && GetFocus() == firstTabStop) {


request = gcnew TraversalRequest(FocusNavigationDirection::Last);
}
else if (!GetKeyState(VK_SHIFT) && GetFocus() == lastTabStop) { {
request = gcnew TraversalRequest(FocusNavigationDirection::Next);
}

if (request != nullptr)
return ((IKeyboardInputSink^) this)->KeyboardInputSite-
>OnNoMoreTabStops(request);
}

Finally, call IsDialogMessage . But one of the responsibilities of a TranslateAccelerator


method is telling WPF whether you handled the keystroke or not. If you did not handle
it, the input event can tunnel and bubble through the rest of the application. Here, you
will expose a quirk of keyboard messange handling and the nature of the input
architecture in Win32. Unfortunately, IsDialogMessage does not return in any way
whether it handles a particular keystroke. Even worse, it will call DispatchMessage() on
keystrokes it should not handle! So you will have to reverse-engineer IsDialogMessage ,
and only call it for the keys you know it will handle:

C++

// Only call IsDialogMessage for keys it will do something with.


if (msg.message == WM_SYSKEYDOWN || msg.message == WM_KEYDOWN) {
switch (m.wParam) {
case VK_TAB:
case VK_LEFT:
case VK_UP:
case VK_RIGHT:
case VK_DOWN:
case VK_EXECUTE:
case VK_RETURN:
case VK_ESCAPE:
case VK_CANCEL:
IsDialogMessage(dialog, &m);
// IsDialogMessage should be called ProcessDialogMessage --
// it processes messages without ever really telling you
// if it handled a specific message or not
return true;
}

Override TabInto Method to Support Tabbing


Now that you have implemented TranslateAccelerator , a user can tab around inside
the dialog box and tab out of it into the greater WPF application. But a user cannot tab
back into the dialog box. To solve that, you override TabInto :

C++

public:
virtual bool TabInto(TraversalRequest^ request) override {
if (request->FocusNavigationDirection ==
FocusNavigationDirection::Last) {
HWND lastTabStop = GetDlgItem(dialog, IDCANCEL);
SetFocus(lastTabStop);
}
else {
HWND firstTabStop = GetDlgItem(dialog, IDC_EDIT1);
SetFocus(firstTabStop);
}
return true;
}

The TraversalRequest parameter tells you whether the tab action is a tab or shift tab.

Override OnMnemonic Method to Support Mnemonics


Keyboard handling is almost complete, but there is one thing missing – mnemonics do
not work. If a user presses alt-F, focus doe not jump to the "First name:" edit box. So,
you override the OnMnemonic method:

C++

virtual bool OnMnemonic(System::Windows::Interop::MSG% msg, ModifierKeys


modifiers) override {
::MSG m = ConvertMessage(msg);

// If it's one of our mnemonics, set focus to the appropriate hwnd


if (msg.message == WM_SYSCHAR && GetKeyState(VK_MENU /*alt*/)) {
int dialogitem = 9999;
switch (m.wParam) {
case 's': dialogitem = IDOK; break;
case 'c': dialogitem = IDCANCEL; break;
case 'f': dialogitem = IDC_EDIT1; break;
case 'l': dialogitem = IDC_EDIT2; break;
case 'p': dialogitem = IDC_EDIT3; break;
case 'a': dialogitem = IDC_EDIT4; break;
case 'i': dialogitem = IDC_EDIT5; break;
case 't': dialogitem = IDC_EDIT6; break;
case 'z': dialogitem = IDC_EDIT7; break;
}
if (dialogitem != 9999) {
HWND hwnd = GetDlgItem(dialog, dialogitem);
SetFocus(hwnd);
return true;
}
}
return false; // key unhandled
};
Why not call IsDialogMessage here? You have the same issue as before--you need to be
able to inform WPF code whether your code handled the keystroke or not, and
IsDialogMessage cannot do that. There is also a second issue, because IsDialogMessage

refuses to process the mnemonic if the focused HWND is not inside the dialog box.

Instantiate the HwndHost Derived Class


Finally, now that all the key and tab support is in place, you can put your HwndHost into
the larger WPF application. If the main application is written in XAML, the easiest way to
put it in the right place is to leave an empty Border element where you want to put the
HwndHost. Here you create a Border named insertHwndHostHere :

XAML

<Window x:Class="WPFApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Windows Presentation Framework Application"
Loaded="Window1_Loaded"
>
<StackPanel>
<Button Content="WPF button"/>
<Border Name="insertHwndHostHere" Height="200" Width="500"/>
<Button Content="WPF button"/>
</StackPanel>
</Window>

Then all that remains is to find a good place in code sequence to instantiate the
HwndHost and connect it to the Border. In this example, you will put it inside the
constructor for the Window derived class:

C#

public partial class Window1 : Window {


public Window1() {
}

void Window1_Loaded(object sender, RoutedEventArgs e) {


HwndHost host = new ManagedCpp.MyHwndHost();
insertHwndHostHere.Child = host;
}
}

Which gives you:


See also
WPF and Win32 Interoperation
Walkthrough: Host a Win32 Control in
WPF
Article • 02/06/2023

Windows Presentation Foundation (WPF) provides a rich environment for creating


applications. However, when you have a substantial investment in Win32 code, it may be
more effective to reuse at least some of that code in your WPF application rather than
rewrite it completely. WPF provides a straightforward mechanism for hosting a Win32
window, on a WPF page.

This topic walks you through an application, Hosting a Win32 ListBox Control in WPF
Sample , that hosts a Win32 list box control. This general procedure can be extended
to hosting any Win32 window.

Requirements
This topic assumes a basic familiarity with both WPF and Windows API programming.
For a basic introduction to WPF programming, see Getting Started. For an introduction
to Windows API programming, see any of the numerous books on the subject, in
particular Programming Windows by Charles Petzold.

Because the sample that accompanies this topic is implemented in C#, it makes use of
Platform Invocation Services (PInvoke) to access the Windows API. Some familiarity with
PInvoke is helpful but not essential.

7 Note

This topic includes a number of code examples from the associated sample.
However, for readability, it does not include the complete sample code. You can
obtain or view complete code from Hosting a Win32 ListBox Control in WPF
Sample .

The Basic Procedure


This section outlines the basic procedure for hosting a Win32 window on a WPF page.
The remaining sections go through the details of each step.

The basic hosting procedure is:


1. Implement a WPF page to host the window. One technique is to create a Border
element to reserve a section of the page for the hosted window.

2. Implement a class to host the control that inherits from HwndHost.

3. In that class, override the HwndHost class member BuildWindowCore.

4. Create the hosted window as a child of the window that contains the WPF page.
Although conventional WPF programming does not need to explicitly make use of
it, the hosting page is a window with a handle (HWND). You receive the page
HWND through the hwndParent parameter of the BuildWindowCore method. The
hosted window should be created as a child of this HWND.

5. Once you have created the host window, return the HWND of the hosted window.
If you want to host one or more Win32 controls, you typically create a host window
as a child of the HWND and make the controls children of that host window.
Wrapping the controls in a host window provides a simple way for your WPF page
to receive notifications from the controls, which deals with some particular Win32
issues with notifications across the HWND boundary.

6. Handle selected messages sent to the host window, such as notifications from
child controls. There are two ways to do this.

If you prefer to handle messages in your hosting class, override the WndProc
method of the HwndHost class.

If you prefer to have the WPF handle the messages, handle the HwndHost
class MessageHook event in your code-behind. This event occurs for every
message that is received by the hosted window. If you choose this option,
you must still override WndProc, but you only need a minimal
implementation.

7. Override the DestroyWindowCore and WndProc methods of HwndHost. You must


override these methods to satisfy the HwndHost contract, but you may only need
to provide a minimal implementation.

8. In your code-behind file, create an instance of the control hosting class and make
it a child of the Border element that is intended to host the window.

9. Communicate with the hosted window by sending it Microsoft Windows messages


and handling messages from its child windows, such as notifications sent by
controls.
Implement the Page Layout
The layout for the WPF page that hosts the ListBox Control consists of two regions. The
left side of the page hosts several WPF controls that provide a user interface (UI) that
allows you to manipulate the Win32 control. The upper right corner of the page has a
square region for the hosted ListBox Control.

The code to implement this layout is quite simple. The root element is a DockPanel that
has two child elements. The first is a Border element that hosts the ListBox Control. It
occupies a 200x200 square in the upper right corner of the page. The second is a
StackPanel element that contains a set of WPF controls that display information and
allow you to manipulate the ListBox Control by setting exposed interoperation
properties. For each of the elements that are children of the StackPanel, see the
reference material for the various elements used for details on what these elements are
or what they do, these are listed in the example code below but will not be explained
here (the basic interoperation model does not require any of them, they are provided to
add some interactivity to the sample).

XAML

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WPF_Hosting_Win32_Control.HostWindow"
Name="mainWindow"
Loaded="On_UIReady">

<DockPanel Background="LightGreen">
<Border Name="ControlHostElement"
Width="200"
Height="200"
HorizontalAlignment="Right"
VerticalAlignment="Top"
BorderBrush="LightGray"
BorderThickness="3"
DockPanel.Dock="Right"/>
<StackPanel>
<Label HorizontalAlignment="Center"
Margin="0,10,0,0"
FontSize="14"
FontWeight="Bold">Control the Control</Label>
<TextBlock Margin="10,10,10,10" >Selected Text: <TextBlock
Name="selectedText"/></TextBlock>
<TextBlock Margin="10,10,10,10" >Number of Items: <TextBlock
Name="numItems"/></TextBlock>

<Line X1="0" X2="200"


Stroke="LightYellow"
StrokeThickness="2"
HorizontalAlignment="Center"
Margin="0,20,0,0"/>

<Label HorizontalAlignment="Center"
Margin="10,10,10,10">Append an Item to the List</Label>
<StackPanel Orientation="Horizontal">
<Label HorizontalAlignment="Left"
Margin="10,10,10,10">Item Text</Label>
<TextBox HorizontalAlignment="Left"
Name="txtAppend"
Width="200"
Margin="10,10,10,10"></TextBox>
</StackPanel>

<Button HorizontalAlignment="Left"
Click="AppendText"
Width="75"
Margin="10,10,10,10">Append</Button>

<Line X1="0" X2="200"


Stroke="LightYellow"
StrokeThickness="2"
HorizontalAlignment="Center"
Margin="0,20,0,0"/>

<Label HorizontalAlignment="Center"
Margin="10,10,10,10">Delete the Selected Item</Label>

<Button Click="DeleteText"
Width="125"
Margin="10,10,10,10"
HorizontalAlignment="Left">Delete</Button>
</StackPanel>
</DockPanel>
</Window>

Implement a Class to Host the Microsoft Win32


Control
The core of this sample is the class that actually hosts the control, ControlHost.cs. It
inherits from HwndHost. The constructor takes two parameters, height and width, which
correspond to the height and width of the Border element that hosts the ListBox control.
These values are used later to ensure that the size of the control matches the Border
element.

C#

public class ControlHost : HwndHost


{
IntPtr hwndControl;
IntPtr hwndHost;
int hostHeight, hostWidth;

public ControlHost(double height, double width)


{
hostHeight = (int)height;
hostWidth = (int)width;
}

There is also a set of constants. These constants are largely taken from Winuser.h, and
allow you to use conventional names when calling Win32 functions.

C#

internal const int


WS_CHILD = 0x40000000,
WS_VISIBLE = 0x10000000,
LBS_NOTIFY = 0x00000001,
HOST_ID = 0x00000002,
LISTBOX_ID = 0x00000001,
WS_VSCROLL = 0x00200000,
WS_BORDER = 0x00800000;

Override BuildWindowCore to Create the Microsoft


Win32 Window
You override this method to create the Win32 window that will be hosted by the page,
and make the connection between the window and the page. Because this sample
involves hosting a ListBox Control, two windows are created. The first is the window that
is actually hosted by the WPF page. The ListBox Control is created as a child of that
window.

The reason for this approach is to simplify the process of receiving notifications from the
control. The HwndHost class allows you to process messages sent to the window that it
is hosting. If you host a Win32 control directly, you receive the messages sent to the
internal message loop of the control. You can display the control and send it messages,
but you do not receive the notifications that the control sends to its parent window. This
means, among other things, that you have no way of detecting when the user interacts
with the control. Instead, create a host window and make the control a child of that
window. This allows you to process the messages for the host window including the
notifications sent to it by the control. For convenience, since the host window is little
more than a simple wrapper for the control, the package will be referred to as a ListBox
control.
Create the Host Window and ListBox Control
You can use PInvoke to create a host window for the control by creating and registering
a window class, and so on. However, a much simpler approach is to create a window
with the predefined "static" window class. This provides you with the window procedure
you need in order to receive notifications from the control, and requires minimal coding.

The HWND of the control is exposed through a read-only property, such that the host
page can use it to send messages to the control.

C#

public IntPtr hwndListBox


{
get { return hwndControl; }
}

The ListBox control is created as a child of the host window. The height and width of
both windows are set to the values passed to the constructor, discussed above. This
ensures that the size of the host window and control is identical to the reserved area on
the page. After the windows are created, the sample returns a HandleRef object that
contains the HWND of the host window.

C#

protected override HandleRef BuildWindowCore(HandleRef hwndParent)


{
hwndControl = IntPtr.Zero;
hwndHost = IntPtr.Zero;

hwndHost = CreateWindowEx(0, "static", "",


WS_CHILD | WS_VISIBLE,
0, 0,
hostWidth, hostHeight,
hwndParent.Handle,
(IntPtr)HOST_ID,
IntPtr.Zero,
0);

hwndControl = CreateWindowEx(0, "listbox", "",


WS_CHILD | WS_VISIBLE | LBS_NOTIFY
| WS_VSCROLL | WS_BORDER,
0, 0,
hostWidth, hostHeight,
hwndHost,
(IntPtr) LISTBOX_ID,
IntPtr.Zero,
0);
return new HandleRef(this, hwndHost);
}

C#

//PInvoke declarations
[DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet =
CharSet.Unicode)]
internal static extern IntPtr CreateWindowEx(int dwExStyle,
string lpszClassName,
string lpszWindowName,
int style,
int x, int y,
int width, int height,
IntPtr hwndParent,
IntPtr hMenu,
IntPtr hInst,

[MarshalAs(UnmanagedType.AsAny)] object pvParam);

Implement DestroyWindow and WndProc


In addition to BuildWindowCore, you must also override the WndProc and
DestroyWindowCore methods of the HwndHost. In this example, the messages for the
control are handled by the MessageHook handler, thus the implementation of WndProc
and DestroyWindowCore is minimal. In the case of WndProc, set handled to false to
indicate that the message was not handled and return 0. For DestroyWindowCore,
simply destroy the window.

C#

protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam,


IntPtr lParam, ref bool handled)
{
handled = false;
return IntPtr.Zero;
}

protected override void DestroyWindowCore(HandleRef hwnd)


{
DestroyWindow(hwnd.Handle);
}

C#

[DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet =


CharSet.Unicode)]
internal static extern bool DestroyWindow(IntPtr hwnd);

Host the Control on the Page


To host the control on the page, you first create a new instance of the ControlHost class.
Pass the height and width of the border element that contains the control
( ControlHostElement ) to the ControlHost constructor. This ensures that the ListBox is
sized correctly. You then host the control on the page by assigning the ControlHost
object to the Child property of the host Border.

The sample attaches a handler to the MessageHook event of the ControlHost to receive
messages from the control. This event is raised for every message sent to the hosted
window. In this case, these are the messages sent to window that wraps the actual
ListBox control, including notifications from the control. The sample calls SendMessage
to obtain information from the control and modify its contents. The details of how the
page communicates with the control are discussed in the next section.

7 Note

Notice that there are two PInvoke declarations for SendMessage. This is necessary
because one uses the wParam parameter to pass a string and the other uses it to
pass an integer. You need a separate declaration for each signature to ensure that
the data is marshaled correctly.

C#

public partial class HostWindow : Window


{
int selectedItem;
IntPtr hwndListBox;
ControlHost listControl;
Application app;
Window myWindow;
int itemCount;

private void On_UIReady(object sender, EventArgs e)


{
app = System.Windows.Application.Current;
myWindow = app.MainWindow;
myWindow.SizeToContent = SizeToContent.WidthAndHeight;
listControl = new ControlHost(ControlHostElement.ActualHeight,
ControlHostElement.ActualWidth);
ControlHostElement.Child = listControl;
listControl.MessageHook += new HwndSourceHook(ControlMsgFilter);
hwndListBox = listControl.hwndListBox;
for (int i = 0; i < 15; i++) //populate listbox
{
string itemText = "Item" + i.ToString();
SendMessage(hwndListBox, LB_ADDSTRING, IntPtr.Zero, itemText);
}
itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero,
IntPtr.Zero);
numItems.Text = "" + itemCount.ToString();
}

C#

private IntPtr ControlMsgFilter(IntPtr hwnd, int msg, IntPtr wParam, IntPtr


lParam, ref bool handled)
{
int textLength;

handled = false;
if (msg == WM_COMMAND)
{
switch ((uint)wParam.ToInt32() >> 16 & 0xFFFF) //extract the HIWORD
{
case LBN_SELCHANGE : //Get the item text and display it
selectedItem = SendMessage(listControl.hwndListBox, LB_GETCURSEL,
IntPtr.Zero, IntPtr.Zero);
textLength = SendMessage(listControl.hwndListBox, LB_GETTEXTLEN,
IntPtr.Zero, IntPtr.Zero);
StringBuilder itemText = new StringBuilder();
SendMessage(hwndListBox, LB_GETTEXT, selectedItem, itemText);
selectedText.Text = itemText.ToString();
handled = true;
break;
}
}
return IntPtr.Zero;
}
internal const int
LBN_SELCHANGE = 0x00000001,
WM_COMMAND = 0x00000111,
LB_GETCURSEL = 0x00000188,
LB_GETTEXTLEN = 0x0000018A,
LB_ADDSTRING = 0x00000180,
LB_GETTEXT = 0x00000189,
LB_DELETESTRING = 0x00000182,
LB_GETCOUNT = 0x0000018B;

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet =


CharSet.Unicode)]
internal static extern int SendMessage(IntPtr hwnd,
int msg,
IntPtr wParam,
IntPtr lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet =


CharSet.Unicode)]
internal static extern int SendMessage(IntPtr hwnd,
int msg,
int wParam,
[MarshalAs(UnmanagedType.LPWStr)]
StringBuilder lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet =


CharSet.Unicode)]
internal static extern IntPtr SendMessage(IntPtr hwnd,
int msg,
IntPtr wParam,
String lParam);

Implement Communication Between the


Control and the Page
You manipulate the control by sending it Windows messages. The control notifies you
when the user interacts with it by sending notifications to its host window. The Hosting
a Win32 ListBox Control in WPF sample includes a UI that provides several examples
of how this works:

Append an item to the list.

Delete the selected item from the list

Display the text of the currently selected item.

Display the number of items in the list.

The user can also select an item in the list box by clicking on it, just as they would for a
conventional Win32 application. The displayed data is updated each time the user
changes the state of the list box by selecting, adding, or appending an item.

To append items, send the list box an LB_ADDSTRING message. To delete items, send
LB_GETCURSEL to get the index of the current selection and then LB_DELETESTRING to
delete the item. The sample also sends LB_GETCOUNT, and uses the returned value to
update the display that shows the number of items. Both these instances of
SendMessage use one of the PInvoke declarations discussed in the previous section.

C#
private void AppendText(object sender, EventArgs args)
{
if (!string.IsNullOrEmpty(txtAppend.Text))
{
SendMessage(hwndListBox, LB_ADDSTRING, IntPtr.Zero, txtAppend.Text);
}
itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero,
IntPtr.Zero);
numItems.Text = "" + itemCount.ToString();
}
private void DeleteText(object sender, EventArgs args)
{
selectedItem = SendMessage(listControl.hwndListBox, LB_GETCURSEL,
IntPtr.Zero, IntPtr.Zero);
if (selectedItem != -1) //check for selected item
{
SendMessage(hwndListBox, LB_DELETESTRING, (IntPtr)selectedItem,
IntPtr.Zero);
}
itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero,
IntPtr.Zero);
numItems.Text = "" + itemCount.ToString();
}

When the user selects an item or changes their selection, the control notifies the host
window by sending it a WM_COMMAND message, which raises the MessageHook event
for the page. The handler receives the same information as the main window procedure
of the host window. It also passes a reference to a Boolean value, handled . You set
handled to true to indicate that you have handled the message and no further

processing is needed.

WM_COMMAND is sent for a variety of reasons, so you must examine the notification ID
to determine whether it is an event that you wish to handle. The ID is contained in the
high word of the wParam parameter. The sample uses bitwise operators to extract the ID.
If the user has made or changed their selection, the ID will be LBN_SELCHANGE.

When LBN_SELCHANGE is received, the sample gets the index of the selected item by
sending the control a LB_GETCURSEL message. To get the text, you first create a
StringBuilder. You then send the control an LB_GETTEXT message. Pass the empty
StringBuilder object as the wParam parameter. When SendMessage returns, the
StringBuilder will contain the text of the selected item. This use of SendMessage requires
yet another PInvoke declaration.

Finally, set handled to true to indicate that the message has been handled.
See also
HwndHost
WPF and Win32 Interoperation
Walkthrough: My first WPF desktop application
Walkthrough: Hosting WPF Content in
Win32
Article • 02/06/2023

WPF functionality to your application rather than rewriting your original code. WPF
provides a straightforward mechanism for hosting WPF content in a Win32 window.

This tutorial describes how to write a sample application, Hosting WPF Content in a
Win32 Window Sample , that hosts WPF content in a Win32 window. You can extend
this sample to host any Win32 window. Because it involves mixing managed and
unmanaged code, the application is written in C++/CLI.

Requirements
This tutorial assumes a basic familiarity with both WPF and Win32 programming. For a
basic introduction to WPF programming, see Getting Started. For an introduction to
Win32 programming, you should reference any of the numerous books on the subject,
in particular Programming Windows by Charles Petzold.

Because the sample that accompanies this tutorial is implemented in C++/CLI, this
tutorial assumes familiarity with the use of C++ to program the Windows API plus an
understanding of managed code programming. Familiarity with C++/CLI is helpful but
not essential.

7 Note

This tutorial includes a number of code examples from the associated sample.
However, for readability, it does not include the complete sample code. For the
complete sample code, see Hosting WPF Content in a Win32 Window Sample .

The Basic Procedure


This section outlines the basic procedure you use to host WPF content in a Win32
window. The remaining sections explain the details of each step.

The key to hosting WPF content on a Win32 window is the HwndSource class. This class
wraps the WPF content in a Win32 window, allowing it to be incorporated into your WPF
in a single application.
1. Implement your WPF content as a managed class.

2. Implement a Windows application with C++/CLI. If you are starting with an existing
application and unmanaged C++ code, you can usually enable it to call managed
code by changing your project settings to include the /clr compiler flag.

3. Set the threading model to single-threaded apartment (STA).

4. Handle the WM_CREATEnotification in your window procedure and do the


following:

a. Create a new HwndSource object with the parent window as its parent
parameter.

b. Create an instance of your WPF content class.

c. Assign a reference to the WPF content object to the RootVisual property of the
HwndSource.

d. Get the HWND for the content. The Handle property of the HwndSource object
contains the window handle (HWND). To get an HWND that you can use in the
unmanaged part of your application, cast Handle.ToPointer() to an HWND.

5. Implement a managed class that contains a static field to hold a reference to your
WPF content. This class allows you to get a reference to the WPF content from
your Win32 code.

6. Assign the WPF content to the static field.

7. Receive notifications from the WPF content by attaching a handler to one or more
of the WPF events.

8. Communicate with the WPF content by using the reference that you stored in the
static field to set properties, and so on.

7 Note

You can also use WPF content. However, you will have to compile it separately as a
dynamic-link library (DLL) and reference that DLL from your Win32 application. The
remainder of the procedure is similar to that outlined above.

Implementing the Host Application


This section describes how to host WPF content in a basic Win32 application. The
content itself is implemented in C++/CLI as a managed class. For the most part, it is
straightforward WPF programming. The key aspects of the content implementation are
discussed in Implementing the WPF Content.

The Basic Application

Hosting the WPF Content

Holding a Reference to the WPF Content

Communicating with the WPF Content

The Basic Application


The starting point for the host application was to create a Visual Studio 2005 template.

1. Open Visual Studio 2005, and select New Project from the File menu.

2. Select Win32 from the list of Visual C++ project types. If your default language is
not C++, you will find these project types under Other Languages.

3. Select a Win32 Project template, assign a name to the project and click OK to
launch the Win32 Application Wizard.

4. Accept the wizard's default settings and click Finish to start the project.

The template creates a basic Win32 application, including:

An entry point for the application.

A window, with an associated window procedure (WndProc).

A menu with File and Help headings. The File menu has an Exit item that closes
the application. The Help menu has an About item that launches a simple dialog
box.

Before you start writing code to host the WPF content, you need to make two
modifications to the basic template.

The first is to compile the project as managed code. By default, the project compiles as
unmanaged code. However, because WPF is implemented in managed code, the project
must be compiled accordingly.

1. Right-click the project name in Solution Explorer and select Properties from the
context menu to launch the Property Pages dialog box.
2. Select Configuration Properties from the tree view in the left pane.

3. Select Common Language Runtime support from the Project Defaults list in the
right pane.

4. Select Common Language Runtime Support (/clr) from the drop-down list box.

7 Note

This compiler flag allows you to use managed code in your application, but your
unmanaged code will still compile as before.

WPF uses the single-threaded apartment (STA) threading model. In order to work
properly with the WPF content code, you must set the application's threading model to
STA by applying an attribute to the entry point.

C++

[System::STAThreadAttribute] //Needs to be an STA thread to play nicely with


WPF
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{

Hosting the WPF Content


The WPF content is a simple address entry application. It consists of several TextBox
controls to take user name, address, and so on. There are also two Button controls, OK
and Cancel. When the user clicks OK, the button's Click event handler collects the data
from the TextBox controls, assigns it to corresponding properties, and raises a custom
event, OnButtonClicked . When the user clicks Cancel, the handler simply raises
OnButtonClicked . The event argument object for OnButtonClicked contains a Boolean
field that indicates which button was clicked.

The code to host the WPF content is implemented in a handler for the WM_CREATE
notification on the host window.

C++

case WM_CREATE :
GetClientRect(hWnd, &rect);
wpfHwnd = GetHwnd(hWnd, rect.right-375, 0, 375, 250);
CreateDataDisplay(hWnd, 275, rect.right-375, 375);
CreateRadioButtons(hWnd);
break;

The GetHwnd method takes size and position information plus the parent window handle
and returns the window handle of the hosted WPF content.

7 Note

You cannot use a #using directive for the System::Windows::Interop namespace.


Doing so creates a name collision between the MSG structure in that namespace
and the MSG structure declared in winuser.h. You must instead use fully-qualified
names to access the contents of that namespace.

C++

HWND GetHwnd(HWND parent, int x, int y, int width, int height)


{
System::Windows::Interop::HwndSourceParameters^ sourceParams = gcnew
System::Windows::Interop::HwndSourceParameters(
"hi" // NAME
);
sourceParams->PositionX = x;
sourceParams->PositionY = y;
sourceParams->Height = height;
sourceParams->Width = width;
sourceParams->ParentWindow = IntPtr(parent);
sourceParams->WindowStyle = WS_VISIBLE | WS_CHILD; // style
System::Windows::Interop::HwndSource^ source = gcnew
System::Windows::Interop::HwndSource(*sourceParams);
WPFPage ^myPage = gcnew WPFPage(width, height);
//Assign a reference to the WPF page and a set of UI properties to a set
of static properties in a class
//that is designed for that purpose.
WPFPageHost::hostedPage = myPage;
WPFPageHost::initBackBrush = myPage->Background;
WPFPageHost::initFontFamily = myPage->DefaultFontFamily;
WPFPageHost::initFontSize = myPage->DefaultFontSize;
WPFPageHost::initFontStyle = myPage->DefaultFontStyle;
WPFPageHost::initFontWeight = myPage->DefaultFontWeight;
WPFPageHost::initForeBrush = myPage->DefaultForeBrush;
myPage->OnButtonClicked += gcnew
WPFPage::ButtonClickHandler(WPFButtonClicked);
source->RootVisual = myPage;
return (HWND) source->Handle.ToPointer();
}
You cannot host the WPF content directly in your application window. Instead, you first
create an HwndSource object to wrap the WPF content. This object is basically a window
that is designed to host a WPF content. You host the HwndSource object in the parent
window by creating it as a child of a Win32 window that is part of your application. The
HwndSource constructor parameters contain much the same information that you
would pass to CreateWindow when you create a Win32 child window.

You next create an instance of the WPF content object. In this case, the WPF content is
implemented as a separate class, WPFPage , using C++/CLI. You could also implement the
WPF content with WPF content as a DLL. You can add a reference to that DLL to your
project, and use that reference to create an instance of the WPF content.

You display the WPF content in your child window by assigning a reference to the WPF
content to the RootVisual property of the HwndSource.

The next line of code attaches an event handler, WPFButtonClicked , to the WPF content
OnButtonClicked event. This handler is called when the user clicks the OK or Cancel
button. See communicating_with_the_WPF content for further discussion of this event
handler.

The final line of code shown returns the window handle (HWND) that is associated with
the HwndSource object. You can use this handle from your Win32 code to send
messages to the hosted window, although the sample does not do so. The HwndSource
object raises an event every time it receives a message. To process the messages, call the
AddHook method to attach a message handler and then process the messages in that
handler.

Holding a Reference to the WPF Content


For many applications, you will want to communicate with the WPF content later. For
example, you might want to modify the WPF content properties, or perhaps have the
HwndSource object host different WPF content. To do this, you need a reference to the
HwndSource object or the WPF content. The HwndSource object and its associated WPF
content remain in memory until you destroy the window handle. However, the variable
you assign to the HwndSource object will go out of scope as soon as you return from
the window procedure. The customary way to handle this issue with Win32 applications
is to use a static or global variable. Unfortunately, you cannot assign a managed object
to those types of variables. You can assign the window handle associated with
HwndSource object to a global or static variable, but that doe not provide access to the
object itself.
The simplest solution to this issue is to implement a managed class that contains a set
of static fields to hold references to any managed objects that you need access to. The
sample uses the WPFPageHost class to hold a reference to the WPF content, plus the
initial values of a number of its properties that might be changed later by the user. This
is defined in the header.

C++

public ref class WPFPageHost


{
public:
WPFPageHost();
static WPFPage^ hostedPage;
//initial property settings
static System::Windows::Media::Brush^ initBackBrush;
static System::Windows::Media::Brush^ initForeBrush;
static System::Windows::Media::FontFamily^ initFontFamily;
static System::Windows::FontStyle initFontStyle;
static System::Windows::FontWeight initFontWeight;
static double initFontSize;
};

The latter part of the GetHwnd function assigns values to those fields for later use while
myPage is still in scope.

Communicating with the WPF Content


There are two types of communication with the UI that allows the user to change
various WPF content properties, such as the background color or default font size.

As mentioned above, when the user clicks either button the WPF content raises an
OnButtonClicked event. The application attaches a handler to this event to receive these
notifications. If the OK button was clicked, the handler gets the user information from
the WPF content and displays it in a set of static controls.

C++

void WPFButtonClicked(Object ^sender, MyPageEventArgs ^args)


{
if(args->IsOK) //display data if OK button was clicked
{
WPFPage ^myPage = WPFPageHost::hostedPage;
LPCWSTR userName = (LPCWSTR)
InteropServices::Marshal::StringToHGlobalAuto("Name: " + myPage-
>EnteredName).ToPointer();
SetWindowText(nameLabel, userName);
LPCWSTR userAddress = (LPCWSTR)
InteropServices::Marshal::StringToHGlobalAuto("Address: " + myPage-
>EnteredAddress).ToPointer();
SetWindowText(addressLabel, userAddress);
LPCWSTR userCity = (LPCWSTR)
InteropServices::Marshal::StringToHGlobalAuto("City: " + myPage-
>EnteredCity).ToPointer();
SetWindowText(cityLabel, userCity);
LPCWSTR userState = (LPCWSTR)
InteropServices::Marshal::StringToHGlobalAuto("State: " + myPage-
>EnteredState).ToPointer();
SetWindowText(stateLabel, userState);
LPCWSTR userZip = (LPCWSTR)
InteropServices::Marshal::StringToHGlobalAuto("Zip: " + myPage-
>EnteredZip).ToPointer();
SetWindowText(zipLabel, userZip);
}
else
{
SetWindowText(nameLabel, L"Name: ");
SetWindowText(addressLabel, L"Address: ");
SetWindowText(cityLabel, L"City: ");
SetWindowText(stateLabel, L"State: ");
SetWindowText(zipLabel, L"Zip: ");
}
}

The handler receives a custom event argument object from the WPF content,
MyPageEventArgs . The object's IsOK property is set to true if the OK button was clicked,

and false if the Cancel button was clicked.

If the OK button was clicked, the handler gets a reference to the WPF content from the
container class. It then collects the user information that is held by the associated WPF
content properties and uses the static controls to display the information on the parent
window. Because the WPF content data is in the form of a managed string, it has to be
marshaled for use by a Win32 control. If the Cancel button was clicked, the handler
clears the data from the static controls.

The application UI provides a set of radio buttons that allow the user to modify the
background color of the WPF content, and several font-related properties. The following
example is an excerpt from the application's window procedure (WndProc) and its
message handling that sets various properties on different messages, including the
background color. The others are similar, and are not shown. See the complete sample
for details and context.

C++

case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);

switch (wmId)
{
//Menu selections
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
//RadioButtons
case IDC_ORIGINALBACKGROUND :
WPFPageHost::hostedPage->Background = WPFPageHost::initBackBrush;
break;
case IDC_LIGHTGREENBACKGROUND :
WPFPageHost::hostedPage->Background = gcnew
SolidColorBrush(Colors::LightGreen);
break;
case IDC_LIGHTSALMONBACKGROUND :
WPFPageHost::hostedPage->Background = gcnew
SolidColorBrush(Colors::LightSalmon);
break;

To set the background color, get a reference to the WPF content ( hostedPage ) from
WPFPageHost and set the background color property to the appropriate color. The

sample uses three color options: the original color, light green, or light salmon. The
original background color is stored as a static field in the WPFPageHost class. To set the
other two, you create a new SolidColorBrush object and pass the constructor a static
colors value from the Colors object.

Implementing the WPF Page


You can host and use the WPF content without any knowledge of the actual
implementation. If the WPF content had been packaged in a separate DLL, it could have
been built in any common language runtime (CLR) language. Following is a brief
walkthrough of the C++/CLI implementation that is used in the sample. This section
contains the following subsections.

Layout

Returning the Data to the Host Window

Setting the WPF Properties

Layout
The UI elements in the WPF content consist of five TextBox controls, with associated
Label controls: Name, Address, City, State, and Zip. There are also two Button controls,
OK and Cancel

The WPF content is implemented in the WPFPage class. Layout is handled with a Grid
layout element. The class inherits from Grid, which effectively makes it the WPF content
root element.

The WPF content constructor takes the required width and height, and sizes the Grid
accordingly. It then defines the basic layout by creating a set of ColumnDefinition and
RowDefinition objects and adding them to the Grid object base ColumnDefinitions and
RowDefinitions collections, respectively. This defines a grid of five rows and seven
columns, with the dimensions determined by the contents of the cells.

C++

WPFPage::WPFPage(int allottedWidth, int allotedHeight)


{
array<ColumnDefinition ^> ^ columnDef = gcnew array<ColumnDefinition ^>
(4);
array<RowDefinition ^> ^ rowDef = gcnew array<RowDefinition ^> (6);

this->Height = allotedHeight;
this->Width = allottedWidth;
this->Background = gcnew SolidColorBrush(Colors::LightGray);

//Set up the Grid's row and column definitions


for(int i=0; i<4; i++)
{
columnDef[i] = gcnew ColumnDefinition();
columnDef[i]->Width = GridLength(1, GridUnitType::Auto);
this->ColumnDefinitions->Add(columnDef[i]);
}
for(int i=0; i<6; i++)
{
rowDef[i] = gcnew RowDefinition();
rowDef[i]->Height = GridLength(1, GridUnitType::Auto);
this->RowDefinitions->Add(rowDef[i]);
}

Next, the constructor adds the UI elements to the Grid. The first element is the title text,
which is a Label control that is centered in the first row of the grid.

C++

//Add the title


titleText = gcnew Label();
titleText->Content = "Simple WPF Control";
titleText->HorizontalAlignment =
System::Windows::HorizontalAlignment::Center;
titleText->Margin = Thickness(10, 5, 10, 0);
titleText->FontWeight = FontWeights::Bold;
titleText->FontSize = 14;
Grid::SetColumn(titleText, 0);
Grid::SetRow(titleText, 0);
Grid::SetColumnSpan(titleText, 4);
this->Children->Add(titleText);

The next row contains the Name Label control and its associated TextBox control.
Because the same code is used for each label/textbox pair, it is placed in a pair of private
methods and used for all five label/textbox pairs. The methods create the appropriate
control, and call the Grid class static SetColumn and SetRow methods to place the
controls in the appropriate cell. After the control is created, the sample calls the Add
method on the Children property of the Grid to add the control to the grid. The code to
add the remaining label/textbox pairs is similar. See the sample code for details.

C++

//Add the Name Label and TextBox


nameLabel = CreateLabel(0, 1, "Name");
this->Children->Add(nameLabel);
nameTextBox = CreateTextBox(1, 1, 3);
this->Children->Add(nameTextBox);

The implementation of the two methods is as follows:

C++

Label ^WPFPage::CreateLabel(int column, int row, String ^ text)


{
Label ^ newLabel = gcnew Label();
newLabel->Content = text;
newLabel->Margin = Thickness(10, 5, 10, 0);
newLabel->FontWeight = FontWeights::Normal;
newLabel->FontSize = 12;
Grid::SetColumn(newLabel, column);
Grid::SetRow(newLabel, row);
return newLabel;
}
TextBox ^WPFPage::CreateTextBox(int column, int row, int span)
{
TextBox ^newTextBox = gcnew TextBox();
newTextBox->Margin = Thickness(10, 5, 10, 0);
Grid::SetColumn(newTextBox, column);
Grid::SetRow(newTextBox, row);
Grid::SetColumnSpan(newTextBox, span);
return newTextBox;
}
Finally, the sample adds the OK and Cancel buttons and attaches an event handler to
their Click events.

C++

//Add the Buttons and atttach event handlers


okButton = CreateButton(0, 5, "OK");
cancelButton = CreateButton(1, 5, "Cancel");
this->Children->Add(okButton);
this->Children->Add(cancelButton);
okButton->Click += gcnew RoutedEventHandler(this, &WPFPage::ButtonClicked);
cancelButton->Click += gcnew RoutedEventHandler(this,
&WPFPage::ButtonClicked);

Returning the Data to the Host Window


When either button is clicked, its Click event is raised. The host window could simply
attach handlers to these events and get the data directly from the TextBox controls. The
sample uses a somewhat less direct approach. It handles the Click within the WPF
content, and then raises a custom event OnButtonClicked , to notify the WPF content.
This allows the WPF content to do some parameter validation before notifying the host.
The handler gets the text from the TextBox controls and assigns it to public properties,
from which the host can retrieve the information.

The event declaration, in WPFPage.h:

C++

public:
delegate void ButtonClickHandler(Object ^, MyPageEventArgs ^);
WPFPage();
WPFPage(int height, int width);
event ButtonClickHandler ^OnButtonClicked;

The Click event handler, in WPFPage.cpp:

C++

void WPFPage::ButtonClicked(Object ^sender, RoutedEventArgs ^args)


{

//TODO: validate input data


bool okClicked = true;
if(sender == cancelButton)
okClicked = false;
EnteredName = nameTextBox->Text;
EnteredAddress = addressTextBox->Text;
EnteredCity = cityTextBox->Text;
EnteredState = stateTextBox->Text;
EnteredZip = zipTextBox->Text;
OnButtonClicked(this, gcnew MyPageEventArgs(okClicked));
}

Setting the WPF Properties


The Win32 host allows the user to change several WPF content properties. From the
Win32 side, it is simply a matter of changing the properties. The implementation in the
WPF content class is somewhat more complicated, because there is no single global
property that controls the fonts for all controls. Instead, the appropriate property for
each control is changed in the properties' set accessors. The following example shows
the code for the DefaultFontFamily property. Setting the property calls a private
method that in turn sets the FontFamily properties for the various controls.

From WPFPage.h:

C++

property FontFamily^ DefaultFontFamily


{
FontFamily^ get() {return _defaultFontFamily;}
void set(FontFamily^ value) {SetFontFamily(value);}
};

From WPFPage.cpp:

C++

void WPFPage::SetFontFamily(FontFamily^ newFontFamily)


{
_defaultFontFamily = newFontFamily;
titleText->FontFamily = newFontFamily;
nameLabel->FontFamily = newFontFamily;
addressLabel->FontFamily = newFontFamily;
cityLabel->FontFamily = newFontFamily;
stateLabel->FontFamily = newFontFamily;
zipLabel->FontFamily = newFontFamily;
}

See also
HwndSource
WPF and Win32 Interoperation
Walkthrough: Host a WPF Clock in
Win32
Article • 08/18/2022

To put WPF inside Win32 applications, use HwndSource, which provides the HWND that
contains your WPF content. First you create the HwndSource, giving it parameters
similar to CreateWindow. Then you tell the HwndSource about the WPF content you
want inside it. Finally, you get the HWND out of the HwndSource. This walkthrough
illustrates how to create a mixed WPF inside Win32 application that reimplements the
operating system Date and Time Properties dialog.

Prerequisites
See WPF and Win32 Interoperation.

How to Use This Tutorial


This tutorial concentrates on the important steps of producing an interoperation
application. The tutorial is backed by a sample, Win32 Clock Interoperation Sample ,
but that sample is reflective of the end product. This tutorial documents the steps as if
you were starting with an existing Win32 project of your own, perhaps a pre-existing
project, and you were adding a hosted WPF to your application. You can compare your
end product with Win32 Clock Interoperation Sample .

A Walkthrough of Windows Presentation


Framework Inside Win32 (HwndSource)
The following graphic shows the intended end product of this tutorial:
You can recreate this dialog by creating a C++ Win32 project in Visual Studio, and using
the dialog editor to create the following:

(You do not need to use Visual Studio to use HwndSource, and you do not need to use
C++ to write Win32 programs, but this is a fairly typical way to do it, and lends itself well
to a stepwise tutorial explanation).
You need to accomplish five particular substeps in order to put a WPF clock into the
dialog:

1. Enable your Win32 project to call managed code (/clr) by changing project settings
in Visual Studio.

2. Create a WPFPage in a separate DLL.

3. Put that WPFPage inside an HwndSource.

4. Get an HWND for that Page using the Handle property.

5. Use Win32 to decide where to place the HWND within the larger Win32
application

/clr
The first step is to turn this unmanaged Win32 project into one that can call managed
code. You use the /clr compiler option, which will link to the necessary DLLs you want to
use, and adjust the Main method for use with WPF.

To enable the use of managed code inside the C++ project: Right-click on win32clock
project and select Properties. On the General property page (the default), change
Common Language Runtime support to /clr .

Next, add references to DLLs necessary for WPF: PresentationCore.dll,


PresentationFramework.dll, System.dll, WindowsBase.dll, UIAutomationProvider.dll, and
UIAutomationTypes.dll. (Following instructions assume the operating system is installed
on C: drive.)

1. Right-click win32clock project and select References..., and inside that dialog:

2. Right-click win32clock project and select References....

3. Click Add New Reference, click Browse tab, enter C:\Program Files\Reference
Assemblies\Microsoft\Framework\v3.0\PresentationCore.dll, and click OK.

4. Repeat for PresentationFramework.dll: C:\Program Files\Reference


Assemblies\Microsoft\Framework\v3.0\PresentationFramework.dll.

5. Repeat for WindowsBase.dll: C:\Program Files\Reference


Assemblies\Microsoft\Framework\v3.0\WindowsBase.dll.

6. Repeat for UIAutomationTypes.dll: C:\Program Files\Reference


Assemblies\Microsoft\Framework\v3.0\UIAutomationTypes.dll.
7. Repeat for UIAutomationProvider.dll: C:\Program Files\Reference
Assemblies\Microsoft\Framework\v3.0\UIAutomationProvider.dll.

8. Click Add New Reference, select System.dll, and click OK.

9. Click OK to exit the win32clock Property Pages for adding references.

Finally, add the STAThreadAttribute to the _tWinMain method for use with WPF:

C++

[System::STAThreadAttribute]
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)

This attribute tells the common language runtime (CLR) that when it initializes
Component Object Model (COM), it should use a single threaded apartment model
(STA), which is necessary for WPF (and Windows Forms).

Create a Windows Presentation Framework


Page
Next, you create a DLL that defines a WPFPage. It’s often easiest to create the WPFPage
as a standalone application, and write and debug the WPF portion that way. Once done,
that project can be turned into a DLL by right-clicking the project, clicking on
Properties, going to the Application, and changing Output type to Windows Class
Library.

The WPF dll project can then be combined with the Win32 project (one solution that
contains two projects) – right-click on the solution, select Add\Existing Project.

To use that WPF dll from the Win32 project, you need to add a reference:

1. Right-click win32clock project and select References....

2. Click Add New Reference.

3. Click the Projects tab. Select WPFClock, click OK.

4. Click OK to exit the win32clock Property Pages for adding references.

HwndSource
Next, you use HwndSource to make the WPFPage look like an HWND. You add this
block of code to a C++ file:

C++

namespace ManagedCode
{
using namespace System;
using namespace System::Windows;
using namespace System::Windows::Interop;
using namespace System::Windows::Media;

HWND GetHwnd(HWND parent, int x, int y, int width, int height) {


HwndSource^ source = gcnew HwndSource(
0, // class style
WS_VISIBLE | WS_CHILD, // style
0, // exstyle
x, y, width, height,
"hi", // NAME
IntPtr(parent) // parent window
);

UIElement^ page = gcnew WPFClock::Clock();


source->RootVisual = page;
return (HWND) source->Handle.ToPointer();
}
}
}

This is a long piece of code that could use some explanation. The first part is various
clauses so that you do not need to fully qualify all the calls:

C++

namespace ManagedCode
{
using namespace System;
using namespace System::Windows;
using namespace System::Windows::Interop;
using namespace System::Windows::Media;

Then you define a function that creates the WPF content, puts an HwndSource around it,
and returns the HWND:

C++

HWND GetHwnd(HWND parent, int x, int y, int width, int height) {

First you create an HwndSource, whose parameters are similar to CreateWindow:


C++

HwndSource^ source = gcnew HwndSource(


0, // class style
WS_VISIBLE | WS_CHILD, // style
0, // exstyle
x, y, width, height,
"hi", // NAME
IntPtr(parent) // parent window
);

Then you create the WPF content class by calling its constructor:

C++

UIElement^ page = gcnew WPFClock::Clock();

You then connect the page to the HwndSource:

C++

source->RootVisual = page;

And in the final line, return the HWND for the HwndSource:

C++

return (HWND) source->Handle.ToPointer();

Positioning the Hwnd


Now that you have an HWND that contains the WPF clock, you need to put that HWND
inside the Win32 dialog. If you knew just where to put the HWND, you would just pass
that size and location to the GetHwnd function you defined earlier. But you used a
resource file to define the dialog, so you are not exactly sure where any of the HWNDs
are positioned. You can use the Visual Studio dialog editor to put a Win32 STATIC
control where you want the clock to go ("Insert clock here"), and use that to position the
WPF clock.

Where you handle WM_INITDIALOG, you use GetDlgItem to retrieve the HWND for the
placeholder STATIC:

C++
HWND placeholder = GetDlgItem(hDlg, IDC_CLOCK);

You then calculate the size and position of that placeholder STATIC, so you can put the
WPF clock in that place:

RECT rectangle;

C++

GetWindowRect(placeholder, &rectangle);
int width = rectangle.right - rectangle.left;
int height = rectangle.bottom - rectangle.top;
POINT point;
point.x = rectangle.left;
point.y = rectangle.top;
result = MapWindowPoints(NULL, hDlg, &point, 1);

Then you hide the placeholder STATIC:

C++

ShowWindow(placeholder, SW_HIDE);

And create the WPF clock HWND in that location:

C++

HWND clock = ManagedCode::GetHwnd(hDlg, point.x, point.y, width, height);

To make the tutorial interesting, and to produce a real WPF clock, you will need to
create a WPF clock control at this point. You can do so mostly in markup, with just a few
event handlers in code-behind. Since this tutorial is about interoperation and not about
control design, complete code for the WPF clock is provided here as a code block,
without discrete instructions for building it up or what each part means. Feel free to
experiment with this code to change the look and feel or functionality of the control.

Here is the markup:

XAML

<Page x:Class="WPFClock.Clock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Grid>
<Grid.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#fcfcfe" Offset="0" />
<GradientStop Color="#f6f4f0" Offset="1.0" />
</LinearGradientBrush>
</Grid.Background>

<Grid Name="PodClock" HorizontalAlignment="Center"


VerticalAlignment="Center">
<Grid.Resources>
<Storyboard x:Key="sb">
<DoubleAnimation From="0" To="360" Duration="12:00:00"
RepeatBehavior="Forever"
Storyboard.TargetName="HourHand"
Storyboard.TargetProperty="
(Rectangle.RenderTransform).(RotateTransform.Angle)"
/>
<DoubleAnimation From="0" To="360" Duration="01:00:00"
RepeatBehavior="Forever"
Storyboard.TargetName="MinuteHand"
Storyboard.TargetProperty="
(Rectangle.RenderTransform).(RotateTransform.Angle)"
/>
<DoubleAnimation From="0" To="360" Duration="0:1:00"
RepeatBehavior="Forever"
Storyboard.TargetName="SecondHand"
Storyboard.TargetProperty="
(Rectangle.RenderTransform).(RotateTransform.Angle)"
/>
</Storyboard>
</Grid.Resources>

<Ellipse Width="108" Height="108" StrokeThickness="3">


<Ellipse.Stroke>
<LinearGradientBrush>
<GradientStop Color="LightBlue" Offset="0" />
<GradientStop Color="DarkBlue" Offset="1" />
</LinearGradientBrush>
</Ellipse.Stroke>
</Ellipse>
<Ellipse VerticalAlignment="Center" HorizontalAlignment="Center"
Width="104" Height="104" Fill="LightBlue" StrokeThickness="3">
<Ellipse.Stroke>
<LinearGradientBrush>
<GradientStop Color="DarkBlue" Offset="0" />
<GradientStop Color="LightBlue" Offset="1" />
</LinearGradientBrush>
</Ellipse.Stroke>
</Ellipse>
<Border BorderThickness="1" BorderBrush="Black"
Background="White" Margin="20" HorizontalAlignment="Right"
VerticalAlignment="Center">
<TextBlock Name="MonthDay" Text="{Binding}"/>
</Border>
<Canvas Width="102" Height="102">
<Ellipse Width="8" Height="8" Fill="Black" Canvas.Top="46"
Canvas.Left="46" />
<Rectangle Canvas.Top="5" Canvas.Left="48" Fill="Black"
Width="4" Height="8">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="0"
/>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black"
Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="30"
/>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black"
Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="60"
/>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="48" Fill="Black"
Width="4" Height="8">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="90"
/>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black"
Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46"
Angle="120" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black"
Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46"
Angle="150" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="48" Fill="Black"
Width="4" Height="8">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46"
Angle="180" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black"
Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46"
Angle="210" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black"
Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46"
Angle="240" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="48" Fill="Black"
Width="4" Height="8">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46"
Angle="270" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black"
Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46"
Angle="300" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black"
Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46"
Angle="330" />
</Rectangle.RenderTransform>
</Rectangle>

<Rectangle x:Name="HourHand" Canvas.Top="21"


Canvas.Left="48"
Fill="Black" Width="4" Height="30">
<Rectangle.RenderTransform>
<RotateTransform x:Name="HourHand2" CenterX="2"
CenterY="30" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="MinuteHand" Canvas.Top="6"
Canvas.Left="49"
Fill="Black" Width="2" Height="45">
<Rectangle.RenderTransform>
<RotateTransform CenterX="1" CenterY="45" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="SecondHand" Canvas.Top="4"
Canvas.Left="49"
Fill="Red" Width="1" Height="47">
<Rectangle.RenderTransform>
<RotateTransform CenterX="0.5" CenterY="47" />
</Rectangle.RenderTransform>
</Rectangle>
</Canvas>
</Grid>
</Grid>
</Page>

And here is the accompanying code-behind:

C#

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace WPFClock
{
/// <summary>
/// Interaction logic for Clock.xaml
/// </summary>
public partial class Clock : Page
{
private DispatcherTimer _dayTimer;

public Clock()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Clock_Loaded);
}

void Clock_Loaded(object sender, RoutedEventArgs e) {


// set the datacontext to be today's date
DateTime now = DateTime.Now;
DataContext = now.Day.ToString();

// then set up a timer to fire at the start of tomorrow, so that


we can update
// the datacontext
_dayTimer = new DispatcherTimer();
_dayTimer.Interval = new TimeSpan(1, 0, 0, 0) - now.TimeOfDay;
_dayTimer.Tick += new EventHandler(OnDayChange);
_dayTimer.Start();

// finally, seek the timeline, which assumes a beginning at


midnight, to the appropriate
// offset
Storyboard sb = (Storyboard)PodClock.FindResource("sb");
sb.Begin(PodClock, HandoffBehavior.SnapshotAndReplace, true);
sb.Seek(PodClock, now.TimeOfDay, TimeSeekOrigin.BeginTime);
}
private void OnDayChange(object sender, EventArgs e)
{
// date has changed, update the datacontext to reflect today's
date
DateTime now = DateTime.Now;
DataContext = now.Day.ToString();
_dayTimer.Interval = new TimeSpan(1, 0, 0, 0);
}
}
}

The final result looks like:

To compare your end result to the code that produced this screenshot, see Win32 Clock
Interoperation Sample .

See also
HwndSource
WPF and Win32 Interoperation
Win32 Clock Interoperation Sample
WPF and Direct3D9 Interoperation
Article • 02/06/2023

You can include Direct3D9 content in a Windows Presentation Foundation (WPF)


application. This topic describes how to create Direct3D9 content so that it efficiently
interoperates with WPF.

7 Note

When using Direct3D9 content in WPF, you also need to think about performance.
For more information about how to optimize for performance, see Performance
Considerations for Direct3D9 and WPF Interoperability.

Display Buffers
The D3DImage class manages two display buffers, which are called the back buffer and
the front buffer. The back buffer is your Direct3D9 surface. Changes to the back buffer
are copied forward to the front buffer when you call the Unlock method.

The following illustration shows the relationship between the back buffer and the front
buffer.

Direct3D9 Device Creation


To render Direct3D9 content, you must create a Direct3D9 device. There are two
Direct3D9 objects that you can use to create a device, IDirect3D9 and IDirect3D9Ex .
Use these objects to create IDirect3DDevice9 and IDirect3DDevice9Ex devices,
respectively.

Create a device by calling one of the following methods.


IDirect3D9 * Direct3DCreate9(UINT SDKVersion);

HRESULT Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex **ppD3D);

On Windows Vista or later operating system, use the Direct3DCreate9Ex method with a
display that is configured to use the Windows Display Driver Model (WDDM). Use the
Direct3DCreate9 method on any other platform.

Availability of the Direct3DCreate9Ex method


The d3d9.dll has the Direct3DCreate9Ex method only on Windows Vista or later
operating system. If you directly link the function on Windows XP, your application fails
to load. To determine whether the Direct3DCreate9Ex method is supported, load the
DLL and look for the proc address. The following code shows how to test for the
Direct3DCreate9Ex method. For a full code example, see Walkthrough: Creating

Direct3D9 Content for Hosting in WPF.

C++

HRESULT
CRendererManager::EnsureD3DObjects()
{
HRESULT hr = S_OK;

HMODULE hD3D = NULL;


if (!m_pD3D)
{
hD3D = LoadLibrary(TEXT("d3d9.dll"));
DIRECT3DCREATE9EXFUNCTION pfnCreate9Ex =
(DIRECT3DCREATE9EXFUNCTION)GetProcAddress(hD3D, "Direct3DCreate9Ex");
if (pfnCreate9Ex)
{
IFC((*pfnCreate9Ex)(D3D_SDK_VERSION, &m_pD3DEx));
IFC(m_pD3DEx->QueryInterface(__uuidof(IDirect3D9),
reinterpret_cast<void **>(&m_pD3D)));
}
else
{
m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (!m_pD3D)
{
IFC(E_FAIL);
}
}

m_cAdapters = m_pD3D->GetAdapterCount();
}

Cleanup:
if (hD3D)
{
FreeLibrary(hD3D);
}

return hr;
}

HWND Creation
Creating a device requires an HWND. In general, you create a dummy HWND for
Direct3D9 to use. The following code example shows how to create a dummy HWND.

C++

HRESULT
CRendererManager::EnsureHWND()
{
HRESULT hr = S_OK;

if (!m_hwnd)
{
WNDCLASS wndclass;

wndclass.style = CS_HREDRAW | CS_VREDRAW;


wndclass.lpfnWndProc = DefWindowProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = NULL;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;

if (!RegisterClass(&wndclass))
{
IFC(E_FAIL);
}

m_hwnd = CreateWindow(szAppName,
TEXT("D3DImageSample"),
WS_OVERLAPPEDWINDOW,
0, // Initial X
0, // Initial Y
0, // Width
0, // Height
NULL,
NULL,
NULL,
NULL);
}
Cleanup:
return hr;
}

Present Parameters
Creating a device also requires a D3DPRESENT_PARAMETERS struct, but only a few
parameters are important. These parameters are chosen to minimize the memory
footprint.

Set the BackBufferHeight and BackBufferWidth fields to 1. Setting them to 0 causes


them to be set to the dimensions of the HWND.

Always set the D3DCREATE_MULTITHREADED and D3DCREATE_FPU_PRESERVE flags to prevent


corrupting memory used by Direct3D9 and to prevent Direct3D9 from changing FPU
settings.

The following code shows how to initialize the D3DPRESENT_PARAMETERS struct.

C++

HRESULT
CRenderer::Init(IDirect3D9 *pD3D, IDirect3D9Ex *pD3DEx, HWND hwnd, UINT
uAdapter)
{
HRESULT hr = S_OK;

D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.BackBufferHeight = 1;
d3dpp.BackBufferWidth = 1;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

D3DCAPS9 caps;
DWORD dwVertexProcessing;
IFC(pD3D->GetDeviceCaps(uAdapter, D3DDEVTYPE_HAL, &caps));
if ((caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) ==
D3DDEVCAPS_HWTRANSFORMANDLIGHT)
{
dwVertexProcessing = D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
else
{
dwVertexProcessing = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
if (pD3DEx)
{
IDirect3DDevice9Ex *pd3dDevice = NULL;
IFC(pD3DEx->CreateDeviceEx(
uAdapter,
D3DDEVTYPE_HAL,
hwnd,
dwVertexProcessing | D3DCREATE_MULTITHREADED |
D3DCREATE_FPU_PRESERVE,
&d3dpp,
NULL,
&m_pd3dDeviceEx
));

IFC(m_pd3dDeviceEx->QueryInterface(__uuidof(IDirect3DDevice9),
reinterpret_cast<void**>(&m_pd3dDevice)));
}
else
{
assert(pD3D);

IFC(pD3D->CreateDevice(
uAdapter,
D3DDEVTYPE_HAL,
hwnd,
dwVertexProcessing | D3DCREATE_MULTITHREADED |
D3DCREATE_FPU_PRESERVE,
&d3dpp,
&m_pd3dDevice
));
}

Cleanup:
return hr;
}

Creating the Back Buffer Render Target


To display Direct3D9 content in a D3DImage, you create a Direct3D9 surface and assign
it by calling the SetBackBuffer method.

Verifying Adapter Support


Before creating a surface, verify that all adapters support the surface properties you
require. Even if you render to only one adapter, the WPF window may be displayed on
any adapter in the system. You should always write Direct3D9 code that handles multi-
adapter configurations, and you should check all adapters for support, because WPF
might move the surface among the available adapters.
The following code example shows how to check all adapters on the system for
Direct3D9 support.

C++

HRESULT
CRendererManager::TestSurfaceSettings()
{
HRESULT hr = S_OK;

D3DFORMAT fmt = m_fUseAlpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;

//
// We test all adapters because because we potentially use all adapters.
// But even if this sample only rendered to the default adapter, you
// should check all adapters because WPF may move your surface to
// another adapter for you!
//

for (UINT i = 0; i < m_cAdapters; ++i)


{
// Can we get HW rendering?
IFC(m_pD3D->CheckDeviceType(
i,
D3DDEVTYPE_HAL,
D3DFMT_X8R8G8B8,
fmt,
TRUE
));

// Is the format okay?


IFC(m_pD3D->CheckDeviceFormat(
i,
D3DDEVTYPE_HAL,
D3DFMT_X8R8G8B8,
D3DUSAGE_RENDERTARGET | D3DUSAGE_DYNAMIC, // We'll use dynamic
when on XP
D3DRTYPE_SURFACE,
fmt
));

// D3DImage only allows multisampling on 9Ex devices. If we can't


// multisample, overwrite the desired number of samples with 0.
if (m_pD3DEx && m_uNumSamples > 1)
{
assert(m_uNumSamples <= 16);

if (FAILED(m_pD3D->CheckDeviceMultiSampleType(
i,
D3DDEVTYPE_HAL,
fmt,
TRUE,
static_cast<D3DMULTISAMPLE_TYPE>(m_uNumSamples),
NULL
)))
{
m_uNumSamples = 0;
}
}
else
{
m_uNumSamples = 0;
}
}

Cleanup:
return hr;
}

Creating the Surface


Before creating a surface, verify that the device capabilities support good performance
on the target operating system. For more information, see Performance Considerations
for Direct3D9 and WPF Interoperability.

When you have verified device capabilities, you can create the surface. The following
code example shows how to create the render target.

C++

HRESULT
CRenderer::CreateSurface(UINT uWidth, UINT uHeight, bool fUseAlpha, UINT
m_uNumSamples)
{
HRESULT hr = S_OK;

SAFE_RELEASE(m_pd3dRTS);

IFC(m_pd3dDevice->CreateRenderTarget(
uWidth,
uHeight,
fUseAlpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8,
static_cast<D3DMULTISAMPLE_TYPE>(m_uNumSamples),
0,
m_pd3dDeviceEx ? FALSE : TRUE, // Lockable RT required for good XP
perf
&m_pd3dRTS,
NULL
));

IFC(m_pd3dDevice->SetRenderTarget(0, m_pd3dRTS));

Cleanup:
return hr;
}
WDDM
On Windows Vista and later operating systems, which are configured to use the WDDM,
you can create a render target texture and pass the level 0 surface to the SetBackBuffer
method. This approach is not recommended on Windows XP, because you cannot
create a lockable render target texture and performance will be reduced.

Handling Device State


The D3DImage class manages two display buffers, which are called the back buffer and
the front buffer. The back buffer is your Direct3D surface. Changes to the back buffer are
copied forward to the front buffer when you call the Unlock method, where it is
displayed on the hardware. Occasionally, the front buffer becomes unavailable. This lack
of availability can be caused by screen locking, full-screen exclusive Direct3D
applications, user-switching, or other system activities. When this occurs, your WPF
application is notified by handling the IsFrontBufferAvailableChanged event. How your
application responds to the front buffer becoming unavailable depends on whether
WPF is enabled to fall back to software rendering. The SetBackBuffer method has an
overload that takes a parameter that specifies whether WPF falls back to software
rendering.

When you call the SetBackBuffer(D3DResourceType, IntPtr) overload or call the


SetBackBuffer(D3DResourceType, IntPtr, Boolean) overload with the
enableSoftwareFallback parameter set to false , the rendering system releases its
reference to the back buffer when the front buffer becomes unavailable and nothing is
displayed. When the front buffer is available again, the rendering system raises the
IsFrontBufferAvailableChanged event to notify your WPF application. You can create an
event handler for the IsFrontBufferAvailableChanged event to restart rendering again
with a valid Direct3D surface. To restart rendering, you must call SetBackBuffer.

When you call the SetBackBuffer(D3DResourceType, IntPtr, Boolean) overload with the
enableSoftwareFallback parameter set to true , the rendering system retains its
reference to the back buffer when the front buffer becomes unavailable, so there is no
need to call SetBackBuffer when the front buffer is available again.

When software rendering is enabled, there may be situations where the user’s device
becomes unavailable, but the rendering system retains a reference to the Direct3D
surface. To check whether a Direct3D9 device is unavailable, call the
TestCooperativeLevel method. To check a Direct3D9Ex devices call the
CheckDeviceState method, because the TestCooperativeLevel method is deprecated

and always returns success. If the user device has become unavailable, call SetBackBuffer
to release WPF’s reference to the back buffer. If you need to reset your device, call
SetBackBuffer with the backBuffer parameter set to null , and then call SetBackBuffer
again with backBuffer set to a valid Direct3D surface.

Call the Reset method to recover from an invalid device only if you implement multi-
adapter support. Otherwise, release all Direct3D9 interfaces and re-create them
completely. If the adapter layout has changed, Direct3D9 objects created before the
change are not updated.

Handling Resizing
If a D3DImage is displayed at a resolution other than its native size, it is scaled
according to the current BitmapScalingMode, except that Bilinear is substituted for Fant.

If you require higher fidelity, you must create a new surface when the container of the
D3DImage changes size.

There are three possible approaches to handle resizing.

Participate in the layout system and create a new surface when the size changes.
Do not create too many surfaces, because you may exhaust or fragment video
memory.

Wait until a resize event has not occurred for a fixed period of time to create the
new surface.

Create a DispatcherTimer that checks the container dimensions several times per
second.

Multi-monitor Optimization
Significantly reduced performance can result when the rendering system moves a
D3DImage to another monitor.

On WDDM, as long as the monitors are on the same video card and you use
Direct3DCreate9Ex , there is no reduction in performance. If the monitors are on

separate video cards, performance is reduced. On Windows XP, performance is always


reduced.
When the D3DImage moves to another monitor, you can create a new surface on the
corresponding adapter to restore good performance.

To avoid the performance penalty, write code specifically for the multi-monitor case. The
following list shows one way to write multi-monitor code.

1. Find a point of the D3DImage in screen space with the Visual.ProjectToScreen


method.

2. Use the MonitorFromPoint GDI method to find the monitor that is displaying the
point.

3. Use the IDirect3D9::GetAdapterMonitor method to find which Direct3D9 adapter


the monitor is on.

4. If the adapter is not the same as the adapter with the back buffer, create a new
back buffer on the new monitor and assign it to the D3DImage back buffer.

7 Note

If the D3DImage straddles monitors, performance will be slow, except in the case of
WDDM and IDirect3D9Ex on the same adapter. There is no way to improve
performance in this situation.

The following code example shows how to find the current monitor.

C++

void
CRendererManager::SetAdapter(POINT screenSpacePoint)
{
CleanupInvalidDevices();

//
// After CleanupInvalidDevices, we may not have any D3D objects. Rather
than
// recreate them here, ignore the adapter update and wait for render to
recreate.
//

if (m_pD3D && m_rgRenderers)


{
HMONITOR hMon = MonitorFromPoint(screenSpacePoint,
MONITOR_DEFAULTTONULL);

for (UINT i = 0; i < m_cAdapters; ++i)


{
if (hMon == m_pD3D->GetAdapterMonitor(i))
{
m_pCurrentRenderer = m_rgRenderers[i];
break;
}
}
}
}

Update the monitor when the D3DImage container's size or position changes, or update
the monitor by using a DispatcherTimer that updates a few times per second.

WPF Software Rendering


WPF renders synchronously on the UI thread in software in the following situations.

Printing

BitmapEffect

RenderTargetBitmap

When one of these situations occurs, the rendering system calls the CopyBackBuffer
method to copy the hardware buffer to software. The default implementation calls the
GetRenderTargetData method with your surface. Because this call occurs outside of the

Lock/Unlock pattern, it may fail. In this case, the CopyBackBuffer method returns null
and no image is displayed.

You can override the CopyBackBuffer method, call the base implementation, and if it
returns null , you can return a placeholder BitmapSource.

You can also implement your own software rendering instead of calling the base
implementation.

7 Note

If WPF is rendering completely in software, D3DImage is not shown because WPF


does not have a front buffer.

See also
D3DImage
Performance Considerations for Direct3D9 and WPF Interoperability
Walkthrough: Creating Direct3D9 Content for Hosting in WPF
Walkthrough: Hosting Direct3D9 Content in WPF
Performance Considerations for
Direct3D9 and WPF Interoperability
Article • 02/06/2023

You can host Direct3D9 content by using the D3DImage class. Hosting Direct3D9
content can affect the performance of your application. This topic describes best
practices to optimize performance when hosting Direct3D9 content in a Windows
Presentation Foundation (WPF) application. These best practices include how to use
D3DImage and best practices when you are using Windows Vista, Windows XP, and
multi-monitor displays.

7 Note

For code examples that demonstrate these best practices, see WPF and Direct3D9
Interoperation.

Use D3DImage Sparingly


Direct3D9 content hosted in a D3DImage instance does not render as fast as in a pure
Direct3D application. Copying the surface and flushing the command buffer can be
costly operations. As the number of D3DImage instances increases, more flushing
occurs, and performance degrades. Therefore, you should use D3DImage sparingly.

Best Practices on Windows Vista


For best performance on Windows Vista with a display that is configured to use the
Windows Display Driver Model (WDDM), create your Direct3D9 surface on an
IDirect3DDevice9Ex device. This enables surface sharing. The video card must support
the D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES and D3DCAPS2_CANSHARERESOURCE driver
capabilities on Windows Vista. Any other settings cause the surface to be copied
through software, which reduces performance significantly.

7 Note

If Windows Vista has a display that is configured to use the Windows XP Display
Driver Model (XDDM), the surface is always copied through software, regardless of
settings. With the proper settings and video card, you will see better performance
on Windows Vista when you use the WDDM because surface copies are performed
in hardware.

Best Practices on Windows XP


For best performance on Windows XP, which uses the Windows XP Display Driver Model
(XDDM), create a lockable surface that behaves correctly when the
IDirect3DSurface9::GetDC method is called. Internally, the BitBlt method transfers the
surface across devices in hardware. The GetDC method always works on XRGB surfaces.
However, if the client computer is running Windows XP with SP3 or SP2, and if the client
also has the hotfix for the layered-window feature, this method only works on ARGB
surfaces. The video card must support the D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES
driver capability.

A 16-bit desktop display depth can significantly reduce performance. A 32-bit desktop is
recommended.

If you are developing for Windows Vista and Windows XP, test the performance on
Windows XP. Running out of video memory on Windows XP is a concern. In addition,
D3DImage on Windows XP uses more video memory and bandwidth than Windows
Vista WDDM, due to a necessary extra video memory copy. Therefore, you can expect
performance to be worse on Windows XP than on Windows Vista for the same video
hardware.

7 Note

XDDM is available on both Windows XP and Windows Vista; however, WDDM is


available only on Windows Vista.

General Best Practices


When you create the device, use the D3DCREATE_MULTITHREADED creation flag. This
reduces performance, but the WPF rendering system calls methods on this device from
another thread. Be sure to follow the locking protocol correctly, so that no two threads
access the device at the same time.

If your rendering is performed on a WPF managed thread, it is strongly recommended


that you create the device with the D3DCREATE_FPU_PRESERVE creation flag. Without this
setting, the D3D rendering can reduce the accuracy of WPF double-precision operations
and introduce rendering issues.

Tiling a D3DImage is fast, unless you tile a non-pow2 surface without hardware support,
or if you tile a DrawingBrush or VisualBrush that contains a D3DImage.

Best Practices for Multi-Monitor Displays


If you are using a computer that has multiple monitors, you should follow the previously
described best practices. There are also some additional performance considerations for
a multi-monitor configuration.

When you create the back buffer, it is created on a specific device and adapter, but WPF
may display the front buffer on any adapter. Copying across adapters to update the
front buffer can be very expensive. On Windows Vista that is configured to use the
WDDM with multiple video cards and with an IDirect3DDevice9Ex device, if the front
buffer is on a different adapter but still the same video card, there is no performance
penalty. However, on Windows XP and the XDDM with multiple video cards, there is a
significant performance penalty when the front buffer is displayed on a different adapter
than the back buffer. For more information, see WPF and Direct3D9 Interoperation.

Performance Summary
The following table shows performance of the front buffer update as a function of
operating system, pixel format, and surface lockability. The front buffer and back buffer
are assumed to be on the same adapter. Depending on the adapter configuration,
hardware updates are generally much faster than software updates.

Surface pixel Windows Vista, Other Windows Windows XP SP3 Windows


format WDDM and 9Ex Vista or SP2 w/ hotfix XP SP2
configurations

D3DFMT_X8R8G8B8 Hardware Software Update Software Update Software


(not lockable) Update Update

D3DFMT_X8R8G8B8 Hardware Software Update Hardware Update Hardware


(lockable) Update Update

D3DFMT_A8R8G8B8 Hardware Software Update Software Update Software


(not lockable) Update Update

D3DFMT_A8R8G8B8 Hardware Software Update Hardware Update Software


(lockable) Update Update
See also
D3DImage
WPF and Direct3D9 Interoperation
Walkthrough: Creating Direct3D9 Content for Hosting in WPF
Walkthrough: Hosting Direct3D9 Content in WPF
Walkthrough: Creating Direct3D9
Content for Hosting in WPF
Article • 02/06/2023

This walkthrough shows how to create Direct3D9 content that is suitable for hosting in a
Windows Presentation Foundation (WPF) application. For more information on hosting
Direct3D9 content in WPF applications, see WPF and Direct3D9 Interoperation.

In this walkthrough, you perform the following tasks:

Create a Direct3D9 project.

Configure the Direct3D9 project for hosting in a WPF application.

When you are finished, you will have a DLL that contains Direct3D9 content for use in a
WPF application.

Prerequisites
You need the following components to complete this walkthrough:

Visual Studio 2010.

DirectX SDK 9 or later.

Creating the Direct3D9 Project


The first step is to create and configure the Direct3D9 project.

To create the Direct3D9 project


1. Create a new Win32 Project in C++ named D3DContent .

The Win32 Application Wizard opens and displays the Welcome screen.

2. Click Next.

The Application Settings screen appears.

3. In the Application type: section, select the DLL option.

4. Click Finish.
The D3DContent project is generated.

5. In Solution Explorer, right-click the D3DContent project and select Properties.

The D3DContent Property Pages dialog box opens.

6. Select the C/C++ node.

7. In the Additional Include Directories field, specify the location of the DirectX
include folder. The default location for this folder is %ProgramFiles%\Microsoft
DirectX SDK (version)\Include.

8. Double-click the Linker node to expand it.

9. In the Additional Library Directories field, specify the location of the DirectX
libraries folder. The default location for this folder is %ProgramFiles%\Microsoft
DirectX SDK (version)\Lib\x86.

10. Select the Input node.

11. In the Additional Dependencies field, add the d3d9.lib and d3dx9.lib files.

12. In Solution Explorer, add a new module definition file (.def) named D3DContent.def
to the project.

Creating the Direct3D9 Content


To get the best performance, your Direct3D9 content must use particular settings. The
following code shows how to create a Direct3D9 surface that has the best performance
characteristics. For more information, see Performance Considerations for Direct3D9 and
WPF Interoperability.

To create the Direct3D9 content


1. Using Solution Explorer, add three C++ classes to the project named the following.

CRenderer (with virtual destructor)

CRendererManager

CTriangleRenderer

2. Open Renderer.h in the Code Editor and replace the automatically generated code
with the following code.
C++

#pragma once

class CRenderer
{
public:
virtual ~CRenderer();

HRESULT CheckDeviceState();
HRESULT CreateSurface(UINT uWidth, UINT uHeight, bool fUseAlpha,
UINT m_uNumSamples);

virtual HRESULT Render() = 0;

IDirect3DSurface9 *GetSurfaceNoRef() { return m_pd3dRTS; }

protected:
CRenderer();

virtual HRESULT Init(IDirect3D9 *pD3D, IDirect3D9Ex *pD3DEx, HWND


hwnd, UINT uAdapter);

IDirect3DDevice9 *m_pd3dDevice;
IDirect3DDevice9Ex *m_pd3dDeviceEx;

IDirect3DSurface9 *m_pd3dRTS;

};

3. Open Renderer.cpp in the Code Editor and replace the automatically generated
code with the following code.

C++

//+--------------------------------------------------------------------
---------
//
// CRenderer
//
// An abstract base class that creates a device and a target
render
// surface. Derive from this class and override Init() and
Render()
// to do your own rendering. See CTriangleRenderer for an example.

//---------------------------------------------------------------------
---------

#include "StdAfx.h"
//+--------------------------------------------------------------------
---------
//
// Member:
// CRenderer ctor
//
//---------------------------------------------------------------------
---------
CRenderer::CRenderer() : m_pd3dDevice(NULL), m_pd3dDeviceEx(NULL),
m_pd3dRTS(NULL)
{
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRenderer dtor
//
//---------------------------------------------------------------------
---------
CRenderer::~CRenderer()
{
SAFE_RELEASE(m_pd3dDevice);
SAFE_RELEASE(m_pd3dDeviceEx);
SAFE_RELEASE(m_pd3dRTS);
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRenderer::CheckDeviceState
//
// Synopsis:
// Returns the status of the device. 9Ex devices are a special
case because
// TestCooperativeLevel() has been deprecated in 9Ex.
//
//---------------------------------------------------------------------
---------
HRESULT
CRenderer::CheckDeviceState()
{
if (m_pd3dDeviceEx)
{
return m_pd3dDeviceEx->CheckDeviceState(NULL);
}
else if (m_pd3dDevice)
{
return m_pd3dDevice->TestCooperativeLevel();
}
else
{
return D3DERR_DEVICELOST;
}
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRenderer::CreateSurface
//
// Synopsis:
// Creates and sets the render target
//
//---------------------------------------------------------------------
---------
HRESULT
CRenderer::CreateSurface(UINT uWidth, UINT uHeight, bool fUseAlpha,
UINT m_uNumSamples)
{
HRESULT hr = S_OK;

SAFE_RELEASE(m_pd3dRTS);

IFC(m_pd3dDevice->CreateRenderTarget(
uWidth,
uHeight,
fUseAlpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8,
static_cast<D3DMULTISAMPLE_TYPE>(m_uNumSamples),
0,
m_pd3dDeviceEx ? FALSE : TRUE, // Lockable RT required for
good XP perf
&m_pd3dRTS,
NULL
));

IFC(m_pd3dDevice->SetRenderTarget(0, m_pd3dRTS));

Cleanup:
return hr;
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRenderer::Init
//
// Synopsis:
// Creates the device
//
//---------------------------------------------------------------------
---------
HRESULT
CRenderer::Init(IDirect3D9 *pD3D, IDirect3D9Ex *pD3DEx, HWND hwnd, UINT
uAdapter)
{
HRESULT hr = S_OK;

D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.BackBufferHeight = 1;
d3dpp.BackBufferWidth = 1;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

D3DCAPS9 caps;
DWORD dwVertexProcessing;
IFC(pD3D->GetDeviceCaps(uAdapter, D3DDEVTYPE_HAL, &caps));
if ((caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) ==
D3DDEVCAPS_HWTRANSFORMANDLIGHT)
{
dwVertexProcessing = D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
else
{
dwVertexProcessing = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}

if (pD3DEx)
{
IDirect3DDevice9Ex *pd3dDevice = NULL;
IFC(pD3DEx->CreateDeviceEx(
uAdapter,
D3DDEVTYPE_HAL,
hwnd,
dwVertexProcessing | D3DCREATE_MULTITHREADED |
D3DCREATE_FPU_PRESERVE,
&d3dpp,
NULL,
&m_pd3dDeviceEx
));

IFC(m_pd3dDeviceEx->QueryInterface(__uuidof(IDirect3DDevice9),
reinterpret_cast<void**>(&m_pd3dDevice)));
}
else
{
assert(pD3D);

IFC(pD3D->CreateDevice(
uAdapter,
D3DDEVTYPE_HAL,
hwnd,
dwVertexProcessing | D3DCREATE_MULTITHREADED |
D3DCREATE_FPU_PRESERVE,
&d3dpp,
&m_pd3dDevice
));
}
Cleanup:
return hr;
}

4. Open RendererManager.h in the Code Editor and replace the automatically


generated code with the following code.

C++

#pragma once

class CRenderer;

class CRendererManager
{
public:
static HRESULT Create(CRendererManager **ppManager);
~CRendererManager();

HRESULT EnsureDevices();

void SetSize(UINT uWidth, UINT uHeight);


void SetAlpha(bool fUseAlpha);
void SetNumDesiredSamples(UINT uNumSamples);
void SetAdapter(POINT screenSpacePoint);

HRESULT GetBackBufferNoRef(IDirect3DSurface9 **ppSurface);

HRESULT Render();

private:
CRendererManager();

void CleanupInvalidDevices();
HRESULT EnsureRenderers();
HRESULT EnsureHWND();
HRESULT EnsureD3DObjects();
HRESULT TestSurfaceSettings();
void DestroyResources();

IDirect3D9 *m_pD3D;
IDirect3D9Ex *m_pD3DEx;

UINT m_cAdapters;
CRenderer **m_rgRenderers;
CRenderer *m_pCurrentRenderer;

HWND m_hwnd;

UINT m_uWidth;
UINT m_uHeight;
UINT m_uNumSamples;
bool m_fUseAlpha;
bool m_fSurfaceSettingsChanged;
};

5. Open RendererManager.cpp in the Code Editor and replace the automatically


generated code with the following code.

C++

//+--------------------------------------------------------------------
---------
//
// CRendererManager
//
// Manages the list of CRenderers. Managed code pinvokes into this
class
// and this class forwards to the appropriate CRenderer.
//
//---------------------------------------------------------------------
---------

#include "StdAfx.h"

const static TCHAR szAppName[] = TEXT("D3DImageSample");


typedef HRESULT (WINAPI *DIRECT3DCREATE9EXFUNCTION)(UINT SDKVersion,
IDirect3D9Ex**);

//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager ctor
//
//---------------------------------------------------------------------
---------
CRendererManager::CRendererManager()
:
m_pD3D(NULL),
m_pD3DEx(NULL),
m_cAdapters(0),
m_hwnd(NULL),
m_pCurrentRenderer(NULL),
m_rgRenderers(NULL),
m_uWidth(1024),
m_uHeight(1024),
m_uNumSamples(0),
m_fUseAlpha(false),
m_fSurfaceSettingsChanged(true)
{

}
//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager dtor
//
//---------------------------------------------------------------------
---------
CRendererManager::~CRendererManager()
{
DestroyResources();

if (m_hwnd)
{
DestroyWindow(m_hwnd);
UnregisterClass(szAppName, NULL);
}
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager::Create
//
// Synopsis:
// Creates the manager
//
//---------------------------------------------------------------------
---------
HRESULT
CRendererManager::Create(CRendererManager **ppManager)
{
HRESULT hr = S_OK;

*ppManager = new CRendererManager();


IFCOOM(*ppManager);

Cleanup:
return hr;
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager::EnsureRenderers
//
// Synopsis:
// Makes sure the CRenderer objects exist
//
//---------------------------------------------------------------------
---------
HRESULT
CRendererManager::EnsureRenderers()
{
HRESULT hr = S_OK;

if (!m_rgRenderers)
{
IFC(EnsureHWND());

assert(m_cAdapters);
m_rgRenderers = new CRenderer*[m_cAdapters];
IFCOOM(m_rgRenderers);
ZeroMemory(m_rgRenderers, m_cAdapters *
sizeof(m_rgRenderers[0]));

for (UINT i = 0; i < m_cAdapters; ++i)


{
IFC(CTriangleRenderer::Create(m_pD3D, m_pD3DEx, m_hwnd, i,
&m_rgRenderers[i]));
}

// Default to the default adapter


m_pCurrentRenderer = m_rgRenderers[0];
}

Cleanup:
return hr;
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager::EnsureHWND
//
// Synopsis:
// Makes sure an HWND exists if we need it
//
//---------------------------------------------------------------------
---------
HRESULT
CRendererManager::EnsureHWND()
{
HRESULT hr = S_OK;

if (!m_hwnd)
{
WNDCLASS wndclass;

wndclass.style = CS_HREDRAW | CS_VREDRAW;


wndclass.lpfnWndProc = DefWindowProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = NULL;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;

if (!RegisterClass(&wndclass))
{
IFC(E_FAIL);
}

m_hwnd = CreateWindow(szAppName,
TEXT("D3DImageSample"),
WS_OVERLAPPEDWINDOW,
0, // Initial X
0, // Initial Y
0, // Width
0, // Height
NULL,
NULL,
NULL,
NULL);
}

Cleanup:
return hr;
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager::EnsureD3DObjects
//
// Synopsis:
// Makes sure the D3D objects exist
//
//---------------------------------------------------------------------
---------
HRESULT
CRendererManager::EnsureD3DObjects()
{
HRESULT hr = S_OK;

HMODULE hD3D = NULL;


if (!m_pD3D)
{
hD3D = LoadLibrary(TEXT("d3d9.dll"));
DIRECT3DCREATE9EXFUNCTION pfnCreate9Ex =
(DIRECT3DCREATE9EXFUNCTION)GetProcAddress(hD3D, "Direct3DCreate9Ex");
if (pfnCreate9Ex)
{
IFC((*pfnCreate9Ex)(D3D_SDK_VERSION, &m_pD3DEx));
IFC(m_pD3DEx->QueryInterface(__uuidof(IDirect3D9),
reinterpret_cast<void **>(&m_pD3D)));
}
else
{
m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (!m_pD3D)
{
IFC(E_FAIL);
}
}

m_cAdapters = m_pD3D->GetAdapterCount();
}

Cleanup:
if (hD3D)
{
FreeLibrary(hD3D);
}

return hr;
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager::CleanupInvalidDevices
//
// Synopsis:
// Checks to see if any devices are bad and if so, deletes all
resources
//
// We could delete resources and wait for D3DERR_DEVICENOTRESET
and reset
// the devices, but if the device is lost because of an adapter
order
// change then our existing D3D objects would have stale adapter
// information. We'll delete everything to be safe rather than
sorry.
//
//---------------------------------------------------------------------
---------
void
CRendererManager::CleanupInvalidDevices()
{
for (UINT i = 0; i < m_cAdapters; ++i)
{
if (FAILED(m_rgRenderers[i]->CheckDeviceState()))
{
DestroyResources();
break;
}
}
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager::GetBackBufferNoRef
//
// Synopsis:
// Returns the surface of the current renderer without adding a
reference
//
// This can return NULL if we're in a bad device state.
//
//---------------------------------------------------------------------
---------
HRESULT
CRendererManager::GetBackBufferNoRef(IDirect3DSurface9 **ppSurface)
{
HRESULT hr = S_OK;

// Make sure we at least return NULL


*ppSurface = NULL;

CleanupInvalidDevices();

IFC(EnsureD3DObjects());

//
// Even if we never render to another adapter, this sample creates
devices
// and resources on each one. This is a potential waste of video
memory,
// but it guarantees that we won't have any problems (e.g. out of
video
// memory) when switching to render on another adapter. In your own
code
// you may choose to delay creation but you'll need to handle the
issues
// that come with it.
//

IFC(EnsureRenderers());

if (m_fSurfaceSettingsChanged)
{
if (FAILED(TestSurfaceSettings()))
{
IFC(E_FAIL);
}

for (UINT i = 0; i < m_cAdapters; ++i)


{
IFC(m_rgRenderers[i]->CreateSurface(m_uWidth, m_uHeight,
m_fUseAlpha, m_uNumSamples));
}

m_fSurfaceSettingsChanged = false;
}
if (m_pCurrentRenderer)
{
*ppSurface = m_pCurrentRenderer->GetSurfaceNoRef();
}

Cleanup:
// If we failed because of a bad device, ignore the failure for now
and
// we'll clean up and try again next time.
if (hr == D3DERR_DEVICELOST)
{
hr = S_OK;
}

return hr;
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager::TestSurfaceSettings
//
// Synopsis:
// Checks to see if our current surface settings are allowed on
all
// adapters.
//
//---------------------------------------------------------------------
---------
HRESULT
CRendererManager::TestSurfaceSettings()
{
HRESULT hr = S_OK;

D3DFORMAT fmt = m_fUseAlpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;

//
// We test all adapters because because we potentially use all
adapters.
// But even if this sample only rendered to the default adapter,
you
// should check all adapters because WPF may move your surface to
// another adapter for you!
//

for (UINT i = 0; i < m_cAdapters; ++i)


{
// Can we get HW rendering?
IFC(m_pD3D->CheckDeviceType(
i,
D3DDEVTYPE_HAL,
D3DFMT_X8R8G8B8,
fmt,
TRUE
));

// Is the format okay?


IFC(m_pD3D->CheckDeviceFormat(
i,
D3DDEVTYPE_HAL,
D3DFMT_X8R8G8B8,
D3DUSAGE_RENDERTARGET | D3DUSAGE_DYNAMIC, // We'll use
dynamic when on XP
D3DRTYPE_SURFACE,
fmt
));

// D3DImage only allows multisampling on 9Ex devices. If we


can't
// multisample, overwrite the desired number of samples with 0.
if (m_pD3DEx && m_uNumSamples > 1)
{
assert(m_uNumSamples <= 16);

if (FAILED(m_pD3D->CheckDeviceMultiSampleType(
i,
D3DDEVTYPE_HAL,
fmt,
TRUE,
static_cast<D3DMULTISAMPLE_TYPE>(m_uNumSamples),
NULL
)))
{
m_uNumSamples = 0;
}
}
else
{
m_uNumSamples = 0;
}
}

Cleanup:
return hr;
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager::DestroyResources
//
// Synopsis:
// Delete all D3D resources
//
//---------------------------------------------------------------------
---------
void
CRendererManager::DestroyResources()
{
SAFE_RELEASE(m_pD3D);
SAFE_RELEASE(m_pD3DEx);

for (UINT i = 0; i < m_cAdapters; ++i)


{
delete m_rgRenderers[i];
}
delete [] m_rgRenderers;
m_rgRenderers = NULL;

m_pCurrentRenderer = NULL;
m_cAdapters = 0;

m_fSurfaceSettingsChanged = true;
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager::SetSize
//
// Synopsis:
// Update the size of the surface. Next render will create a new
surface.
//
//---------------------------------------------------------------------
---------
void
CRendererManager::SetSize(UINT uWidth, UINT uHeight)
{
if (uWidth != m_uWidth || uHeight != m_uHeight)
{
m_uWidth = uWidth;
m_uHeight = uHeight;
m_fSurfaceSettingsChanged = true;
}
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager::SetAlpha
//
// Synopsis:
// Update the format of the surface. Next render will create a new
surface.
//
//---------------------------------------------------------------------
---------
void
CRendererManager::SetAlpha(bool fUseAlpha)
{
if (fUseAlpha != m_fUseAlpha)
{
m_fUseAlpha = fUseAlpha;
m_fSurfaceSettingsChanged = true;
}
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager::SetNumDesiredSamples
//
// Synopsis:
// Update the MSAA settings of the surface. Next render will
create a
// new surface.
//
//---------------------------------------------------------------------
---------
void
CRendererManager::SetNumDesiredSamples(UINT uNumSamples)
{
if (m_uNumSamples != uNumSamples)
{
m_uNumSamples = uNumSamples;
m_fSurfaceSettingsChanged = true;
}
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager::SetAdapter
//
// Synopsis:
// Update the current renderer. Next render will use the new
renderer.
//
//---------------------------------------------------------------------
---------
void
CRendererManager::SetAdapter(POINT screenSpacePoint)
{
CleanupInvalidDevices();

//
// After CleanupInvalidDevices, we may not have any D3D objects.
Rather than
// recreate them here, ignore the adapter update and wait for
render to recreate.
//
if (m_pD3D && m_rgRenderers)
{
HMONITOR hMon = MonitorFromPoint(screenSpacePoint,
MONITOR_DEFAULTTONULL);

for (UINT i = 0; i < m_cAdapters; ++i)


{
if (hMon == m_pD3D->GetAdapterMonitor(i))
{
m_pCurrentRenderer = m_rgRenderers[i];
break;
}
}
}
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager::Render
//
// Synopsis:
// Forward to the current renderer
//
//---------------------------------------------------------------------
---------
HRESULT
CRendererManager::Render()
{
return m_pCurrentRenderer ? m_pCurrentRenderer->Render() : S_OK;
}

6. Open TriangleRenderer.h in the Code Editor and replace the automatically


generated code with the following code.

C++

#pragma once

class CTriangleRenderer : public CRenderer


{
public:
static HRESULT Create(IDirect3D9 *pD3D, IDirect3D9Ex *pD3DEx, HWND
hwnd, UINT uAdapter, CRenderer **ppRenderer);
~CTriangleRenderer();

HRESULT Render();

protected:
HRESULT Init(IDirect3D9 *pD3D, IDirect3D9Ex *pD3DEx, HWND hwnd,
UINT uAdapter);
private:
CTriangleRenderer();

IDirect3DVertexBuffer9 *m_pd3dVB;
};

7. Open TriangleRenderer.cpp in the Code Editor and replace the automatically


generated code with the following code.

C++

//+--------------------------------------------------------------------
---------
//
// CTriangleRenderer
//
// Subclass of CRenderer that renders a single, spinning triangle
//
//---------------------------------------------------------------------
---------

#include "StdAfx.h"

struct CUSTOMVERTEX
{
FLOAT x, y, z;
DWORD color;
};

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)

//+--------------------------------------------------------------------
---------
//
// Member:
// CTriangleRenderer ctor
//
//---------------------------------------------------------------------
---------
CTriangleRenderer::CTriangleRenderer() : CRenderer(), m_pd3dVB(NULL)
{
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CTriangleRenderer dtor
//
//---------------------------------------------------------------------
---------
CTriangleRenderer::~CTriangleRenderer()
{
SAFE_RELEASE(m_pd3dVB);
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CTriangleRenderer::Create
//
// Synopsis:
// Creates the renderer
//
//---------------------------------------------------------------------
---------
HRESULT
CTriangleRenderer::Create(IDirect3D9 *pD3D, IDirect3D9Ex *pD3DEx, HWND
hwnd, UINT uAdapter, CRenderer **ppRenderer)
{
HRESULT hr = S_OK;

CTriangleRenderer *pRenderer = new CTriangleRenderer();


IFCOOM(pRenderer);

IFC(pRenderer->Init(pD3D, pD3DEx, hwnd, uAdapter));

*ppRenderer = pRenderer;
pRenderer = NULL;

Cleanup:
delete pRenderer;

return hr;
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CTriangleRenderer::Init
//
// Synopsis:
// Override of CRenderer::Init that calls base to create the
device and
// then creates the CTriangleRenderer-specific resources
//
//---------------------------------------------------------------------
---------
HRESULT
CTriangleRenderer::Init(IDirect3D9 *pD3D, IDirect3D9Ex *pD3DEx, HWND
hwnd, UINT uAdapter)
{
HRESULT hr = S_OK;
D3DXMATRIXA16 matView, matProj;
D3DXVECTOR3 vEyePt(0.0f, 0.0f,-5.0f);
D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);

// Call base to create the device and render target


IFC(CRenderer::Init(pD3D, pD3DEx, hwnd, uAdapter));

// Set up the VB
CUSTOMVERTEX vertices[] =
{
{ -1.0f, -1.0f, 0.0f, 0xffff0000, }, // x, y, z, color
{ 1.0f, -1.0f, 0.0f, 0xff00ff00, },
{ 0.0f, 1.0f, 0.0f, 0xff00ffff, },
};

IFC(m_pd3dDevice->CreateVertexBuffer(sizeof(vertices), 0,
D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &m_pd3dVB, NULL));

void *pVertices;
IFC(m_pd3dVB->Lock(0, sizeof(vertices), &pVertices, 0));
memcpy(pVertices, vertices, sizeof(vertices));
m_pd3dVB->Unlock();

// Set up the camera


D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
IFC(m_pd3dDevice->SetTransform(D3DTS_VIEW, &matView));
D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, 1.0f, 1.0f,
100.0f);
IFC(m_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj));

// Set up the global state


IFC(m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE));
IFC(m_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE));
IFC(m_pd3dDevice->SetStreamSource(0, m_pd3dVB, 0,
sizeof(CUSTOMVERTEX)));
IFC(m_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX));

Cleanup:
return hr;
}

//+--------------------------------------------------------------------
---------
//
// Member:
// CTriangleRenderer::Render
//
// Synopsis:
// Renders the rotating triangle
//
//---------------------------------------------------------------------
---------
HRESULT
CTriangleRenderer::Render()
{
HRESULT hr = S_OK;
D3DXMATRIXA16 matWorld;

IFC(m_pd3dDevice->BeginScene());
IFC(m_pd3dDevice->Clear(
0,
NULL,
D3DCLEAR_TARGET,
D3DCOLOR_ARGB(128, 0, 0, 128), // NOTE: Premultiplied alpha!
1.0f,
0
));

// Set up the rotation


UINT iTime = GetTickCount() % 1000;
FLOAT fAngle = iTime * (2.0f * D3DX_PI) / 1000.0f;
D3DXMatrixRotationY(&matWorld, fAngle);
IFC(m_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld));

IFC(m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1));

IFC(m_pd3dDevice->EndScene());

Cleanup:
return hr;
}

8. Open stdafx.h in the Code Editor and replace the automatically generated code
with the following code.

C++

// stdafx.h : include file for standard system include files,


// or project specific include files that are used frequently, but
// are changed infrequently
//

#pragma once

#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff


from Windows headers
// Windows Header Files:
#include <windows.h>

#include <d3d9.h>
#include <d3dx9.h>

#include <assert.h>

#include "RendererManager.h"
#include "Renderer.h"
#include "TriangleRenderer.h"

#define IFC(x) { hr = (x); if (FAILED(hr)) goto Cleanup; }


#define IFCOOM(x) { if ((x) == NULL) { hr = E_OUTOFMEMORY; IFC(hr); } }
#define SAFE_RELEASE(x) { if (x) { x->Release(); x = NULL; } }

9. Open dllmain.cpp in the Code Editor and replace the automatically generated code
with the following code.

C++

// dllmain.cpp : Defines the entry point for the DLL application.


#include "stdafx.h"

BOOL APIENTRY DllMain( HMODULE hModule,


DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

static CRendererManager *pManager = NULL;

static HRESULT EnsureRendererManager()


{
return pManager ? S_OK : CRendererManager::Create(&pManager);
}

extern "C" HRESULT WINAPI SetSize(UINT uWidth, UINT uHeight)


{
HRESULT hr = S_OK;

IFC(EnsureRendererManager());

pManager->SetSize(uWidth, uHeight);

Cleanup:
return hr;
}

extern "C" HRESULT WINAPI SetAlpha(BOOL fUseAlpha)


{
HRESULT hr = S_OK;

IFC(EnsureRendererManager());
pManager->SetAlpha(!!fUseAlpha);

Cleanup:
return hr;
}

extern "C" HRESULT WINAPI SetNumDesiredSamples(UINT uNumSamples)


{
HRESULT hr = S_OK;

IFC(EnsureRendererManager());

pManager->SetNumDesiredSamples(uNumSamples);

Cleanup:
return hr;
}

extern "C" HRESULT WINAPI SetAdapter(POINT screenSpacePoint)


{
HRESULT hr = S_OK;

IFC(EnsureRendererManager());

pManager->SetAdapter(screenSpacePoint);

Cleanup:
return hr;
}

extern "C" HRESULT WINAPI GetBackBufferNoRef(IDirect3DSurface9


**ppSurface)
{
HRESULT hr = S_OK;

IFC(EnsureRendererManager());

IFC(pManager->GetBackBufferNoRef(ppSurface));

Cleanup:
return hr;
}

extern "C" HRESULT WINAPI Render()


{
assert(pManager);

return pManager->Render();
}

extern "C" void WINAPI Destroy()


{
delete pManager;
pManager = NULL;
}
10. Open D3DContent.def in the code editor.

11. Replace the automatically generated code with the following code.

C++

LIBRARY "D3DContent"

EXPORTS

SetSize
SetAlpha
SetNumDesiredSamples
SetAdapter

GetBackBufferNoRef
Render
Destroy

12. Build the project.

Next Steps
Host the Direct3D9 content in a WPF application. For more information, see
Walkthrough: Hosting Direct3D9 Content in WPF.

See also
D3DImage
Performance Considerations for Direct3D9 and WPF Interoperability
Walkthrough: Hosting Direct3D9 Content in WPF
Walkthrough: Hosting Direct3D9
Content in WPF
Article • 08/18/2022

This walkthrough shows how to host Direct3D9 content in a Windows Presentation


Foundation (WPF) application.

In this walkthrough, you perform the following tasks:

Create a WPF project to host the Direct3D9 content.

Import the Direct3D9 content.

Display the Direct3D9 content by using the D3DImage class.

When you are finished, you will know how to host Direct3D9 content in a WPF
application.

Prerequisites
You need the following components to complete this walkthrough:

Visual Studio.

DirectX SDK 9 or later.

A DLL that contains Direct3D9 content in a WPF-compatible format. For more


information, see WPF and Direct3D9 Interoperation and Walkthrough: Creating
Direct3D9 Content for Hosting in WPF.

Creating the WPF Project


The first step is to create the project for the WPF application.

To create the WPF project


Create a new WPF Application project in Visual C# named D3DHost . For more
information, see Walkthrough: My first WPF desktop application.

MainWindow.xaml opens in the WPF Designer.


Importing the Direct3D9 Content
You import the Direct3D9 content from an unmanaged DLL by using the DllImport
attribute.

To import Direct3D9 content


1. Open MainWindow.xaml.cs in the Code Editor.

2. Replace the automatically generated code with the following code.

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Runtime.InteropServices;
using System.Security.Permissions;

namespace D3DHost
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

// Set up the initial state for the D3DImage.


HRESULT.Check(SetSize(512, 512));
HRESULT.Check(SetAlpha(false));
HRESULT.Check(SetNumDesiredSamples(4));

//
// Optional: Subscribing to the
IsFrontBufferAvailableChanged event.
//
// If you don't render every frame (e.g. you only render in
// reaction to a button click), you should subscribe to the
// IsFrontBufferAvailableChanged event to be notified when
rendered content
// is no longer being displayed. This event also notifies
you when
// the D3DImage is capable of being displayed again.

// For example, in the button click case, if you don't


render again when
// the IsFrontBufferAvailable property is set to true, your
// D3DImage won't display anything until the next button
click.
//
// Because this application renders every frame, there is
no need to
// handle the IsFrontBufferAvailableChanged event.
//
CompositionTarget.Rendering += new
EventHandler(CompositionTarget_Rendering);

//
// Optional: Multi-adapter optimization
//
// The surface is created initially on a particular
adapter.
// If the WPF window is dragged to another adapter, WPF
// ensures that the D3DImage still shows up on the new
// adapter.
//
// This process is slow on Windows XP.
//
// Performance is better on Vista with a 9Ex device. It's
only
// slow when the D3DImage crosses a video-card boundary.
//
// To work around this issue, you can move your surface
when
// the D3DImage is displayed on another adapter. To
// determine when that is the case, transform a point on
the
// D3DImage into screen space and find out which adapter
// contains that screen space point.
//
// When your D3DImage straddles two adapters, nothing
// can be done, because one will be updating slowly.
//
_adapterTimer = new DispatcherTimer();
_adapterTimer.Tick += new EventHandler(AdapterTimer_Tick);
_adapterTimer.Interval = new TimeSpan(0, 0, 0, 0, 500);
_adapterTimer.Start();

//
// Optional: Surface resizing
//
// The D3DImage is scaled when WPF renders it at a size
// different from the natural size of the surface. If the
// D3DImage is scaled up significantly, image quality
// degrades.
//
// To avoid this, you can either create a very large
// texture initially, or you can create new surfaces as
// the size changes. Below is a very simple example of
// how to do the latter.
//
// By creating a timer at Render priority, you are
guaranteed
// that new surfaces are created while the element
// is still being arranged. A 200 ms interval gives
// a good balance between image quality and performance.
// You must be careful not to create new surfaces too
// frequently. Frequently allocating a new surface may
// fragment or exhaust video memory. This issue is more
// significant on XDDM than it is on WDDM, because WDDM
// can page out video memory.
//
// Another approach is deriving from the Image class,
// participating in layout by overriding the
ArrangeOverride method, and
// updating size in the overriden method. Performance will
degrade
// if you resize too frequently.
//
// Blurry D3DImages can still occur due to subpixel
// alignments.
//
_sizeTimer = new
DispatcherTimer(DispatcherPriority.Render);
_sizeTimer.Tick += new EventHandler(SizeTimer_Tick);
_sizeTimer.Interval = new TimeSpan(0, 0, 0, 0, 200);
_sizeTimer.Start();
}

~MainWindow()
{
Destroy();
}

void AdapterTimer_Tick(object sender, EventArgs e)


{
POINT p = new POINT(imgelt.PointToScreen(new Point(0, 0)));

HRESULT.Check(SetAdapter(p));
}

void SizeTimer_Tick(object sender, EventArgs e)


{
// The following code does not account for
RenderTransforms.
// To handle that case, you must transform up to the root
and
// check the size there.
// Given that the D3DImage is at 96.0 DPI, its Width and
Height
// properties will always be integers. ActualWidth/Height
// may not be integers, so they are cast to integers.
uint actualWidth = (uint)imgelt.ActualWidth;
uint actualHeight = (uint)imgelt.ActualHeight;
if ((actualWidth > 0 && actualHeight > 0) &&
(actualWidth != (uint)d3dimg.Width || actualHeight !=
(uint)d3dimg.Height))
{
HRESULT.Check(SetSize(actualWidth, actualHeight));
}
}

void CompositionTarget_Rendering(object sender, EventArgs e)


{
RenderingEventArgs args = (RenderingEventArgs)e;

// It's possible for Rendering to call back twice in the


same frame
// so only render when we haven't already rendered in this
frame.
if (d3dimg.IsFrontBufferAvailable && _lastRender !=
args.RenderingTime)
{
IntPtr pSurface = IntPtr.Zero;
HRESULT.Check(GetBackBufferNoRef(out pSurface));
if (pSurface != IntPtr.Zero)
{
d3dimg.Lock();
// Repeatedly calling SetBackBuffer with the same
IntPtr is
// a no-op. There is no performance penalty.

d3dimg.SetBackBuffer(D3DResourceType.IDirect3DSurface9, pSurface);
HRESULT.Check(Render());
d3dimg.AddDirtyRect(new Int32Rect(0, 0,
d3dimg.PixelWidth, d3dimg.PixelHeight));
d3dimg.Unlock();

_lastRender = args.RenderingTime;
}
}
}

DispatcherTimer _sizeTimer;
DispatcherTimer _adapterTimer;
TimeSpan _lastRender;

// Import the methods exported by the unmanaged Direct3D


content.

[DllImport("D3DCode.dll")]
static extern int GetBackBufferNoRef(out IntPtr pSurface);
[DllImport("D3DCode.dll")]
static extern int SetSize(uint width, uint height);

[DllImport("D3DCode.dll")]
static extern int SetAlpha(bool useAlpha);

[DllImport("D3DCode.dll")]
static extern int SetNumDesiredSamples(uint numSamples);

[StructLayout(LayoutKind.Sequential)]
struct POINT
{
public POINT(Point p)
{
x = (int)p.X;
y = (int)p.Y;
}

public int x;
public int y;
}

[DllImport("D3DCode.dll")]
static extern int SetAdapter(POINT screenSpacePoint);

[DllImport("D3DCode.dll")]
static extern int Render();

[DllImport("D3DCode.dll")]
static extern void Destroy();
}

public static class HRESULT


{
public static void Check(int hr)
{
Marshal.ThrowExceptionForHR(hr);
}
}
}

Hosting the Direct3D9 Content


Finally, use the D3DImage class to host the Direct3D9 content.

To host the Direct3D9 content


1. In MainWindow.xaml, replace the automatically generated XAML with the
following XAML.
XAML

<Window x:Class="D3DHost.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-
namespace:System.Windows.Interop;assembly=PresentationCore"
Title="MainWindow" Height="300" Width="300"
Background="PaleGoldenrod">
<Grid>
<Image x:Name="imgelt">
<Image.Source>
<i:D3DImage x:Name="d3dimg" />
</Image.Source>
</Image>
</Grid>
</Window>

2. Build the project.

3. Copy the DLL that contains the Direct3D9 content to the bin/Debug folder.

4. Press F5 to run the project.

The Direct3D9 content appears within the WPF application.

See also
D3DImage
Performance Considerations for Direct3D9 and WPF Interoperability
Performance
Article • 08/10/2023

Achieving optimal application performance requires forethought in application design


and an understanding of best practices for Windows Presentation Foundation (WPF)
application development. The topics in this section provide additional information on
building high performance WPF applications.

In This Section
Graphics Rendering Tiers
Optimizing WPF Application Performance
Walkthrough: Caching Application Data in a WPF Application

Reference
RenderCapability

Tier

PresentationTraceSources

See also
Layout
Animation Tips and Tricks
Graphics Rendering Tiers
Article • 08/04/2022

A rendering tier defines a level of graphics hardware capability and performance for a
device that runs a WPF application.

Graphics Hardware
The features of the graphics hardware that most impact the rendering tier levels are:

Video RAM The amount of video memory on the graphics hardware determines
the size and number of buffers that can be used for compositing graphics.

Pixel Shader A pixel shader is a graphics processing function that calculates effects
on a per-pixel basis. Depending on the resolution of the displayed graphics, there
could be several million pixels that need to be processed for each display frame.

Vertex Shader A vertex shader is a graphics processing function that performs


mathematical operations on the vertex data of the object.

Multitexture Support Multitexture support refers to the ability to apply two or


more distinct textures during a blending operation on a 3D graphics object. The
degree of multitexture support is determined by the number of multitexture units
on the graphics hardware.

Rendering Tier Definitions


The features of the graphics hardware determine the rendering capability of a WPF
application. The WPF system defines three rendering tiers:

Rendering Tier 0 No graphics hardware acceleration. All graphics features use


software acceleration. The DirectX version level is less than version 9.0.

Rendering Tier 1 Some graphics features use graphics hardware acceleration. The
DirectX version level is greater than or equal to version 9.0.

Rendering Tier 2 Most graphics features use graphics hardware acceleration. The
DirectX version level is greater than or equal to version 9.0.

The RenderCapability.Tier property allows you to retrieve the rendering tier at


application run time. You use the rendering tier to determine whether the device
supports certain hardware-accelerated graphics features. Your application can then take
different code paths at run time depending on the rendering tier supported by the
device.

Rendering Tier 0
A rendering tier value of 0 means that there is no graphics hardware acceleration
available for the application on the device. At this tier level, you should assume that all
graphics will be rendered by software with no hardware acceleration. This tier's
functionality corresponds to a DirectX version that is less than 9.0.

Rendering Tier 1 and Rendering Tier 2

7 Note

Starting in the .NET Framework 4, rendering tier 1 has been redefined to only
include graphics hardware that supports DirectX 9.0 or greater. Graphics hardware
that supports DirectX 7 or 8 is now defined as rendering tier 0.

A rendering tier value of 1 or 2 means that most of the graphics features of WPF will use
hardware acceleration if the necessary system resources are available and have not been
exhausted. This corresponds to a DirectX version that is greater than or equal to 9.0.

The following table shows the differences in graphics hardware requirements for
rendering tier 1 and rendering tier 2:

Feature Tier 1 Tier 2

DirectX Must be greater than or equal to 9.0. Must be greater than or equal to 9.0.
version

Video RAM Must be greater than or equal to 60 Must be greater than or equal to 120
MB. MB.

Pixel shader Version level must greater than or Version level must greater than or equal
equal to 2.0. to 2.0.

Vertex shader No requirement. Version level must greater than or equal


to 2.0.

Multitexture No requirement. Number of units must greater than or


units equal to 4.

The following features and capabilities are hardware accelerated for rendering tier 1 and
rendering tier 2:
Feature Notes

2D Most 2D rendering is supported.


rendering

3D Most 3D rasterization is supported.


rasterization

3D WPF attempts to use anisotropic filtering when rendering 3D content. Anisotropic


anisotropic filtering refers to enhancing the image quality of textures on surfaces that are far
filtering away and steeply angled with respect to the camera.

3D MIP WPF attempts to use MIP mapping when rendering 3D content. MIP mapping
mapping improves the quality of texture rendering when a texture occupies a smaller field of
view in a Viewport3D.

Radial While supported, avoid the use of RadialGradientBrush on large objects.


gradients

3D lighting WPF performs per-vertex lighting, which means that a light intensity must be
calculations calculated at each vertex for each material applied to a mesh.

Text Subpixel font rendering uses available pixel shaders on the graphics hardware.
rendering

The following features and capabilities are hardware accelerated only for rendering tier
2:

Feature Notes

3D anti- 3D anti-aliasing is supported only on operating systems that support Windows Display
aliasing Driver Model (WDDM), such as Windows Vista and Windows 7.

The following features and capabilities are not hardware accelerated:

Feature Notes

Printed content All printed content is rendered using the WPF software pipeline.

Rasterized content Any content rendered by using the Render method of RenderTargetBitmap.
that uses
RenderTargetBitmap

Tiled content that Any tiled content in which the TileMode property of the TileBrush is set to
uses TileBrush Tile.
Feature Notes

Surfaces that For most graphics hardware, large surfaces are 2048x2048 or 4096x4096
exceed the pixels in size.
maximum texture
size of the graphics
hardware

Any operation You can monitor application video RAM usage by using the Perforator tool
whose video RAM that is included in the WPF Performance Suite in the Windows SDK.
requirement
exceeds the
memory of the
graphics hardware

Layered windows Layered windows allow WPF applications to render content to the screen in
a non-rectangular window. On operating systems that support Windows
Display Driver Model (WDDM), such as Windows Vista and Windows 7,
layered windows are hardware accelerated. On other systems, such as
Windows XP, layered windows are rendered by software with no hardware
acceleration.

You can enable layered windows in WPF by setting the following Window
properties:

- WindowStyle = None
- AllowsTransparency = true
- Background = Transparent

Other Resources
The following resources can help you analyze the performance characteristics of your
WPF application.

Graphics Rendering Registry Settings


WPF provides four registry settings for controlling WPF rendering:

Setting Description

Disable Hardware Specifies whether hardware acceleration should be enabled.


Acceleration Option

Maximum Multisample Specifies the degree of multisampling for antialiasing 3D content.


Value
Setting Description

Required Video Driver Specifies whether the system disables hardware acceleration for
Date Setting drivers released before November 2004.

Use Reference Rasterizer Specifies whether WPF should use the reference rasterizer.
Option

These settings can be accessed by any external configuration utility that knows how to
reference the WPF registry settings. These settings can also be created or modified by
accessing the values directly by using the Windows Registry Editor. For more
information, see Graphics Rendering Registry Settings.

WPF Performance Profiling Tools


WPF provides a suite of performance profiling tools that allow you to analyze the run-
time behavior of your application and determine the types of performance
optimizations you can apply. The following table lists the performance profiling tools
that are included in the Windows SDK tool, WPF Performance Suite:

Tool Description

Perforator Use for analyzing rendering behavior.

Visual Use for profiling the use of WPF services, such as layout and event handling, by
Profiler elements in the visual tree.

The WPF Performance Suite provides a rich, graphical view of performance data. For
more information about WPF performance tools, see WPF Performance Suite.

DirectX Diagnostic Tool


The DirectX Diagnostic Tool, Dxdiag.exe, is designed to help you troubleshoot DirectX-
related issues. The default installation folder for the DirectX Diagnostic Tool is:

~\Windows\System32

When you run the DirectX Diagnostic Tool, the main window contains a set of tabs that
allow you to display and diagnose DirectX-related information. For example, the System
tab provides system information about your computer and specifies the version of
DirectX that is installed on your computer.
DirectX Diagnostic Tool main window

See also
RenderCapability
RenderOptions
Optimizing WPF Application Performance
WPF Performance Suite
Graphics Rendering Registry Settings
Animation Tips and Tricks
Optimizing WPF Application
Performance
Article • 08/10/2023

This section is intended as a reference for Windows Presentation Foundation (WPF)


application developers who are looking for ways to improve the performance of their
applications. If you are a developer who is new to the Microsoft .NET Framework and
WPF, you should first familiarize yourself with both platforms. This section assumes
working knowledge of both, and is written for programmers who already know enough
to get their applications up and running.

7 Note

The performance data provided in this section are based on WPF applications
running on a 2.8 GHz PC with 512 RAM and an ATI Radeon 9700 graphics card.

In This Section
Planning for Application Performance

Taking Advantage of Hardware

Layout and Design

2D Graphics and Imaging

Object Behavior

Application Resources

Text

Data Binding

Controls

Other Performance Recommendations

Application Startup Time

See also
RenderOptions
RenderCapability
Graphics Rendering Tiers
WPF Graphics Rendering Overview
Layout
Trees in WPF
Drawing Objects Overview
Using DrawingVisual Objects
Dependency Properties Overview
Freezable Objects Overview
XAML Resources
Documents in WPF
Drawing Formatted Text
Typography in WPF
Data Binding Overview
Navigation Overview
Animation Tips and Tricks
Walkthrough: Caching Application Data in a WPF Application
Planning for Application Performance
Article • 02/06/2023

The success of achieving your performance goals depends on how well you develop
your performance strategy. Planning is the first stage in developing any product. This
topic describes a few very simple rules for developing a good performance strategy.

Think in Terms of Scenarios


Scenarios can help you focus on the critical components of your application. Scenarios
are generally derived from your customers, as well as competitive products. Always
study your customers and find out what really makes them excited about your product,
and your competitors' products. Your customers' feedback can help you to determine
your application's primary scenario. For instance, if you are designing a component that
will be used at startup, it is likely that the component will be called only once, when the
application starts up. Startup time becomes your key scenario. Other examples of key
scenarios could be the desired frame rate for animation sequences, or the maximum
working set allowed for the application.

Define Goals
Goals help you to determine whether an application is performing faster or slower. You
should define goals for all of your scenarios. All performance goals that you define
should be based on your customers' expectations. It may be difficult to set performance
goals early on in the application development cycle, when there are still many
unresolved issues. However, it is better to set an initial goal and revise it later than not
to have a goal at all.

Understand Your Platform


Always maintain the cycle of measuring, investigating, refining/correcting during your
application development cycle. From the beginning to the end of the development
cycle, you need to measure your application's performance in a reliable, stable
environment. You should avoid variability caused by external factors. For example, when
testing performance, you should disable anti-virus or any automatic update such as
SMS, in order not to impact performance test results. Once you have measured your
application's performance, you need to identify the changes that will result in the
biggest improvements. Once you have modified your application, start the cycle again.
Make Performance Tuning an Iterative Process
You should know the relative cost of each feature you will use. For example, the use of
reflection in Microsoft .NET Framework is generally performance intensive in terms of
computing resources, so you would want to use it judiciously. This does not mean to
avoid the use of reflection, only that you should be careful to balance the performance
requirements of your application with the performance demands of the features you
use.

Build Towards Graphical Richness


A key technique for creating a scalable approach towards achieving WPF application
performance is to build towards graphical richness and complexity. Always start with
using the least performance intensive resources to achieve your scenario goals. Once
you achieve these goals, build towards graphic richness by using more performance
intensive features, always keeping your scenario goals in mind. Remember, WPF is a very
rich platform and provides very rich graphic features. Using performance intensive
features without thinking can negatively impact your overall application performance.

WPF controls are inherently extensible by allowing for wide-spread customization of


their appearance, while not altering their control behavior. By taking advantage of styles,
data templates, and control templates, you can create and incrementally evolve a
customizable user interface (UI) that adapts to your performance requirements.

See also
Optimizing WPF Application Performance
Taking Advantage of Hardware
Layout and Design
2D Graphics and Imaging
Object Behavior
Application Resources
Text
Data Binding
Other Performance Recommendations
Optimizing Performance: Taking
Advantage of Hardware
Article • 02/06/2023

The internal architecture of WPF has two rendering pipelines, hardware and software.
This topic provides information about these rendering pipelines to help you make
decisions about performance optimizations of your applications.

Hardware Rendering Pipeline


One of the most important factors in determining WPF performance is that it is render
bound—the more pixels you have to render, the greater the performance cost. However,
the more rendering that can be offloaded to the graphics processing unit (GPU), the
more performance benefits you can gain. The WPF application hardware rendering
pipeline takes full advantage of Microsoft DirectX features on hardware that supports a
minimum of Microsoft DirectX version 7.0. Further optimizations can be gained by
hardware that supports Microsoft DirectX version 7.0 and PixelShader 2.0+ features.

Software Rendering Pipeline


The WPF software rendering pipeline is entirely CPU bound. WPF takes advantage of the
SSE and SSE2 instruction sets in the CPU to implement an optimized, fully-featured
software rasterizer. Fallback to software is seamless any time application functionality
cannot be rendered using the hardware rendering pipeline.

The biggest performance issue you will encounter when rendering in software mode is
related to fill rate, which is defined as the number of pixels that you are rendering. If you
are concerned about performance in software rendering mode, try to minimize the
number of times a pixel is redrawn. For example, if you have an application with a blue
background, which then renders a slightly transparent image over it, you will render all
of the pixels in the application twice. As a result, it will take twice as long to render the
application with the image than if you had only the blue background.

Graphics Rendering Tiers


It may be very difficult to predict the hardware configuration that your application will
be running on. However, you might want to consider a design that allows your
application to seamlessly switch features when running on different hardware, so that it
can take full advantage of each different hardware configuration.

To achieve this, WPF provides functionality to determine the graphics capability of a


system at runtime. Graphics capability is determined by categorizing the video card as
one of three rendering capability tiers. WPF exposes an API that allows an application to
query the rendering capability tier. Your application can then take different code paths
at run time depending on the rendering tier supported by the hardware.

The features of the graphics hardware that most impact the rendering tier levels are:

Video RAM The amount of video memory on the graphics hardware determines
the size and number of buffers that can be used for compositing graphics.

Pixel Shader A pixel shader is a graphics processing function that calculates effects
on a per-pixel basis. Depending on the resolution of the displayed graphics, there
could be several million pixels that need to be processed for each display frame.

Vertex Shader A vertex shader is a graphics processing function that performs


mathematical operations on the vertex data of the object.

Multitexture Support Multitexture support refers to the ability to apply two or


more distinct textures during a blending operation on a 3D graphics object. The
degree of multitexture support is determined by the number of multitexture units
on the graphics hardware.

The pixel shader, vertex shader, and multitexture features are used to define specific
DirectX version levels, which, in turn, are used to define the different rendering tiers in
WPF.

The features of the graphics hardware determine the rendering capability of a WPF
application. The WPF system defines three rendering tiers:

Rendering Tier 0 No graphics hardware acceleration. The DirectX version level is


less than version 7.0.

Rendering Tier 1 Partial graphics hardware acceleration. The DirectX version level is
greater than or equal to version 7.0, and lesser than version 9.0.

Rendering Tier 2 Most graphics features use graphics hardware acceleration. The
DirectX version level is greater than or equal to version 9.0.

For more information on WPF rendering tiers, see Graphics Rendering Tiers.
See also
Optimizing WPF Application Performance
Planning for Application Performance
Layout and Design
2D Graphics and Imaging
Object Behavior
Application Resources
Text
Data Binding
Other Performance Recommendations
Optimizing Performance: Layout and
Design
Article • 02/06/2023

The design of your WPF application can impact its performance by creating unnecessary
overhead in calculating layout and validating object references. The construction of
objects, particularly at run time, can affect the performance characteristics of your
application.

This topic provides performance recommendations in these areas.

Layout
The term "layout pass" describes the process of measuring and arranging the members
of a Panel-derived object's collection of children, and then drawing them onscreen. The
layout pass is a mathematically-intensive process—the larger the number of children in
the collection, the greater the number of calculations required. For example, each time a
child UIElement object in the collection changes its position, it has the potential to
trigger a new pass by the layout system. Because of the close relationship between
object characteristics and layout behavior, it's important to understand the type of
events that can invoke the layout system. Your application will perform better by
reducing as much as possible any unnecessary invocations of the layout pass.

The layout system completes two passes for each child member in a collection: a
measure pass, and an arrange pass. Each child object provides its own overridden
implementation of the Measure and Arrange methods in order to provide its own
specific layout behavior. At its simplest, layout is a recursive system that leads to an
element being sized, positioned, and drawn onscreen.

A child UIElement object begins the layout process by first having its core
properties measured.

The object's FrameworkElement properties that are related to size, such as Width,
Height, and Margin, are evaluated.

Panel-specific logic is applied, such as the Dock property of the DockPanel, or the
Orientation property of the StackPanel.

Content is arranged, or positioned, after all child objects have been measured.

The collection of child objects is drawn to the screen.


The layout pass process is invoked again if any of the following actions occur:

A child object is added to the collection.

A LayoutTransform is applied to the child object.

The UpdateLayout method is called for the child object.

When a change occurs to the value of a dependency property that is marked with
metadata affecting the measure or arrange passes.

Use the Most Efficient Panel where Possible


The complexity of the layout process is directly based on the layout behavior of the
Panel-derived elements you use. For example, a Grid or StackPanel control provides
much more functionality than a Canvas control. The price for this greater increase in
functionality is a greater increase in performance costs. However, if you do not require
the functionality that a Grid control provides, you should use the less costly alternatives,
such as a Canvas or a custom panel.

For more information, see Panels Overview.

Update Rather than Replace a RenderTransform


You may be able to update a Transform rather than replacing it as the value of a
RenderTransform property. This is particularly true in scenarios that involve animation.
By updating an existing Transform, you avoid initiating an unnecessary layout
calculation.

Build Your Tree Top-Down


When a node is added or removed from the logical tree, property invalidations are
raised on the node's parent and all its children. As a result, a top-down construction
pattern should always be followed to avoid the cost of unnecessary invalidations on
nodes that have already been validated. The following table shows the difference in
execution speed between building a tree top-down versus bottom-up, where the tree is
150 levels deep with a single TextBlock and DockPanel at each level.

Action Tree building (in ms) Render—includes tree building (in ms)

Bottom-up 366 454

Top-down 11 96
The following code example demonstrates how to create a tree top down.

C#

private void OnBuildTreeTopDown(object sender, RoutedEventArgs e)


{
TextBlock textBlock = new TextBlock();
textBlock.Text = "Default";

DockPanel parentPanel = new DockPanel();


DockPanel childPanel;

myCanvas.Children.Add(parentPanel);
myCanvas.Children.Add(textBlock);

for (int i = 0; i < 150; i++)


{
textBlock = new TextBlock();
textBlock.Text = "Default";
parentPanel.Children.Add(textBlock);

childPanel = new DockPanel();


parentPanel.Children.Add(childPanel);
parentPanel = childPanel;
}
}

For more information on the logical tree, see Trees in WPF.

See also
Optimizing WPF Application Performance
Planning for Application Performance
Taking Advantage of Hardware
2D Graphics and Imaging
Object Behavior
Application Resources
Text
Data Binding
Other Performance Recommendations
Layout
Optimizing Performance: 2D Graphics
and Imaging
Article • 02/06/2023

WPF provides a wide range of 2D graphics and imaging functionality that can be
optimized for your application requirements. This topic provides information about
performance optimization in those areas.

Drawing and Shapes


WPF provides both Drawing and Shape objects to represent graphical drawing content.
However, Drawing objects are simpler constructs than Shape objects and provide better
performance characteristics.

A Shape allows you to draw a graphical shape to the screen. Because they are derived
from the FrameworkElement class, Shape objects can be used inside panels and most
controls.

WPF offers several layers of access to graphics and rendering services. At the top layer,
Shape objects are easy to use and provide many useful features, such as layout and
event handling. WPF provides a number of ready-to-use shape objects. All shape
objects inherit from the Shape class. Available shape objects include Ellipse, Line, Path,
Polygon, Polyline, and Rectangle.

Drawing objects, on the other hand, do not derive from the FrameworkElement class
and provide a lighter-weight implementation for rendering shapes, images, and text.

There are four types of Drawing objects:

GeometryDrawing Draws a shape.

ImageDrawing Draws an image.

GlyphRunDrawing Draws text.

DrawingGroup Draws other drawings. Use a drawing group to combine other


drawings into a single composite drawing.

The GeometryDrawing object is used to render geometry content. The Geometry class
and the concrete classes that derive from it, such as CombinedGeometry,
EllipseGeometry, and PathGeometry, provide a means for rendering 2D graphics and
providing hit-testing and clipping support. Geometry objects can be used to define the
region of a control, for example, or to define the clip region to apply to an image.
Geometry objects can be simple regions, such as rectangles and circles, or composite
regions created from two or more geometry objects. More complex geometric regions
can be created by combining PathSegment-derived objects, such as ArcSegment,
BezierSegment, and QuadraticBezierSegment.

On the surface, the Geometry class and the Shape class are similar. Both are used in the
rendering of 2D graphics and both have similar concrete classes that derive from them,
for example, EllipseGeometry and Ellipse. However, there are important differences
between these two sets of classes. For one, the Geometry class lacks some of the
functionality of the Shape class, such as the ability to draw itself. To draw a geometry
object, another class such as DrawingContext, Drawing, or a Path (it is worth noting that
a Path is a Shape) must be used to perform the drawing operation. Rendering properties
such as fill, stroke, and the stroke thickness are on the class that draws the geometry
object, while a shape object contains these properties. One way to think of this
difference is that a geometry object defines a region, for example, a circle, while a shape
object defines a region, defines how that region is filled and outlined, and participates in
the layout system.

Since Shape objects derive from the FrameworkElement class, using them can add
significantly more memory consumption in your application. If you really do not need
the FrameworkElement features for your graphical content, consider using the lighter-
weight Drawing objects.

For more information on Drawing objects, see Drawing Objects Overview.

StreamGeometry Objects
The StreamGeometry object is a lightweight alternative to PathGeometry for creating
geometric shapes. Use a StreamGeometry when you need to describe a complex
geometry. StreamGeometry is optimized for handling many PathGeometry objects and
performs better when compared to using many individual PathGeometry objects.

The following example uses attribute syntax to create a triangular StreamGeometry in


XAML.

XAML

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>

<Path Data="F0 M10,100 L100,100 100,50Z"


StrokeThickness="1" Stroke="Black"/>
</StackPanel>
</Page>

For more information on StreamGeometry objects, see Create a Shape Using a


StreamGeometry.

DrawingVisual Objects
The DrawingVisual object is a lightweight drawing class that is used to render shapes,
images, or text. This class is considered lightweight because it does not provide layout
or event handling, which improves its performance. For this reason, drawings are ideal
for backgrounds and clip art. For more information, see Using DrawingVisual Objects.

Images
WPF imaging provides a significant improvement over the imaging capabilities in
previous versions of Windows. Imaging capabilities, such as displaying a bitmap or using
an image on a common control, were primarily handled by the Microsoft Windows
Graphics Device Interface (GDI) or Microsoft Windows GDI+ application programming
interface (API). These APIs provided baseline imaging functionality but lacked features
such as support for codec extensibility and high fidelity image support. WPF Imaging
APIs have been redesigned to overcome the shortcomings of GDI and GDI+ and provide
a new set of APIs to display and use images within your applications.

When using images, consider the following recommendations for gaining better
performance:

If your application requires you to display thumbnail images, consider creating a


reduced-sized version of the image. By default, WPF loads your image and
decodes it to its full size. If you only want a thumbnail version of the image, WPF
unnecessary decodes the image to its full-size and then scales it down to a
thumbnail size. To avoid this unnecessary overhead, you can either request WPF to
decode the image to a thumbnail size, or request WPF to load a thumbnail size
image.

Always decode the image to desired size and not to the default size. As mentioned
above, request WPF to decode your image to a desired size and not the default full
size. You will reduce not only your application's working set, but execution speed
as well.
If possible, combine the images into a single image, such as a film strip composed
of multiple images.

For more information, see Imaging Overview.

BitmapScalingMode
When animating the scale of any bitmap, the default high-quality image resampling
algorithm can sometimes consume sufficient system resources to cause frame rate
degradation, effectively causing animations to stutter. By setting the
BitmapScalingMode property of the RenderOptions object to LowQuality, you can
create a smoother animation when scaling a bitmap. LowQuality mode tells the WPF
rendering engine to switch from a quality-optimized algorithm to a speed-optimized
algorithm when processing images.

The following example shows how to set the BitmapScalingMode for an image object.

C#

// Set the bitmap scaling mode for the image to render faster.
RenderOptions.SetBitmapScalingMode(MyImage, BitmapScalingMode.LowQuality);

CachingHint
By default, WPF does not cache the rendered contents of TileBrush objects, such as
DrawingBrush and VisualBrush. In static scenarios where the contents or use of the
TileBrush in the scene aren't changing, this makes sense, since it conserves video
memory. It does not make as much sense when a TileBrush with static content is used in
a non-static way—for example, when a static DrawingBrush or VisualBrush is mapped to
the surface of a rotating 3D object. The default behavior of WPF is to re-render the
entire content of the DrawingBrush or VisualBrush for every frame, even though the
content is unchanging.

By setting the CachingHint property of the RenderOptions object to Cache, you can
increase performance by using cached versions of the tiled brush objects.

The CacheInvalidationThresholdMinimum and CacheInvalidationThresholdMaximum


property values are relative size values that determine when the TileBrush object should
be regenerated due to changes in scale. For example, by setting the
CacheInvalidationThresholdMaximum property to 2.0, the cache for the TileBrush only
needs to be regenerated when its size exceeds twice the size of the current cache.
The following example shows how to use the caching hint option for a DrawingBrush.

C#

DrawingBrush drawingBrush = new DrawingBrush();

// Set the caching hint option for the brush.


RenderOptions.SetCachingHint(drawingBrush, CachingHint.Cache);

// Set the minimum and maximum relative sizes for regenerating the tiled
brush.
// The tiled brush will be regenerated and re-cached when its size is
// 0.5x or 2x of the current cached size.
RenderOptions.SetCacheInvalidationThresholdMinimum(drawingBrush, 0.5);
RenderOptions.SetCacheInvalidationThresholdMaximum(drawingBrush, 2.0);

See also
Optimizing WPF Application Performance
Planning for Application Performance
Taking Advantage of Hardware
Layout and Design
Object Behavior
Application Resources
Text
Data Binding
Other Performance Recommendations
Animation Tips and Tricks
Optimizing Performance: Object
Behavior
Article • 08/18/2022

Understanding the intrinsic behavior of WPF objects will help you make the right
tradeoffs between functionality and performance.

Not Removing Event Handlers on Objects may


Keep Objects Alive
The delegate that an object passes to its event is effectively a reference to that object.
Therefore, event handlers can keep objects alive longer than expected. When
performing clean up of an object that has registered to listen to an object's event, it is
essential to remove that delegate before releasing the object. Keeping unneeded
objects alive increases the application's memory usage. This is especially true when the
object is the root of a logical tree or a visual tree.

WPF introduces a weak event listener pattern for events that can be useful in situations
where the object lifetime relationships between source and listener are difficult to keep
track of. Some existing WPF events use this pattern. If you are implementing objects
with custom events, this pattern may be of use to you. For details, see Weak Event
Patterns.

There are several tools, such as the CLR Profiler and the Working Set Viewer, that can
provides information on the memory usage of a specified process. The CLR Profiler
includes a number of very useful views of the allocation profile, including a histogram of
allocated types, allocation and call graphs, a time line showing garbage collections of
various generations and the resulting state of the managed heap after those collections,
and a call tree showing per-method allocations and assembly loads. For more
information, see Performance.

Dependency Properties and Objects


In general, accessing a dependency property of a DependencyObject is not slower than
accessing a CLR property. While there is a small performance overhead for setting a
property value, getting a value is as fast as getting the value from a CLR property.
Offsetting the small performance overhead is the fact that dependency properties
support robust features, such as data binding, animation, inheritance, and styling. For
more information, see Dependency Properties Overview.

DependencyProperty Optimizations
You should define dependency properties in your application very carefully. If your
DependencyProperty affects only render type metadata options, rather than other
metadata options such as AffectsMeasure, you should mark it as such by overriding its
metadata. For more information about overriding or obtaining property metadata, see
Dependency Property Metadata.

It may be more efficient to have a property change handler invalidate the measure,
arrange, and render passes manually if not all property changes actually affect measure,
arrange, and render. For instance, you might decide to re-render a background only
when a value is greater than a set limit. In this case, your property change handler would
only invalidate render when the value exceeds the set limit.

Making a DependencyProperty Inheritable is Not Free


By default, registered dependency properties are non-inheritable. However, you can
explicitly make any property inheritable. While this is a useful feature, converting a
property to be inheritable impacts performance by increasing the length of time for
property invalidation.

Use RegisterClassHandler Carefully


While calling RegisterClassHandler allows you to save your instance state, it is important
to be aware that the handler is called on every instance, which can cause performance
problems. Only use RegisterClassHandler when your application requires that you save
your instance state.

Set the Default Value for a DependencyProperty during


Registration
When creating a DependencyProperty that requires a default value, set the value using
the default metadata passed as a parameter to the Register method of the
DependencyProperty. Use this technique rather than setting the property value in a
constructor or on each instance of an element.

Set the PropertyMetadata Value using Register


When creating a DependencyProperty, you have the option of setting the
PropertyMetadata using either the Register or OverrideMetadata methods. Although
your object could have a static constructor to call OverrideMetadata, this is not the
optimal solution and will impact performance. For best performance, set the
PropertyMetadata during the call to Register.

Freezable Objects
A Freezable is a special type of object that has two states: unfrozen and frozen. Freezing
objects whenever possible improves the performance of your application and reduces
its working set. For more information, see Freezable Objects Overview.

Each Freezable has a Changed event that is raised whenever it changes. However,
change notifications are costly in terms of application performance.

Consider the following example in which each Rectangle uses the same Brush object:

C#

rectangle_1.Fill = myBrush;
rectangle_2.Fill = myBrush;
rectangle_3.Fill = myBrush;
// ...
rectangle_10.Fill = myBrush;

By default, WPF provides an event handler for the SolidColorBrush object's Changed
event in order to invalidate the Rectangle object's Fill property. In this case, each time
the SolidColorBrush has to fire its Changed event it is required to invoke the callback
function for each Rectangle—the accumulation of these callback function invocations
impose a significant performance penalty. In addition, it is very performance intensive to
add and remove handlers at this point since the application would have to traverse the
entire list to do so. If your application scenario never changes the SolidColorBrush, you
will be paying the cost of maintaining Changed event handlers unnecessarily.

Freezing a Freezable can improve its performance, because it no longer needs to expend
resources on maintaining change notifications. The table below shows the size of a
simple SolidColorBrush when its IsFrozen property is set to true , compared to when it is
not. This assumes applying one brush to the Fill property of ten Rectangle objects.

State Size

Frozen SolidColorBrush 212 Bytes

Non-frozen SolidColorBrush 972 Bytes


The following code sample demonstrates this concept:

C#

Brush frozenBrush = new SolidColorBrush(Colors.Blue);


frozenBrush.Freeze();
Brush nonFrozenBrush = new SolidColorBrush(Colors.Blue);

for (int i = 0; i < 10; i++)


{
// Create a Rectangle using a non-frozed Brush.
Rectangle rectangleNonFrozen = new Rectangle();
rectangleNonFrozen.Fill = nonFrozenBrush;

// Create a Rectangle using a frozed Brush.


Rectangle rectangleFrozen = new Rectangle();
rectangleFrozen.Fill = frozenBrush;
}

Changed Handlers on Unfrozen Freezables may Keep


Objects Alive
The delegate that an object passes to a Freezable object's Changed event is effectively a
reference to that object. Therefore, Changed event handlers can keep objects alive
longer than expected. When performing clean up of an object that has registered to
listen to a Freezable object's Changed event, it is essential to remove that delegate
before releasing the object.

WPF also hooks up Changed events internally. For example, all dependency properties
which take Freezable as a value will listen to Changed events automatically. The Fill
property, which takes a Brush, illustrates this concept.

C#

Brush myBrush = new SolidColorBrush(Colors.Red);


Rectangle myRectangle = new Rectangle();
myRectangle.Fill = myBrush;

On the assignment of myBrush to myRectangle.Fill , a delegate pointing back to the


Rectangle object will be added to the SolidColorBrush object's Changed event. This
means the following code does not actually make myRect eligible for garbage collection:

C#

myRectangle = null;
In this case myBrush is still keeping myRectangle alive and will call back to it when it fires
its Changed event. Note that assigning myBrush to the Fill property of a new Rectangle
will simply add another event handler to myBrush .

The recommended way to clean up these types of objects is to remove the Brush from
the Fill property, which will in turn remove the Changed event handler.

C#

myRectangle.Fill = null;
myRectangle = null;

User Interface Virtualization


WPF also provides a variation of the StackPanel element that automatically "virtualizes"
data-bound child content. In this context, the word virtualize refers to a technique by
which a subset of objects are generated from a larger number of data items based upon
which items are visible on-screen. It is intensive, both in terms of memory and
processor, to generate a large number of UI elements when only a few may be on the
screen at a given time. VirtualizingStackPanel (through functionality provided by
VirtualizingPanel) calculates visible items and works with the ItemContainerGenerator
from an ItemsControl (such as ListBox or ListView) to only create elements for visible
items.

As a performance optimization, visual objects for these items are only generated or kept
alive if they are visible on the screen. When they are no longer in the viewable area of
the control, the visual objects may be removed. This is not to be confused with data
virtualization, where data objects are not all present in the local collection- rather
streamed in as needed.

The table below shows the elapsed time adding and rendering 5000 TextBlock elements
to a StackPanel and a VirtualizingStackPanel. In this scenario, the measurements
represent the time between attaching a text string to the ItemsSource property of an
ItemsControl object to the time when the panel elements display the text string.

Host panel Render time (ms)

StackPanel 3210

VirtualizingStackPanel 46
See also
Optimizing WPF Application Performance
Planning for Application Performance
Taking Advantage of Hardware
Layout and Design
2D Graphics and Imaging
Application Resources
Text
Data Binding
Other Performance Recommendations
Optimizing Performance: Application
Resources
Article • 02/06/2023

WPF allows you to share application resources so that you can support a consistent look
or behavior across similar-typed elements. This topic provides a few recommendations
in this area that can help you improve the performance of your applications.

For more information on resources, see XAML Resources.

Sharing resources
If your application uses custom controls and defines resources in a ResourceDictionary
(or XAML Resources node), it is recommended that you either define the resources at
the Application or Window object level, or define them in the default theme for the
custom controls. Defining resources in a custom control's ResourceDictionary imposes a
performance impact for every instance of that control. For example, if you have
performance-intensive brush operations defined as part of the resource definition of a
custom control and many instances of the custom control, the application's working set
will increase significantly.

To illustrate this point, consider the following. Let's say you are developing a card game
using WPF. For most card games, you need 52 cards with 52 different faces. You decide
to implement a card custom control and you define 52 brushes (each representing a
card face) in the resources of your card custom control. In your main application, you
initially create 52 instances of this card custom control. Each instance of the card custom
control generates 52 instances of Brush objects, which gives you a total of 52 * 52 Brush
objects in your application. By moving the brushes out of the card custom control
resources to the Application or Window object level, or defining them in the default
theme for the custom control, you reduce the working set of the application, since you
are now sharing the 52 brushes among 52 instances of the card control.

Sharing a Brush without Copying


If you have multiple elements using the same Brush object, define the brush as a
resource and reference it, rather than defining the brush inline in XAML. This method
will create one instance and reuse it, whereas defining brushes inline in XAML creates a
new instance for each element.
The following markup sample illustrates this point:

XAML

<StackPanel.Resources>
<LinearGradientBrush x:Key="myBrush" StartPoint="0,0.5" EndPoint="1,0.5"
Opacity="0.5">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="GoldenRod" Offset="0" />
<GradientStop Color="White" Offset="1" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</StackPanel.Resources>

<!-- Non-shared Brush object. -->


<Label>
Label 1
<Label.Background>
<LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5" Opacity="0.5">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="GoldenRod" Offset="0" />
<GradientStop Color="White" Offset="1" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Label.Background>
</Label>

<!-- Shared Brush object. -->


<Label Background="{StaticResource myBrush}">Label 2</Label>
<Label Background="{StaticResource myBrush}">Label 3</Label>

Use Static Resources when Possible


A static resource 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 compile-time lookup.

A dynamic resource, on the other hand, 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. Lookup behavior for that
resource is analogous to run-time lookup, which imposes a performance impact. Use
static resources whenever possible in your application, using dynamic resources only
when necessary.
The following markup sample shows the use of both types of resources:

XAML

<StackPanel.Resources>
<SolidColorBrush x:Key="myBrush" Color="Teal"/>
</StackPanel.Resources>

<!-- StaticResource reference -->


<Label Foreground="{StaticResource myBrush}">Label 1</Label>

<!-- DynamicResource reference -->


<Label Foreground="{DynamicResource {x:Static
SystemColors.ControlBrushKey}}">Label 2</Label>

See also
Optimizing WPF Application Performance
Planning for Application Performance
Taking Advantage of Hardware
Layout and Design
2D Graphics and Imaging
Object Behavior
Text
Data Binding
Other Performance Recommendations
Optimizing Performance: Text
Article • 08/18/2022

WPF includes support for the presentation of text content through the use of feature-
rich user interface (UI) controls. In general you can divide text rendering in three layers:

1. Using the Glyphs and GlyphRun objects directly.

2. Using the FormattedText object.

3. Using high-level controls, such as the TextBlock and FlowDocument objects.

This topic provides text rendering performance recommendations.

Rendering Text at the Glyph Level


Windows Presentation Foundation (WPF) provides advanced text support including
glyph-level markup with direct access to Glyphs for customers who want to intercept
and persist text after formatting. These features provide critical support for the different
text rendering requirements in each of the following scenarios.

Screen display of fixed-format documents.

Print scenarios.

Extensible Application Markup Language (XAML) as a device printer language.

Microsoft XPS Document Writer.

Previous printer drivers, output from Win32 applications to the fixed format.

Print spool format.

Fixed-format document representation, including clients for previous versions of


Windows and other computing devices.

7 Note

Glyphs and GlyphRun are designed for fixed-format document presentation and
print scenarios. UI scenarios, see the Typography in WPF.

The following examples show how to define properties for a Glyphs object in XAML. The
examples assume that the Arial, Courier New, and Times New Roman fonts are installed
in the C:\WINDOWS\Fonts folder on the local computer.

XAML

<!-- The example shows how to use a Glyphs object. -->


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>

<StackPanel Background="PowderBlue">

<Glyphs
FontUri = "C:\WINDOWS\Fonts\TIMES.TTF"
FontRenderingEmSize = "100"
StyleSimulations = "BoldSimulation"
UnicodeString = "Hello World!"
Fill = "Black"
OriginX = "100"
OriginY = "200"
/>

</StackPanel>
</Page>

Using DrawGlyphRun
If you have custom control and you want to render glyphs, use the DrawGlyphRun
method.

WPF also provides lower-level services for custom text formatting through the use of
the FormattedText object. The most efficient way of rendering text in Windows
Presentation Foundation (WPF) is by generating text content at the glyph level using
Glyphs and GlyphRun. However, the cost of this efficiency is the loss of easy to use rich
text formatting, which are built-in features of Windows Presentation Foundation (WPF)
controls, such as TextBlock and FlowDocument.

FormattedText Object
The FormattedText object allows you to draw multi-line text, in which each character in
the text can be individually formatted. For more information, see Drawing Formatted
Text.

To create formatted text, call the FormattedText constructor to create a FormattedText


object. Once you have created the initial formatted text string, you can apply a range of
formatting styles. If your application wants to implement its own layout, then the
FormattedText object is better choice than using a control, such as TextBlock. For more
information on the FormattedText object, see Drawing Formatted Text .

The FormattedText object provides low-level text formatting capability. You can apply
multiple formatting styles to one or more characters. For example, you could call both
the SetFontSize and SetForegroundBrush methods to change the formatting of the first
five characters in the text.

The following code example creates a FormattedText object and renders it.

C#

protected override void OnRender(DrawingContext drawingContext)


{
string testString = "Lorem ipsum dolor sit amet, consectetur adipisicing
elit, sed do eiusmod tempor";

// Create the initial formatted text string.


FormattedText formattedText = new FormattedText(
testString,
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Verdana"),
32,
Brushes.Black);

// Set a maximum width and height. If the text overflows these values,
an ellipsis "..." appears.
formattedText.MaxTextWidth = 300;
formattedText.MaxTextHeight = 240;

// Use a larger font size beginning at the first (zero-based) character


and continuing for 5 characters.
// The font size is calculated in terms of points -- not as device-
independent pixels.
formattedText.SetFontSize(36 * (96.0 / 72.0), 0, 5);

// Use a Bold font weight beginning at the 6th character and continuing
for 11 characters.
formattedText.SetFontWeight(FontWeights.Bold, 6, 11);

// Use a linear gradient brush beginning at the 6th character and


continuing for 11 characters.
formattedText.SetForegroundBrush(
new LinearGradientBrush(
Colors.Orange,
Colors.Teal,
90.0),
6, 11);

// Use an Italic font style beginning at the 28th character and


continuing for 28 characters.
formattedText.SetFontStyle(FontStyles.Italic, 28, 28);

// Draw the formatted text string to the DrawingContext of the control.


drawingContext.DrawText(formattedText, new Point(10, 0));
}

FlowDocument, TextBlock, and Label Controls


WPF includes multiple controls for drawing text to the screen. Each control is targeted to
a different scenario and has its own list of features and limitations.

FlowDocument Impacts Performance More than


TextBlock or Label
In general, the TextBlock element should be used when limited text support is required,
such as a brief sentence in a user interface (UI). Label can be used when minimal text
support is required. The FlowDocument element is a container for re-flowable
documents that support rich presentation of content, and therefore, has a greater
performance impact than using the TextBlock or Label controls.

For more information on FlowDocument, see Flow Document Overview.

Avoid Using TextBlock in FlowDocument


The TextBlock element is derived from UIElement. The Run element is derived from
TextElement, which is less costly to use than a UIElement-derived object. When possible,
use Run rather than TextBlock for displaying text content in a FlowDocument.

The following markup sample illustrates two ways of setting text content within a
FlowDocument:

XAML

<FlowDocument>

<!-- Text content within a Run (more efficient). -->


<Paragraph>
<Run>Line one</Run>
</Paragraph>

<!-- Text content within a TextBlock (less efficient). -->


<Paragraph>
<TextBlock>Line two</TextBlock>
</Paragraph>
</FlowDocument>

Avoid Using Run to Set Text Properties


In general, using a Run within a TextBlock is more performance intensive than not using
an explicit Run object at all. If you are using a Run in order to set text properties, set
those properties directly on the TextBlock instead.

The following markup sample illustrates these two ways of setting a text property, in this
case, the FontWeight property:

XAML

<!-- Run is used to set text properties. -->


<TextBlock>
<Run FontWeight="Bold">Hello, world</Run>
</TextBlock>

<!-- TextBlock is used to set text properties, which is more efficient. -->
<TextBlock FontWeight="Bold">
Hello, world
</TextBlock>

The following table shows the cost of displaying 1000 TextBlock objects with and
without an explicit Run.

TextBlock type Creation time (ms) Render time (ms)

Run setting text properties 146 540

TextBlock setting text properties 43 453

Avoid Databinding to the Label.Content Property


Imagine a scenario where you have a Label object that is updated frequently from a
String source. When data binding the Label element's Content property to the String
source object, you may experience poor performance. Each time the source String is
updated, the old String object is discarded and a new String is recreated—because a
String object is immutable, it cannot be modified. This, in turn, causes the
ContentPresenter of the Label object to discard its old content and regenerate the new
content to display the new String.
The solution to this problem is simple. If the Label is not set to a custom
ContentTemplate value, replace the Label with a TextBlock and data bind its Text
property to the source string.

Data bound property Update time (ms)

Label.Content 835

TextBlock.Text 242

Hyperlink
The Hyperlink object is an inline-level flow content element that allows you to host
hyperlinks within the flow content.

Combine Hyperlinks in One TextBlock Object


You can optimize the use of multiple Hyperlink elements by grouping them together
within the same TextBlock. This helps to minimize the number of objects you create in
your application. For example, you may want to display multiple hyperlinks, such as the
following:

MSN Home | My MSN

The following markup example shows multiple TextBlock elements used to display the
hyperlinks:

XAML

<!-- Hyperlinks in separate TextBlocks. -->


<TextBlock>
<Hyperlink TextDecorations="None" NavigateUri="http://www.msn.com">MSN
Home</Hyperlink>
</TextBlock>

<TextBlock Text=" | "/>

<TextBlock>
<Hyperlink TextDecorations="None" NavigateUri="http://my.msn.com">My
MSN</Hyperlink>
</TextBlock>

The following markup example shows a more efficient way of displaying the hyperlinks,
this time, using a single TextBlock:
XAML

<!-- Hyperlinks combined in the same TextBlock. -->


<TextBlock>
<Hyperlink TextDecorations="None" NavigateUri="http://www.msn.com">MSN
Home</Hyperlink>

<Run Text=" | " />

<Hyperlink TextDecorations="None" NavigateUri="http://my.msn.com">My


MSN</Hyperlink>
</TextBlock>

Showing Underlines on Hyperlinks Only on MouseEnter


Events
A TextDecoration object is a visual ornamentation that you can add to text; however, it
can be performance intensive to instantiate. If you make extensive use of Hyperlink
elements, consider showing an underline only when triggering an event, such as the
MouseEnter event. For more information, see Specify Whether a Hyperlink is Underlined.

The following image shows how the MouseEnter event triggers the underlined
hyperlink:

The following markup sample shows a Hyperlink defined with and without an underline:

XAML

<!-- Hyperlink with default underline. -->


<Hyperlink NavigateUri="http://www.msn.com">
MSN Home
</Hyperlink>

<Run Text=" | " />

<!-- Hyperlink with no underline. -->


<Hyperlink Name="myHyperlink" TextDecorations="None"
MouseEnter="OnMouseEnter"
MouseLeave="OnMouseLeave"
NavigateUri="http://www.msn.com">
My MSN
</Hyperlink>

The following table shows the performance cost of displaying 1000 Hyperlink elements
with and without an underline.

Hyperlink Creation time (ms) Render time (ms)

With underline 289 1130

Without underline 299 776

Text Formatting Features


WPF provides rich text formatting services, such as automatic hyphenations. These
services may impact application performance and should only be used when needed.

Avoid Unnecessary Use of Hyphenation


Automatic hyphenation finds hyphen breakpoints for lines of text, and allows additional
break positions for lines in TextBlock and FlowDocument objects. By default, the
automatic hyphenation feature is disabled in these objects. You can enable this feature
by setting the object's IsHyphenationEnabled property to true . However, enabling this
feature causes WPF to initiate Component Object Model (COM) interoperability, which
can impact application performance. It is recommended that you do not use automatic
hyphenation unless you need it.

Use Figures Carefully


A Figure element represents a portion of flow content that can be absolutely-positioned
within a page of content. In some cases, a Figure may cause an entire page to
automatically reformat if its position collides with content that has already been laid-
out. You can minimize the possibility of unnecessary reformatting by either grouping
Figure elements next to each other, or declaring them near the top of content in a fixed
page size scenario.

Optimal Paragraph
The optimal paragraph feature of the FlowDocument object lays out paragraphs so that
white space is distributed as evenly as possible. By default, the optimal paragraph
feature is disabled. You can enable this feature by setting the object's
IsOptimalParagraphEnabled property to true . However, enabling this feature impacts
application performance. It is recommended that you do not use the optimal paragraph
feature unless you need it.

See also
Optimizing WPF Application Performance
Planning for Application Performance
Taking Advantage of Hardware
Layout and Design
2D Graphics and Imaging
Object Behavior
Application Resources
Data Binding
Other Performance Recommendations
Optimizing Performance: Data Binding
Article • 02/06/2023

Windows Presentation Foundation (WPF) data binding provides a simple and consistent
way for applications to present and interact with data. Elements can be bound to data
from a variety of data sources in the form of CLR objects and XML.

This topic provides data binding performance recommendations.

How Data Binding References are Resolved


Before discussing data binding performance issues, it is worthwhile to explore how the
Windows Presentation Foundation (WPF) data binding engine resolves object references
for binding.

The source of a Windows Presentation Foundation (WPF) data binding can be any CLR
object. You can bind to properties, sub-properties, or indexers of a CLR object. The
binding references are resolved by using either Microsoft .NET Framework reflection or
an ICustomTypeDescriptor. Here are three methods for resolving object references for
binding.

The first method involves using reflection. In this case, the PropertyInfo object is used to
discover the attributes of the property and provides access to property metadata. When
using the ICustomTypeDescriptor interface, the data binding engine uses this interface
to access the property values. The ICustomTypeDescriptor interface is especially useful
in cases where the object does not have a static set of properties.

Property change notifications can be provided either by implementing the


INotifyPropertyChanged interface or by using the change notifications associated with
the TypeDescriptor. However, the preferred strategy for implementing property change
notifications is to use INotifyPropertyChanged.

If the source object is a CLR object and the source property is a CLR property, the
Windows Presentation Foundation (WPF) data binding engine has to first use reflection
on the source object to get the TypeDescriptor, and then query for a PropertyDescriptor.
This sequence of reflection operations is potentially very time-consuming from a
performance perspective.

The second method for resolving object references involves a CLR source object that
implements the INotifyPropertyChanged interface, and a source property that is a CLR
property. In this case, the data binding engine uses reflection directly on the source type
and gets the required property. This is still not the optimal method, but it will cost less
in working set requirements than the first method.

The third method for resolving object references involves a source object that is a
DependencyObject and a source property that is a DependencyProperty. In this case,
the data binding engine does not need to use reflection. Instead, the property engine
and the data binding engine together resolve the property reference independently.
This is the optimal method for resolving object references used for data binding.

The table below compares the speed of data binding the Text property of one thousand
TextBlock elements using these three methods.

Binding the Text property of a TextBlock Binding Render time -- includes


time (ms) binding (ms)

To a property of a CLR object 115 314

To a property of a CLR object which implements 115 305


INotifyPropertyChanged

To a DependencyProperty of a DependencyObject. 90 263

Binding to Large CLR Objects


There is a significant performance impact when you data bind to a single CLR object
with thousands of properties. You can minimize this impact by dividing the single object
into multiple CLR objects with fewer properties. The table shows the binding and
rendering times for data binding to a single large CLR object versus multiple smaller
objects.

Data binding 1000 TextBlock objects Binding time Render time -- includes binding
(ms) (ms)

To a CLR object with 1000 properties 950 1200

To 1000 CLR objects with one 115 314


property

Binding to an ItemsSource
Consider a scenario in which you have a CLR List<T> object that holds a list of
employees that you want to display in a ListBox. To create a correspondence between
these two objects, you would bind your employee list to the ItemsSource property of
the ListBox. However, suppose you have a new employee joining your group. You might
think that in order to insert this new person into your bound ListBox values, you would
simply add this person to your employee list and expect this change to be recognized
by the data binding engine automatically. That assumption would prove false; in
actuality, the change will not be reflected in the ListBox automatically. This is because
the CLR List<T> object does not automatically raise a collection changed event. In order
to get the ListBox to pick up the changes, you would have to recreate your list of
employees and re-attach it to the ItemsSource property of the ListBox. While this
solution works, it introduces a huge performance impact. Each time you reassign the
ItemsSource of ListBox to a new object, the ListBox first throws away its previous items
and regenerates its entire list. The performance impact is magnified if your ListBox maps
to a complex DataTemplate.

A very efficient solution to this problem is to make your employee list an


ObservableCollection<T>. An ObservableCollection<T> object raises a change
notification which the data binding engine can receive. The event adds or removes an
item from an ItemsControl without the need to regenerate the entire list.

The table below shows the time it takes to update the ListBox (with UI virtualization
turned off) when one item is added. The number in the first row represents the elapsed
time when the CLR List<T> object is bound to ListBox element's ItemsSource. The
number in the second row represents the elapsed time when an
ObservableCollection<T> is bound to the ListBox element's ItemsSource. Note the
significant time savings using the ObservableCollection<T> data binding strategy.

Data binding the ItemsSource Update time for 1 item (ms)

To a CLR List<T> object 1656

To an ObservableCollection<T> 20

Bind IList to ItemsControl not IEnumerable


If you have a choice between binding an IList<T> or an IEnumerable to an ItemsControl
object, choose the IList<T> object. Binding IEnumerable to an ItemsControl forces WPF
to create a wrapper IList<T> object, which means your performance is impacted by the
unnecessary overhead of a second object.

Do not Convert CLR objects to XML Just for


Data Binding.
WPF allows you to data bind to XML content; however, data binding to XML content is
slower than data binding to CLR objects. Do not convert CLR object data to XML if the
only purpose is for data binding.

See also
Optimizing WPF Application Performance
Planning for Application Performance
Taking Advantage of Hardware
Layout and Design
2D Graphics and Imaging
Object Behavior
Application Resources
Text
Other Performance Recommendations
Data Binding Overview
Walkthrough: Caching Application Data in a WPF Application
Optimizing performance: Controls
Article • 08/12/2021

Windows Presentation Foundation (WPF) includes many of the common user-interface


(UI) components that are used in most Windows applications. This topic contains
techniques for improving the performance of your UI.

Displaying large data sets


WPF controls such as the ListView and ComboBox are used to display lists of items in an
application. If the list to display is large, the application's performance can be affected.
This is because the standard layout system creates a layout container for each item
associated with the list control, and computes its layout size and position. Typically, you
do not have to display all the items at the same time; instead you display a subset, and
the user scrolls through the list. In this case, it makes sense to use UI virtualization,
which means the item container generation and associated layout computation for an
item is deferred until the item is visible.

UI Virtualization is an important aspect of list controls. UI virtualization should not be


confused with data virtualization. UI virtualization stores only visible items in memory
but in a data-binding scenario stores the entire data structure in memory. In contrast,
data virtualization stores only the data items that are visible on the screen in memory.

By default, UI virtualization is enabled for the ListView and ListBox controls when their
list items are bound to data. TreeView virtualization can be enabled by setting the
VirtualizingStackPanel.IsVirtualizing attached property to true . If you want to enable UI
virtualization for custom controls that derive from ItemsControl or existing item controls
that use the StackPanel class, such as ComboBox, you can set the ItemsPanel to
VirtualizingStackPanel and set IsVirtualizing to true . Unfortunately, you can disable UI
virtualization for these controls without realizing it. The following is a list of conditions
that disable UI virtualization.

Item containers are added directly to the ItemsControl. For example, if an


application explicitly adds ListBoxItem objects to a ListBox, the ListBox does not
virtualize the ListBoxItem objects.

Item containers in the ItemsControl are of different types. For example, a Menu
that uses Separator objects cannot implement item recycling because the Menu
contains objects of type Separator and MenuItem.

Setting CanContentScroll to false .


Setting IsVirtualizing to false .

An important consideration when you virtualize item containers is whether you have
additional state information associated with an item container that belongs with the
item. In this case, you must save the additional state. For example, you might have an
item contained in an Expander control and the IsExpanded state is bound to the item's
container, and not to the item itself. When the container is reused for a new item, the
current value of IsExpanded is used for the new item. In addition, the old item loses the
correct IsExpanded value.

Currently, no WPF controls offer built-in support for data virtualization.

Container recycling
An optimization to UI virtualization added in the .NET Framework 3.5 SP1 for controls
that inherit from ItemsControl is container recycling, which can also improve scrolling
performance. When an ItemsControl that uses UI virtualization is populated, it creates an
item container for each item that scrolls into view and destroys the item container for
each item that scrolls out of view. Container recycling enables the control to reuse the
existing item containers for different data items, so that item containers are not
constantly created and destroyed as the user scrolls the ItemsControl. You can choose to
enable item recycling by setting the VirtualizationMode attached property to Recycling.

Any ItemsControl that supports virtualization can use container recycling. For an
example of how to enable container recycling on a ListBox, see Improve the Scrolling
Performance of a ListBox.

Supporting bidirectional virtualization


VirtualizingStackPanel offers built-in support for UI virtualization in one direction, either
horizontally or vertically. If you want to use bidirectional virtualization for your controls,
you must implement a custom panel that extends the VirtualizingStackPanel class. The
VirtualizingStackPanel class exposes virtual methods such as OnViewportSizeChanged,
LineUp, PageUp, and MouseWheelUp.These virtual methods enable you to detect a
change in the visible part of a list and handle it accordingly.

Optimizing templates
The visual tree contains all the visual elements in an application. In addition to the
objects directly created, it also contains objects due to template expansion. For example,
when you create a Button, you also get ClassicBorderDecorator and ContentPresenter
objects in the visual tree. If you haven't optimized your control templates, you may be
creating a lot of extra unnecessary objects in the visual tree. For more information on
the visual tree, see WPF Graphics Rendering Overview.

Deferred scrolling
By default, when the user drags the thumb on a scrollbar, the content view continuously
updates. If scrolling is slow in your control, consider using deferred scrolling. In deferred
scrolling, the content is updated only when the user releases the thumb.

To implement deferred scrolling, set the IsDeferredScrollingEnabled property to true .


IsDeferredScrollingEnabled is an attached property and can be set on ScrollViewer and
any control that has a ScrollViewer in its control template.

Controls that implement performance features


The following table lists the common controls for displaying data and their support of
performance features. See the previous sections for information on how to enable these
features.

Control Virtualization Container recycling Deferred scrolling

ComboBox Can be enabled Can be enabled Can be enabled

ContextMenu Can be enabled Can be enabled Can be enabled

DocumentViewer Not available Not available Can be enabled

ListBox Default Can be enabled Can be enabled

ListView Default Can be enabled Can be enabled

TreeView Can be enabled Can be enabled Can be enabled

ToolBar Not available Not available Can be enabled

7 Note

For an example of how to enable virtualization and container recycling on a


TreeView, see Improve the Performance of a TreeView.

See also
Layout
Layout and Design
Data Binding
Controls
Styling and Templating
Walkthrough: Caching Application Data in a WPF Application
Optimizing Performance: Other
Recommendations
Article • 02/06/2023

This topic provides performance recommendations in addition to the ones covered by


the topics in the Optimizing WPF Application Performance section.

This topic contains the following sections:

Opacity on Brushes Versus Opacity on Elements

Navigation to Object

Hit Testing on Large 3D Surfaces

CompositionTarget.Rendering Event

Avoid Using ScrollBarVisibility=Auto

Configure Font Cache Service to Reduce Start-up Time

Opacity on Brushes Versus Opacity on Elements


When you use a Brush to set the Fill or Stroke of an element, it is better to set the
Brush.Opacity value rather than the setting the element's Opacity property. Modifying
an element's Opacity property can cause WPF to create a temporary surface.

Navigation to Object
The NavigationWindow object derives from Window and extends it with content
navigation support, primarily by aggregating NavigationService and the journal. You can
update the client area of NavigationWindow by specifying either a uniform resource
identifier (URI) or an object. The following sample shows both methods:

C#

private void buttonGoToUri(object sender, RoutedEventArgs args)


{
navWindow.Source = new Uri("NewPage.xaml", UriKind.RelativeOrAbsolute);
}

private void buttonGoNewObject(object sender, RoutedEventArgs args)


{
NewPage nextPage = new NewPage();
nextPage.InitializeComponent();
navWindow.Content = nextPage;
}

Each NavigationWindow object has a journal that records the user's navigation history in
that window. One of the purposes of the journal is to allow users to retrace their steps.

When you navigate using a uniform resource identifier (URI), the journal stores only the
uniform resource identifier (URI) reference. This means that each time you revisit the
page, it is dynamically reconstructed, which may be time consuming depending on the
complexity of the page. In this case, the journal storage cost is low, but the time to
reconstitute the page is potentially high.

When you navigate using an object, the journal stores the entire visual tree of the
object. This means that each time you revisit the page, it renders immediately without
having to be reconstructed. In this case, the journal storage cost is high, but the time to
reconstitute the page is low.

When you use the NavigationWindow object, you will need to keep in mind how the
journaling support impacts your application's performance. For more information, see
Navigation Overview.

Hit Testing on Large 3D Surfaces


Hit testing on large 3D surfaces is a very performance intensive operation in terms of
CPU consumption. This is especially true when the 3D surface is animating. If you do not
require hit testing on these surfaces, then disable hit testing. Objects that are derived
from UIElement can disable hit testing by setting the IsHitTestVisible property to false .

CompositionTarget.Rendering Event
The CompositionTarget.Rendering event causes WPF to continuously animate. If you use
this event, detach it at every opportunity.

Avoid Using ScrollBarVisibility=Auto


Whenever possible, avoid using the ScrollBarVisibility.Auto value for the
HorizontalScrollBarVisibility and VerticalScrollBarVisibility properties. These
properties are defined for RichTextBox, ScrollViewer, and TextBox objects, and as an
attached property for the ListBox object. Instead, set ScrollBarVisibility to Disabled,
Hidden, or Visible.

The Auto value is intended for cases when space is limited and scrollbars should only be
displayed when necessary. For example, it may be useful to use this ScrollBarVisibility
value with a ListBox of 30 items as opposed to a TextBox with hundreds of lines of text.

Configure Font Cache Service to Reduce Start-


up Time
The WPF Font Cache service shares font data between WPF applications. The first WPF
application you run starts this service if the service is not already running. If you are
using Windows Vista, you can set the "Windows Presentation Foundation (WPF) Font
Cache 3.0.0.0" service from "Manual" (the default) to "Automatic (Delayed Start)" to
reduce the initial start-up time of WPF applications.

See also
Planning for Application Performance
Taking Advantage of Hardware
Layout and Design
2D Graphics and Imaging
Object Behavior
Application Resources
Text
Data Binding
Animation Tips and Tricks
Application Startup Time
Article • 02/06/2023

The amount of time that is required for a WPF application to start can vary greatly. This
topic describes various techniques for reducing the perceived and actual startup time
for a Windows Presentation Foundation (WPF) application.

Understanding Cold Startup and Warm Startup


Cold startup occurs when your application starts for the first time after a system reboot,
or when you start your application, close it, and then start it again after a long period of
time. When an application starts, if the required pages (code, static data, registry, etc)
are not present in the Windows memory manager's standby list, page faults occur. Disk
access is required to bring the pages into memory.

Warm startup occurs when most of the pages for the main common language runtime
(CLR) components are already loaded in memory, which saves expensive disk access
time. That is why a managed application starts faster when it runs a second time.

Implement a Splash Screen


In cases where there is a significant, unavoidable delay between starting an application
and displaying the first UI, optimize the perceived startup time by using a splash screen.
This approach displays an image almost immediately after the user starts the
application. When the application is ready to display its first UI, the splash screen fades.
Starting in the .NET Framework 3.5 SP1, you can use the SplashScreen class to
implement a splash screen. For more information, see Add a Splash Screen to a WPF
Application.

You can also implement your own splash screen by using native Win32 graphics. Display
your implementation before the Run method is called.

Analyze the Startup Code


Determine the reason for a slow cold startup. Disk I/O may be responsible, but this is
not always the case. In general, you should minimize the use of external resources, such
as network, Web services, or disk.

Before you test, verify that no other running applications or services use managed code
or WPF code.
Start your WPF application immediately after a reboot, and determine how long it takes
to display. If all subsequent launches of your application (warm startup) are much faster,
your cold startup issue is most likely caused by I/O.

If your application's cold startup issue is not related to I/O, it is likely that your
application performs some lengthy initialization or computation, waits for some event to
complete, or requires a lot of JIT compilation at startup. The following sections describe
some of these situations in more detail.

Optimize Module Loading


Use tools such as Process Explorer (Procexp.exe) and Tlist.exe to determine which
modules your application loads. The command Tlist <pid> shows all the modules that
are loaded by a process.

For example, if you are not connecting to the Web and you see that System.Web.dll is
loaded, then there is a module in your application that references this assembly. Check
to make sure that the reference is necessary.

If your application has multiple modules, merge them into a single module. This
approach requires less CLR assembly-loading overhead. Fewer assemblies also mean
that the CLR maintains less state.

Defer Initialization Operations


Consider postponing initialization code until after the main application window is
rendered.

Be aware that initialization may be performed inside a class constructor, and if the
initialization code references other classes, it can cause a cascading effect in which many
class constructors are executed.

Avoid Application Configuration


Consider avoiding application configuration. For example, if an application has simple
configuration requirements and has strict startup time goals, registry entries or a simple
INI file may be a faster startup alternative.

Utilize the GAC


If an assembly is not installed in the Global Assembly Cache (GAC), there are delays
caused by hash verification of strong-named assemblies and by Ngen image validation
if a native image for that assembly is available on the computer. Strong-name
verification is skipped for all assemblies installed in the GAC. For more information, see
Gacutil.exe (Global Assembly Cache Tool).

Use Ngen.exe
Consider using the Native Image Generator (Ngen.exe) on your application. Using
Ngen.exe means trading CPU consumption for more disk access because the native
image generated by Ngen.exe is likely to be larger than the MSIL image.

To improve the warm startup time, you should always use Ngen.exe on your application,
because this avoids the CPU cost of JIT compilation of the application code.

In some cold startup scenarios, using Ngen.exe can also be helpful. This is because the
JIT compiler (mscorjit.dll) does not have to be loaded.

Having both Ngen and JIT modules can have the worst effect. This is because mscorjit.dll
must be loaded, and when the JIT compiler works on your code, many pages in the
Ngen images must be accessed when the JIT compiler reads the assemblies' metadata.

Ngen and ClickOnce


The way you plan to deploy your application can also make a difference in load time.
ClickOnce application deployment does not support Ngen. If you decide to use
Ngen.exe for your application, you will have to use another deployment mechanism,
such as Windows Installer.

For more information, see Ngen.exe (Native Image Generator).

Rebasing and DLL Address Collisions


If you use Ngen.exe, be aware that rebasing can occur when the native images are
loaded in memory. If a DLL is not loaded at its preferred base address because that
address range is already allocated, the Windows loader will load it at another address,
which can be a time-consuming operation.

You can use the Virtual Address Dump (Vadump.exe) tool to check if there are modules
in which all the pages are private. If this is the case, the module may have been rebased
to a different address. Therefore, its pages cannot be shared.
For more information about how to set the base address, see Ngen.exe (Native Image
Generator).

Optimize Authenticode
Authenticode verification adds to the startup time. Authenticode-signed assemblies
have to be verified with the certification authority (CA). This verification can be time
consuming, because it can require connecting to the network several times to download
current certificate revocation lists. It also makes sure that there is a full chain of valid
certificates on the path to a trusted root. This can translate to several seconds of delay
while the assembly is being loaded.

Consider installing the CA certificate on the client computer, or avoid using


Authenticode when it is possible. If you know that your application does not need the
publisher evidence, you do not have to pay the cost of signature verification.

Starting in .NET Framework 3.5, there is a configuration option that allows the
Authenticode verification to be bypassed. To do this, add the following setting to the
app.exe.config file:

XML

<configuration>
<runtime>
<generatePublisherEvidence enabled="false"/>
</runtime>
</configuration>

For more information, see <generatePublisherEvidence> Element.

Compare Performance on Windows Vista


The memory manager in Windows Vista has a technology called SuperFetch. SuperFetch
analyzes memory usage patterns over time to determine the optimal memory content
for a specific user. It works continuously to maintain that content at all times.

This approach differs from the pre-fetch technique used in Windows XP, which preloads
data into memory without analyzing usage patterns. Over time, if the user uses your
WPF application frequently on Windows Vista, the cold startup time of your application
may improve.

Use AppDomains Efficiently


If possible, load assemblies into a domain-neutral code area to make sure that the
native image, if one exists, is used in all AppDomains created in the application.

For the best performance, enforce efficient cross-domain communication by reducing


cross-domain calls. When possible, use calls without arguments or with primitive type
arguments.

Use the NeutralResourcesLanguage Attribute


Use the NeutralResourcesLanguageAttribute to specify the neutral culture for the
ResourceManager. This approach avoids unsuccessful assembly lookups.

Use the BinaryFormatter Class for Serialization


If you must use serialization, use the BinaryFormatter class instead of the XmlSerializer
class. The BinaryFormatter class is implemented in the Base Class Library (BCL) in the
mscorlib.dll assembly. The XmlSerializer is implemented in the System.Xml.dll assembly,
which might be an additional DLL to load.

If you must use the XmlSerializer class, you can achieve better performance if you pre-
generate the serialization assembly.

Configure ClickOnce to Check for Updates


After Startup
If your application uses ClickOnce, avoid network access on startup by configuring
ClickOnce to check the deployment site for updates after the application starts.

If you use the XAML browser application (XBAP) model, keep in mind that ClickOnce
checks the deployment site for updates even if the XBAP is already in the ClickOnce
cache. For more information, see ClickOnce Security and Deployment.

Configure the PresentationFontCache Service


to Start Automatically
The first WPF application to run after a reboot is the PresentationFontCache service. The
service caches the system fonts, improves font access, and improves overall
performance. There is an overhead in starting the service, and in some controlled
environments, consider configuring the service to start automatically when the system
reboots.

Set Data Binding Programmatically


Instead of using XAML to set the DataContext declaratively for the main window,
consider setting it programmatically in the OnActivated method.

See also
SplashScreen
AppDomain
NeutralResourcesLanguageAttribute
ResourceManager
Add a Splash Screen to a WPF Application
Ngen.exe (Native Image Generator)
<generatePublisherEvidence> Element
Walkthrough: Caching Application Data
in a WPF Application
Article • 02/06/2023

Caching enables you to store data in memory for rapid access. When the data is
accessed again, applications can get the data from the cache instead of retrieving it
from the original source. This can improve performance and scalability. In addition,
caching makes data available when the data source is temporarily unavailable.

The .NET Framework provides classes that enable you to use caching in .NET Framework
applications. These classes are located in the System.Runtime.Caching namespace.

7 Note

The System.Runtime.Caching namespace is new in the .NET Framework 4. This


namespace makes caching is available to all .NET Framework applications. In
previous versions of the .NET Framework, caching was available only in the
System.Web namespace and therefore required a dependency on ASP.NET classes.

This walkthrough shows you how to use the caching functionality that is available in the
.NET Framework as part of a Windows Presentation Foundation (WPF) application. In the
walkthrough, you cache the contents of a text file.

Tasks illustrated in this walkthrough include the following:

Creating a WPF application project.

Adding a reference to the .NET Framework 4.

Initializing a cache.

Adding a cache entry that contains the contents of a text file.

Providing an eviction policy for the cache entry.

Monitoring the path of the cached file and notifying the cache instance about
changes to the monitored item.

Prerequisites
In order to complete this walkthrough, you will need:
Visual Studio 2010.

A text file that contains a small amount of text. (You will display the contents of the
text file in a message box.) The code illustrated in the walkthrough assumes that
you are working with the following file:

c:\cache\cacheText.txt

However, you can use any text file and make small changes to the code in this
walkthrough.

Creating a WPF Application Project


You will start by creating a WPF application project.

To create a WPF application

1. Start Visual Studio.

2. In the File menu, click New, and then click New Project.

The New Project dialog box is displayed.

3. Under Installed Templates, select the programming language you want to use
(Visual Basic or Visual C#).

4. In the New Project dialog box, select WPF Application.

7 Note

If you do not see the WPF Application template, make sure that you are
targeting a version of the .NET Framework that supports WPF. In the New
Project dialog box, select .NET Framework 4 from the list.

5. In the Name text box, enter a name for your project. For example, you can enter
WPFCaching.

6. Select the Create directory for solution check box.

7. Click OK.

The WPF Designer opens in Design view and displays the MainWindow.xaml file.
Visual Studio creates the My Project folder, the Application.xaml file, and the
MainWindow.xaml file.
Targeting the .NET Framework and Adding a
Reference to the Caching Assemblies
By default, WPF applications target the .NET Framework 4 Client Profile. To use the
System.Runtime.Caching namespace in a WPF application, the application must target
the .NET Framework 4 (not the .NET Framework 4 Client Profile) and must include a
reference to the namespace.

Therefore, the next step is to change the .NET Framework target and add a reference to
the System.Runtime.Caching namespace.

7 Note

The procedure for changing the .NET Framework target is different in a Visual Basic
project and in a Visual C# project.

To change the target .NET Framework in Visual Basic

1. In Solutions Explorer, right-click the project name, and then click Properties.

The properties window for the application is displayed.

2. Click the Compile tab.

3. At the bottom of the window, click Advanced Compile Options….

The Advanced Compiler Settings dialog box is displayed.

4. In the Target framework (all configurations) list, select .NET Framework 4. (Do not
select .NET Framework 4 Client Profile.)

5. Click OK.

The Target Framework Change dialog box is displayed.

6. In the Target Framework Change dialog box, click Yes.

The project is closed and is then reopened.

7. Add a reference to the caching assembly by following these steps:

a. In Solution Explorer, right-click the name of the project and then click Add
Reference.
b. Select the .NET tab, select System.Runtime.Caching , and then click OK.

To change the target .NET Framework in a Visual C# project


1. In Solution Explorer, right-click the project name and then click Properties.

The properties window for the application is displayed.

2. Click the Application tab.

3. In the Target framework list, select .NET Framework 4. (Do not select .NET
Framework 4 Client Profile.)

4. Add a reference to the caching assembly by following these steps:

a. Right-click the References folder and then click Add Reference.

b. Select the .NET tab, select System.Runtime.Caching , and then click OK.

Adding a Button to the WPF Window


Next, you will add a button control and create an event handler for the button's Click
event. Later you will add code to so when you click the button, the contents of the text
file are cached and displayed.

To add a button control

1. In Solution Explorer, double-click the MainWindow.xaml file to open it.

2. From the Toolbox, under Common WPF Controls, drag a Button control to the
MainWindow window.

3. In the Properties window, set the Content property of the Button control to Get
Cache.

Initializing the Cache and Caching an Entry


Next, you will add the code to perform the following tasks:

Create an instance of the cache class—that is, you will instantiate a new
MemoryCache object.
Specify that the cache uses a HostFileChangeMonitor object to monitor changes in
the text file.

Read the text file and cache its contents as a cache entry.

Display the contents of the cached text file.

To create the cache object

1. Double-click the button you just added in order to create an event handler in the
MainWindow.xaml.cs or MainWindow.Xaml.vb file.

2. At the top of the file (before the class declaration), add the following Imports
(Visual Basic) or using (C#) statements:

C#

using System.Runtime.Caching;
using System.IO;

3. In the event handler, add the following code to instantiate the cache object:

C#

ObjectCache cache = MemoryCache.Default;

The ObjectCache class is a built-in class that provides an in-memory object cache.

4. Add the following code to read the contents of a cache entry named filecontents :

C#

string fileContents = cache["filecontents"] as string;

5. Add the following code to check whether the cache entry named filecontents
exists:

C#

if (fileContents == null)
{

}
If the specified cache entry does not exist, you must read the text file and add it as
a cache entry to the cache.

6. In the if/then block, add the following code to create a new CacheItemPolicy
object that specifies that the cache entry expires after 10 seconds.

C#

CacheItemPolicy policy = new CacheItemPolicy();


policy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(10.0);

If no eviction or expiration information is provided, the default is


InfiniteAbsoluteExpiration, which means the cache entries never expire based only
on an absolute time. Instead, cache entries expire only when there is memory
pressure. As a best practice, you should always explicitly provide either an absolute
or a sliding expiration.

7. Inside the if/then block and following the code you added in the previous step,
add the following code to create a collection for the file paths that you want to
monitor, and to add the path of the text file to the collection:

C#

List<string> filePaths = new List<string>();


filePaths.Add("c:\\cache\\cacheText.txt");

7 Note

If the text file you want to use is not c:\cache\cacheText.txt , specify the path
where the text file is that you want to use.

8. Following the code that you added in the previous step, add the following code to
add a new HostFileChangeMonitor object to the collection of change monitors for
the cache entry:

C#

policy.ChangeMonitors.Add(new HostFileChangeMonitor(filePaths));

The HostFileChangeMonitor object monitors the text file's path and notifies the
cache if changes occur. In this example, the cache entry will expire if the content of
the file changes.
9. Following the code that you added in the previous step, add the following code to
read the contents of the text file:

C#

fileContents = File.ReadAllText("c:\\cache\\cacheText.txt") + "\n" +


DateTime.Now;

The date and time timestamp is added so that you will be able to see when the
cache entry expires.

10. Following the code that you added in the previous step, add the following code to
insert the contents of the file into the cache object as a CacheItem instance:

C#

cache.Set("filecontents", fileContents, policy);

You specify information about how the cache entry should be evicted by passing
the CacheItemPolicy object that you created earlier as a parameter.

11. After the if/then block, add the following code to display the cached file content
in a message box:

C#

MessageBox.Show(fileContents);

12. In the Build menu, click Build WPFCaching to build your project.

Testing Caching in the WPF Application


You can now test the application.

To test caching in the WPF application


1. Press CTRL+F5 to run the application.

The MainWindow window is displayed.

2. Click Get Cache.


The cached content from the text file is displayed in a message box. Notice the
timestamp on the file.

3. Close the message box and then click Get Cache again.

The timestamp is unchanged. This indicates the cached content is displayed.

4. Wait 10 seconds or more and then click Get Cache again.

This time a new timestamp is displayed. This indicates that the policy let the cache
entry expire and that new cached content is displayed.

5. In a text editor, open the text file that you created. Do not make any changes yet.

6. Close the message box and then click Get Cache again.

Notice the timestamp again.

7. Make a change to the text file and then save the file.

8. Close the message box and then click Get Cache again.

This message box contains the updated content from the text file and a new
timestamp. This indicates that the host-file change monitor evicted the cache entry
immediately when you changed the file, even though the absolute timeout period
had not expired.

7 Note

You can increase the eviction time to 20 seconds or more to allow more time
for you to make a change in the file.

Code Example
After you have completed this walkthrough, the code for the project you created will
resemble the following example.

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.Caching;
using System.IO;

namespace WPFCaching
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}

private void button1_Click(object sender, RoutedEventArgs e)


{

ObjectCache cache = MemoryCache.Default;


string fileContents = cache["filecontents"] as string;

if (fileContents == null)
{
CacheItemPolicy policy = new CacheItemPolicy();
policy.AbsoluteExpiration =
DateTimeOffset.Now.AddSeconds(10.0);

List<string> filePaths = new List<string>();


filePaths.Add("c:\\cache\\cacheText.txt");

policy.ChangeMonitors.Add(new
HostFileChangeMonitor(filePaths));

// Fetch the file contents.


fileContents = File.ReadAllText("c:\\cache\\cacheText.txt")
+ "\n" + DateTime.Now.ToString();

cache.Set("filecontents", fileContents, policy);


}
MessageBox.Show(fileContents);
}
}
}

See also
MemoryCache
ObjectCache
System.Runtime.Caching
Caching in .NET Framework Applications
Threading model
Article • 10/27/2023

Windows Presentation Foundation (WPF) is designed to save developers from the


difficulties of threading. As a result, most WPF developers don't write an interface that
uses more than one thread. Because multithreaded programs are complex and difficult
to debug, they should be avoided when single-threaded solutions exist.

No matter how well architected, however, no UI framework is able to provide a single-


threaded solution for every sort of problem. WPF comes close, but there are still
situations where multiple threads improve user interface (UI) responsiveness or
application performance. After discussing some background material, this article
explores some of these situations and then concludes with a discussion of some lower-
level details.

7 Note

This topic discusses threading by using the InvokeAsync method for asynchronous
calls. The InvokeAsync method takes an Action or Func<TResult> as a parameter,
and returns a DispatcherOperation or DispatcherOperation<TResult>, which has a
Task property. You can use the await keyword with either the DispatcherOperation
or the associated Task. If you need to wait synchronously for the Task that is
returned by a DispatcherOperation or DispatcherOperation<TResult>, call the
DispatcherOperationWait extension method. Calling Task.Wait will result in a
deadlock. For more information about using a Task to perform asynchronous
operations, see Task-based asynchronous programming.

To make a synchronous call, use the Invoke method, which also has overloads that
takes a delegate, Action, or Func<TResult> parameter.

Overview and the dispatcher


Typically, WPF applications start with two threads: one for handling rendering and
another for managing the UI. The rendering thread effectively runs hidden in the
background while the UI thread receives input, handles events, paints the screen, and
runs application code. Most applications use a single UI thread, although in some
situations it is best to use several. We'll discuss this with an example later.

The UI thread queues work items inside an object called a Dispatcher. The Dispatcher
selects work items on a priority basis and runs each one to completion. Every UI thread
must have at least one Dispatcher, and each Dispatcher can execute work items in
exactly one thread.

The trick to building responsive, user-friendly applications is to maximize the Dispatcher


throughput by keeping the work items small. This way items never get stale sitting in the
Dispatcher queue waiting for processing. Any perceivable delay between input and
response can frustrate a user.

How then are WPF applications supposed to handle big operations? What if your code
involves a large calculation or needs to query a database on some remote server?
Usually, the answer is to handle the big operation in a separate thread, leaving the UI
thread free to tend to items in the Dispatcher queue. When the big operation is
complete, it can report its result back to the UI thread for display.

Historically, Windows allows UI elements to be accessed only by the thread that created
them. This means that a background thread in charge of some long-running task cannot
update a text box when it is finished. Windows does this to ensure the integrity of UI
components. A list box could look strange if its contents were updated by a background
thread during painting.

WPF has a built-in mutual exclusion mechanism that enforces this coordination. Most
classes in WPF derive from DispatcherObject. At construction, a DispatcherObject stores
a reference to the Dispatcher linked to the currently running thread. In effect, the
DispatcherObject associates with the thread that creates it. During program execution, a
DispatcherObject can call its public VerifyAccess method. VerifyAccess examines the
Dispatcher associated with the current thread and compares it to the Dispatcher
reference stored during construction. If they don't match, VerifyAccess throws an
exception. VerifyAccess is intended to be called at the beginning of every method
belonging to a DispatcherObject.

If only one thread can modify the UI, how do background threads interact with the user?
A background thread can ask the UI thread to perform an operation on its behalf. It
does this by registering a work item with the Dispatcher of the UI thread. The Dispatcher
class provides the methods for registering work items: Dispatcher.InvokeAsync,
Dispatcher.BeginInvoke, and Dispatcher.Invoke. These methods schedule a delegate for
execution. Invoke is a synchronous call – that is, it doesn't return until the UI thread
actually finishes executing the delegate. InvokeAsync and BeginInvoke are asynchronous
and return immediately.

The Dispatcher orders the elements in its queue by priority. There are ten levels that
may be specified when adding an element to the Dispatcher queue. These priorities are
maintained in the DispatcherPriority enumeration.
Single-threaded app with a long-running
calculation
Most graphical user interfaces (GUIs) spend a large portion of their time idle while
waiting for events that are generated in response to user interactions. With careful
programming this idle time can be used constructively, without affecting the
responsiveness of the UI. The WPF threading model doesn't allow input to interrupt an
operation happening in the UI thread. This means you must be sure to return to the
Dispatcher periodically to process pending input events before they get stale.

A sample app demonstrating the concepts of this section can be downloaded from
GitHub for either C# or Visual Basic .

Consider the following example:

This simple application counts upwards from three, searching for prime numbers. When
the user clicks the Start button, the search begins. When the program finds a prime, it
updates the user interface with its discovery. At any point, the user can stop the search.

Although simple enough, the prime number search could go on forever, which presents
some difficulties. If we handled the entire search inside of the click event handler of the
button, we would never give the UI thread a chance to handle other events. The UI
would be unable to respond to input or process messages. It would never repaint and
never respond to button clicks.
We could conduct the prime number search in a separate thread, but then we would
need to deal with synchronization issues. With a single-threaded approach, we can
directly update the label that lists the largest prime found.

If we break up the task of calculation into manageable chunks, we can periodically


return to the Dispatcher and process events. We can give WPF an opportunity to repaint
and process input.

The best way to split processing time between calculation and event handling is to
manage calculation from the Dispatcher. By using the InvokeAsync method, we can
schedule prime number checks in the same queue that UI events are drawn from. In our
example, we schedule only a single prime number check at a time. After the prime
number check is complete, we schedule the next check immediately. This check
proceeds only after pending UI events have been handled.

Microsoft Word accomplishes spell checking using this mechanism. Spell checking is
done in the background using the idle time of the UI thread. Let's take a look at the
code.

The following example shows the XAML that creates the user interface.

) Important

The XAML shown in this article is from a C# project. Visual Basic XAML is slightly
different when declaring the backing class for the XAML.

XAML

<Window x:Class="SDKSamples.PrimeNumber"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Prime Numbers" Width="360" Height="100">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"
Margin="20" >
<Button Content="Start"
Click="StartStopButton_Click"
Name="StartStopButton"
Margin="5,0,5,0" Padding="10,0" />

<TextBlock Margin="10,0,0,0">Biggest Prime Found:</TextBlock>


<TextBlock Name="bigPrime" Margin="4,0,0,0">3</TextBlock>
</StackPanel>
</Window>

The following example shows the code-behind.

C#

using System;
using System.Windows;
using System.Windows.Threading;

namespace SDKSamples
{
public partial class PrimeNumber : Window
{
// Current number to check
private long _num = 3;
private bool _runCalculation = false;

public PrimeNumber() =>


InitializeComponent();

private void StartStopButton_Click(object sender, RoutedEventArgs e)


{
_runCalculation = !_runCalculation;

if (_runCalculation)
{
StartStopButton.Content = "Stop";
StartStopButton.Dispatcher.InvokeAsync(CheckNextNumber,
DispatcherPriority.SystemIdle);
}
else
StartStopButton.Content = "Resume";
}

public void CheckNextNumber()


{
// Reset flag.
_isPrime = true;

for (long i = 3; i <= Math.Sqrt(_num); i++)


{
if (_num % i == 0)
{
// Set not a prime flag to true.
_isPrime = false;
break;
}
}

// If a prime number, update the UI text


if (_isPrime)
bigPrime.Text = _num.ToString();

_num += 2;

// Requeue this method on the dispatcher


if (_runCalculation)
StartStopButton.Dispatcher.InvokeAsync(CheckNextNumber,
DispatcherPriority.SystemIdle);
}

private bool _isPrime = false;


}
}

Besides updating the text on the Button, the StartStopButton_Click handler is


responsible for scheduling the first prime number check by adding a delegate to the
Dispatcher queue. Sometime after this event handler has completed its work, the
Dispatcher will select the delegate for execution.

As we mentioned earlier, InvokeAsync is the Dispatcher member used to schedule a


delegate for execution. In this case, we choose the SystemIdle priority. The Dispatcher
will execute this delegate only when there are no important events to process. UI
responsiveness is more important than number checking. We also pass a new delegate
representing the number-checking routine.

C#

public void CheckNextNumber()


{
// Reset flag.
_isPrime = true;

for (long i = 3; i <= Math.Sqrt(_num); i++)


{
if (_num % i == 0)
{
// Set not a prime flag to true.
_isPrime = false;
break;
}
}

// If a prime number, update the UI text


if (_isPrime)
bigPrime.Text = _num.ToString();

_num += 2;

// Requeue this method on the dispatcher


if (_runCalculation)
StartStopButton.Dispatcher.InvokeAsync(CheckNextNumber,
DispatcherPriority.SystemIdle);
}

private bool _isPrime = false;

This method checks if the next odd number is prime. If it is prime, the method directly
updates the bigPrime TextBlock to reflect its discovery. We can do this because the
calculation is occurring in the same thread that was used to create the control. Had we
chosen to use a separate thread for the calculation, we would have to use a more
complicated synchronization mechanism and execute the update in the UI thread. We'll
demonstrate this situation next.

Multiple windows, multiple threads


Some WPF applications require multiple top-level windows. It's perfectly acceptable for
one Thread/Dispatcher combination to manage multiple windows, but sometimes
several threads do a better job. This is especially true if there's any chance that one of
the windows will monopolize the thread.

Windows Explorer works in this fashion. Each new Explorer window belongs to the
original process, but it's created under the control of an independent thread. When
Explorer becomes nonresponsive, such as when looking for network resources, other
Explorer windows continue to be responsive and usable.

We can demonstrate this concept with the following example.


This example contains a window with a rotating ‼️glyph, a Pause button, and two other
buttons that create a new window under the current thread or in a new thread. The ‼️
glyph is constantly rotating until the Pause button is pressed, which pauses the thread
for five seconds. At the bottom of the window, the thread identifier is displayed.

When the Pause button is pressed, all windows under the same thread become
nonresponsive. Any window under a different thread continues to work normally.

The following example is the XAML to the window:

XAML

<Window x:Class="SDKSamples.MultiWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Thread Hosted Window" Width="360" Height="180"
SizeToContent="Height" ResizeMode="NoResize" Loaded="Window_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<TextBlock HorizontalAlignment="Right" Margin="30,0" Text="‼️


"
FontSize="50" FontWeight="ExtraBold"
Foreground="Magenta" RenderTransformOrigin="0.5,0.5"
Name="RotatedTextBlock">
<TextBlock.RenderTransform>
<RotateTransform Angle="0" />
</TextBlock.RenderTransform>
<TextBlock.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="RotatedTextBlock"
Storyboard.TargetProperty="
(UIElement.RenderTransform).(RotateTransform.Angle)"
From="0" To="360" Duration="0:0:5"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>

<StackPanel Orientation="Horizontal" VerticalAlignment="Center"


Margin="20" >
<Button Content="Pause" Click="PauseButton_Click" Margin="5,0"
Padding="10,0" />
<TextBlock Margin="5,0,0,0" Text="<-- Pause for 5 seconds" />
</StackPanel>

<StackPanel Grid.Row="1" Margin="10">


<Button Content="Create 'Same Thread' Window"
Click="SameThreadWindow_Click" />
<Button Content="Create 'New Thread' Window"
Click="NewThreadWindow_Click" Margin="0,10,0,0" />
</StackPanel>

<StatusBar Grid.Row="2" VerticalAlignment="Bottom">


<StatusBarItem Content="Thread ID" Name="ThreadStatusItem" />
</StatusBar>

</Grid>
</Window>

The following example shows the code-behind.

C#

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace SDKSamples
{
public partial class MultiWindow : Window
{
public MultiWindow() =>
InitializeComponent();

private void Window_Loaded(object sender, RoutedEventArgs e) =>


ThreadStatusItem.Content = $"Thread ID:
{Thread.CurrentThread.ManagedThreadId}";

private void PauseButton_Click(object sender, RoutedEventArgs e) =>


Task.Delay(TimeSpan.FromSeconds(5)).Wait();

private void SameThreadWindow_Click(object sender, RoutedEventArgs


e) =>
new MultiWindow().Show();

private void NewThreadWindow_Click(object sender, RoutedEventArgs e)


{
Thread newWindowThread = new Thread(ThreadStartingPoint);
newWindowThread.SetApartmentState(ApartmentState.STA);
newWindowThread.IsBackground = true;
newWindowThread.Start();
}

private void ThreadStartingPoint()


{
new MultiWindow().Show();

System.Windows.Threading.Dispatcher.Run();
}
}
}

The following are some of the details to be noted:

The Task.Delay(TimeSpan) task is used to cause the current thread to pause for five
seconds when the Pause button is pressed.

C#

private void PauseButton_Click(object sender, RoutedEventArgs e) =>


Task.Delay(TimeSpan.FromSeconds(5)).Wait();

The SameThreadWindow_Click event handler immediently shows a new window


under the current thread. The NewThreadWindow_Click event handler creates a new
thread that starts executing the ThreadStartingPoint method, which in turn shows
a new window, as described in the next bullet point.

C#
private void SameThreadWindow_Click(object sender, RoutedEventArgs e)
=>
new MultiWindow().Show();

private void NewThreadWindow_Click(object sender, RoutedEventArgs e)


{
Thread newWindowThread = new Thread(ThreadStartingPoint);
newWindowThread.SetApartmentState(ApartmentState.STA);
newWindowThread.IsBackground = true;
newWindowThread.Start();
}

The ThreadStartingPoint method is the starting point for the new thread. The new
window is created under the control of this thread. WPF automatically creates a
new System.Windows.Threading.Dispatcher to manage the new thread. All we have
to do to make the window functional is to start the
System.Windows.Threading.Dispatcher.

C#

private void ThreadStartingPoint()


{
new MultiWindow().Show();

System.Windows.Threading.Dispatcher.Run();
}

A sample app demonstrating the concepts of this section can be downloaded from
GitHub for either C# or Visual Basic .

Handle a blocking operation with Task.Run


Handling blocking operations in a graphical application can be difficult. We don't want
to call blocking methods from event handlers because the application appears to freeze
up. The previous example created new windows in their own thread, letting each
window run independent from one another. While we can create a new thread with
System.Windows.Threading.Dispatcher, it becomes difficult to synchronize the new
thread with the main UI thread after the work is completed. Because the new thread
can't modify the UI directly, we have to use Dispatcher.InvokeAsync,
Dispatcher.BeginInvoke, or Dispatcher.Invoke, to insert delegates into the Dispatcher of
the UI thread. Eventually, these delegates are executed with permission to modify UI
elements.
There's an easier way to run the code on a new thread while synchronizing the results,
the Task-based asynchronous pattern (TAP). It's based on the Task and Task<TResult>
types in the System.Threading.Tasks namespace, which are used to represent
asynchronous operations. TAP uses a single method to represent the initiation and
completion of an asynchronous operation. There are a few benefits to this pattern:

The caller of a Task can choose to run the code asynchronously or synchronously.
Progress can be reported from the Task .
The calling code can suspend execution and wait for the result of the operation.

Task.Run example
In this example, we mimic a remote procedure call that retrieves a weather forecast.
When the button is clicked, the UI is updated to indicate that the data fetch is in
progress, while a task is started to mimic fetching the weather forecast. When the task is
started, the button event handler code is suspended until the task finishes. After the task
finishes, the event handler code continues to run. The code is suspended, and it doesn't
block the rest of the UI thread. The synchronization context of WPF handles suspending
the code, which allows WPF to continue to run.
A sample app demonstrating the concepts of this section can be downloaded from
GitHub for either C# or Visual Basic . The XAML for this example is quite large and
not provided in this article. Use the previous GitHub links to browse the XAML. The
XAML uses a single button to fetch the weather.

Consider the code-behind to the XAML:

C#
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Threading.Tasks;

namespace SDKSamples
{
public partial class Weather : Window
{
public Weather() =>
InitializeComponent();

private async void FetchButton_Click(object sender, RoutedEventArgs


e)
{
// Change the status image and start the rotation animation.
fetchButton.IsEnabled = false;
fetchButton.Content = "Contacting Server";
weatherText.Text = "";

((Storyboard)Resources["HideWeatherImageStoryboard"]).Begin(this);

// Asynchronously fetch the weather forecast on a different


thread and pause this code.
string weather = await Task.Run(FetchWeatherFromServerAsync);

// After async data returns, process it...


// Set the weather image
if (weather == "sunny")
weatherIndicatorImage.Source =
(ImageSource)Resources["SunnyImageSource"];

else if (weather == "rainy")


weatherIndicatorImage.Source =
(ImageSource)Resources["RainingImageSource"];

//Stop clock animation

((Storyboard)Resources["ShowClockFaceStoryboard"]).Stop(ClockImage);

((Storyboard)Resources["HideClockFaceStoryboard"]).Begin(ClockImage);

//Update UI text
fetchButton.IsEnabled = true;
fetchButton.Content = "Fetch Forecast";
weatherText.Text = weather;
}

private async Task<string> FetchWeatherFromServerAsync()


{
// Simulate the delay from network access
await Task.Delay(TimeSpan.FromSeconds(4));
// Tried and true method for weather forecasting - random
numbers
Random rand = new Random();

if (rand.Next(2) == 0)
return "rainy";

else
return "sunny";
}

private void HideClockFaceStoryboard_Completed(object sender,


EventArgs args) =>

((Storyboard)Resources["ShowWeatherImageStoryboard"]).Begin(ClockImage);

private void HideWeatherImageStoryboard_Completed(object sender,


EventArgs args) =>

((Storyboard)Resources["ShowClockFaceStoryboard"]).Begin(ClockImage, true);
}
}

The following are some of the details to be noted.

The button event handler

C#

private async void FetchButton_Click(object sender, RoutedEventArgs e)


{
// Change the status image and start the rotation animation.
fetchButton.IsEnabled = false;
fetchButton.Content = "Contacting Server";
weatherText.Text = "";
((Storyboard)Resources["HideWeatherImageStoryboard"]).Begin(this);

// Asynchronously fetch the weather forecast on a different thread


and pause this code.
string weather = await Task.Run(FetchWeatherFromServerAsync);

// After async data returns, process it...


// Set the weather image
if (weather == "sunny")
weatherIndicatorImage.Source =
(ImageSource)Resources["SunnyImageSource"];

else if (weather == "rainy")


weatherIndicatorImage.Source =
(ImageSource)Resources["RainingImageSource"];

//Stop clock animation


((Storyboard)Resources["ShowClockFaceStoryboard"]).Stop(ClockImage);

((Storyboard)Resources["HideClockFaceStoryboard"]).Begin(ClockImage);

//Update UI text
fetchButton.IsEnabled = true;
fetchButton.Content = "Fetch Forecast";
weatherText.Text = weather;
}

Notice that the event handler was declared with async (or Async with Visual Basic).
An "async" method allows suspension of the code when an awaited method, such
as FetchWeatherFromServerAsync , is called. This is designated by the await (or
Await with Visual Basic) keyword. Until the FetchWeatherFromServerAsync finishes,

the button's handler code is suspended and control is returned to the caller. This is
similar to a synchronous method except that a synchronous method waits for
every operation in the method to finish after which control is returned to the caller.

Awaited methods utilize the threading context of the current method, which with
the button handler, is the UI thread. This means that calling await
FetchWeatherFromServerAsync(); (Or Await FetchWeatherFromServerAsync() with

Visual Basic) causes the code in FetchWeatherFromServerAsync to run on the UI


thread, but isn't executed on the dispatcher has time to run it, similar to how the
Single-threaded app with a long-running calculation example operates. However,
notice that await Task.Run is used. This creates a new thread on the thread pool
for the designated task instead of the current thread. So
FetchWeatherFromServerAsync runs on its own thread.

Fetching the Weather

C#

private async Task<string> FetchWeatherFromServerAsync()


{
// Simulate the delay from network access
await Task.Delay(TimeSpan.FromSeconds(4));

// Tried and true method for weather forecasting - random numbers


Random rand = new Random();

if (rand.Next(2) == 0)
return "rainy";

else
return "sunny";
}
To keep things simple, we don't actually have any networking code in this example.
Instead, we simulate the delay of network access by putting our new thread to
sleep for four seconds. In this time, the original UI thread is still running and
responding to UI events while the button's event handler is paused until the new
thread completes. To demonstrate this, we've left an animation running, and you
can resize the window. If the UI thread was paused or delayed, the animation
wouldn't be shown and you couldn't interact with the window.

When the Task.Delay is finished, and we've randomly selected our weather
forecast, the weather status is returned to the caller.

Updating the UI

C#

private async void FetchButton_Click(object sender, RoutedEventArgs e)


{
// Change the status image and start the rotation animation.
fetchButton.IsEnabled = false;
fetchButton.Content = "Contacting Server";
weatherText.Text = "";
((Storyboard)Resources["HideWeatherImageStoryboard"]).Begin(this);

// Asynchronously fetch the weather forecast on a different thread


and pause this code.
string weather = await Task.Run(FetchWeatherFromServerAsync);

// After async data returns, process it...


// Set the weather image
if (weather == "sunny")
weatherIndicatorImage.Source =
(ImageSource)Resources["SunnyImageSource"];

else if (weather == "rainy")


weatherIndicatorImage.Source =
(ImageSource)Resources["RainingImageSource"];

//Stop clock animation

((Storyboard)Resources["ShowClockFaceStoryboard"]).Stop(ClockImage);

((Storyboard)Resources["HideClockFaceStoryboard"]).Begin(ClockImage);

//Update UI text
fetchButton.IsEnabled = true;
fetchButton.Content = "Fetch Forecast";
weatherText.Text = weather;
}
When the task finishes and the UI thread has time, the caller of Task.Run , the
button's event handler, is resumed. The rest of the method stops the clock
animation and chooses an image to describe the weather. It displays this image
and enables the "fetch forecast" button.

A sample app demonstrating the concepts of this section can be downloaded from
GitHub for either C# or Visual Basic .

Technical details and stumbling points


The following sections describe some of the details and stumbling points you may come
across with multithreading.

Nested pumping
Sometimes it is not feasible to completely lock up the UI thread. Let's consider the Show
method of the MessageBox class. Show doesn't return until the user clicks the OK
button. It does, however, create a window that must have a message loop in order to be
interactive. While we are waiting for the user to click OK, the original application window
does not respond to user input. It does, however, continue to process paint messages.
The original window redraws itself when covered and revealed.

Some thread must be in charge of the message box window. WPF could create a new
thread just for the message box window, but this thread would be unable to paint the
disabled elements in the original window (remember the earlier discussion of mutual
exclusion). Instead, WPF uses a nested message processing system. The Dispatcher class
includes a special method called PushFrame, which stores an application's current
execution point then begins a new message loop. When the nested message loop
finishes, execution resumes after the original PushFrame call.
In this case, PushFrame maintains the program context at the call to MessageBox.Show,
and it starts a new message loop to repaint the background window and handle input to
the message box window. When the user clicks OK and clears the pop-up window, the
nested loop exits and control resumes after the call to Show.

Stale routed events


The routed event system in WPF notifies entire trees when events are raised.

XAML

<Canvas MouseLeftButtonDown="handler1"
Width="100"
Height="100"
>
<Ellipse Width="50"
Height="50"
Fill="Blue"
Canvas.Left="30"
Canvas.Top="50"
MouseLeftButtonDown="handler2"
/>
</Canvas>

When the left mouse button is pressed over the ellipse, handler2 is executed. After
handler2 finishes, the event is passed along to the Canvas object, which uses handler1

to process it. This happens only if handler2 does not explicitly mark the event object as
handled.

It's possible that handler2 will take a great deal of time processing this event. handler2
might use PushFrame to begin a nested message loop that doesn't return for hours. If
handler2 does not mark the event as handled when this message loop is complete, the

event is passed up the tree even though it is very old.

Reentrancy and locking


The locking mechanism of the common language runtime (CLR) doesn't behave exactly
as one might imagine; one might expect a thread to cease operation completely when
requesting a lock. In actuality, the thread continues to receive and process high-priority
messages. This helps prevent deadlocks and make interfaces minimally responsive, but it
introduces the possibility for subtle bugs. The vast majority of the time you don't need
to know anything about this, but under rare circumstances (usually involving Win32
window messages or COM STA components) this can be worth knowing.
Most interfaces are not built with thread safety in mind because developers work under
the assumption that a UI is never accessed by more than one thread. In this case, that
single thread may make environmental changes at unexpected times, causing those ill
effects that the DispatcherObject mutual exclusion mechanism is supposed to solve.
Consider the following pseudocode:

Most of the time that's the right thing, but there are times in WPF where such
unexpected reentrancy can really cause problems. So, at certain key times, WPF calls
DisableProcessing, which changes the lock instruction for that thread to use the WPF
reentrancy-free lock, instead of the usual CLR lock.

So why did the CLR team choose this behavior? It had to do with COM STA objects and
the finalization thread. When an object is garbage collected, its Finalize method is run
on the dedicated finalizer thread, not the UI thread. And therein lies the problem,
because a COM STA object that was created on the UI thread can only be disposed on
the UI thread. The CLR does the equivalent of a BeginInvoke (in this case using Win32's
SendMessage ). But if the UI thread is busy, the finalizer thread is stalled and the COM STA

object can't be disposed, which creates a serious memory leak. So the CLR team made
the tough call to make locks work the way they do.

The task for WPF is to avoid unexpected reentrancy without reintroducing the memory
leak, which is why we don't block reentrancy everywhere.

See also
Single-Threaded Application with Long-Running Calculation Sample

6 Collaborate with us on
GitHub .NET Desktop feedback
The source for this content can The .NET Desktop documentation is
be found on GitHub, where you open source. Provide feedback here.
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
WPF Unmanaged API Reference
Article • 02/06/2023

Windows Presentation Foundation (WPF) libraries expose a number of unmanaged


functions that are intended for internal use only. They should not be called from user
code.

In This Section
Activate Function
CreateIDispatchSTAForwarder Function
Deactivate Function
ForwardTranslateAccelerator Function
LoadFromHistory Function
ProcessUnhandledException Function
SaveToHistory Function
SetFakeActiveWindow Function

See also
Advanced
Activate Function (WPF Unmanaged API
Reference)
Article • 07/20/2022

This API supports the Windows Presentation Foundation (WPF) infrastructure and is not
intended to be used directly from your code.

Used by the Windows Presentation Foundation (WPF) infrastructure for windows


management.

Syntax
C++

void Activate(
const ActivateParameters* pParameters,
__deref_out_ecount(1) LPUNKNOWN* ppInner,
);

Parameters
pParameters

A pointer to the window's activation parameters.

ppInner

A pointer to the address of a single-element buffer that contains a pointer to an


IOleDocument object.

Requirements
Platforms: See .NET Framework System Requirements.

DLL:

In the .NET Framework 3.0 and 3.5: PresentationHostDLL.dll

In the .NET Framework 4 and later: PresentationHost_v0400.dll

.NET Framework Version: Available since 3.0


See also
WPF Unmanaged API Reference
CreateIDispatchSTAForwarder Function
(WPF Unmanaged API Reference)
Article • 02/06/2023

This API supports the Windows Presentation Foundation (WPF) infrastructure and is not
intended to be used directly from your code.

Used by the Windows Presentation Foundation (WPF) infrastructure for thread and
windows management.

Syntax
C++

HRESULT CreateIDispatchSTAForwarder(
__in IDispatch *pDispatchDelegate,
__deref_out IDispatch **ppForwarder
)

Parameters

Property Value/Return Value


pDispatchDelegate
A pointer to an IDispatch interface.

ppForwarder
A pointer to the address of an IDispatch interface.

Requirements
Platforms: See .NET Framework System Requirements.

DLL:

In the .NET Framework 3.0 and 3.5: PresentationHostDLL.dll

In the .NET Framework 4 and later: PresentationHost_v0400.dll

.NET Framework Version: Available since 3.0


See also
WPF Unmanaged API Reference
Deactivate Function (WPF Unmanaged
API Reference)
Article • 02/06/2023

This API supports the Windows Presentation Foundation (WPF) infrastructure and is not
intended to be used directly from your code.

Used by the Windows Presentation Foundation (WPF) infrastructure for windows


management.

Syntax
C++

void Deactivate()

Requirements
Platforms: See .NET Framework System Requirements.

DLL:

In the .NET Framework 3.0 and 3.5: PresentationHostDLL.dll

In the .NET Framework 4 and later: PresentationHost_v0400.dll

.NET Framework Version: Available since 3.0

See also
WPF Unmanaged API Reference
ForwardTranslateAccelerator Function
(WPF Unmanaged API Reference)
Article • 02/06/2023

This API supports the Windows Presentation Foundation (WPF) infrastructure and is not
intended to be used directly from your code.

Used by the Windows Presentation Foundation (WPF) infrastructure for windows


management.

Syntax
C++

HRESULT ForwardTranslateAccelerator(
MSG* pMsg,
VARIANT_BOOL appUnhandled
)

Parameters
pMsg
A pointer to a message.

appUnhandled
true when the app has already been given a chance to handle the input message, but
has not handled it; otherwise, false .

Requirements
Platforms: See .NET Framework System Requirements.

DLL:

In the .NET Framework 3.0 and 3.5: PresentationHostDLL.dll

In the .NET Framework 4 and later: PresentationHost_v0400.dll

.NET Framework Version: Available since 3.0


See also
WPF Unmanaged API Reference
LoadFromHistory Function (WPF
Unmanaged API Reference)
Article • 02/06/2023

This API supports the Windows Presentation Foundation (WPF) infrastructure and is not
intended to be used directly from your code.

Used by the Windows Presentation Foundation (WPF) infrastructure for windows


management.

Syntax
C++

HRESULT LoadFromHistory_export(
IStream* pHistoryStream,
IBindCtx* pBindCtx
)

Parameters
pHistoryStream
A pointer to a stream of history information.

pBindCtx
A pointer to a bind context.

Requirements
Platforms: See .NET Framework System Requirements.

DLL:

In the .NET Framework 3.0 and 3.5: PresentationHostDLL.dll

In the .NET Framework 4 and later: PresentationHost_v0400.dll

.NET Framework Version: Available since 3.0

See also
WPF Unmanaged API Reference
ProcessUnhandledException Function
(WPF Unmanaged API Reference)
Article • 02/06/2023

This API supports the Windows Presentation Foundation (WPF) infrastructure and is not
intended to be used directly from your code.

Used by the Windows Presentation Foundation (WPF) infrastructure for exception


handling.

Syntax
C++

void __stdcall ProcessUnhandledException(


__in_ecount(1) BSTR errorMsg
)

Parameters
errorMsg
The error message.

Requirements
Platforms: See .NET Framework System Requirements.

DLL:

In the .NET Framework 3.0 and 3.5: PresentationHostDLL.dll

In the .NET Framework 4 and later: PresentationHost_v0400.dll

.NET Framework Version: Available since 3.0

See also
WPF Unmanaged API Reference
SaveToHistory Function (WPF
Unmanaged API Reference)
Article • 02/06/2023

This API supports the Windows Presentation Foundation (WPF) infrastructure and is not
intended to be used directly from your code.

Used by the Windows Presentation Foundation (WPF) infrastructure for windows


management.

Syntax
C++

HRESULT SaveToHistory(
__in_ecount(1) IStream* pHistoryStream
)

Parameters
pHistoryStream
A pointer to the history stream.

Requirements
Platforms: See .NET Framework System Requirements.

DLL:

In the .NET Framework 3.0 and 3.5: PresentationHostDLL.dll

In the .NET Framework 4 and later: PresentationHost_v0400.dll

.NET Framework Version: Available since 3.0

See also
WPF Unmanaged API Reference
SetFakeActiveWindow Function (WPF
Unmanaged API Reference)
Article • 02/06/2023

This API supports the Windows Presentation Foundation (WPF) infrastructure and is not
intended to be used directly from your code.

Used by the Windows Presentation Foundation (WPF) infrastructure for windows


management.

Syntax
C++

void __stdcall SetFakeActiveWindow(


HWND hwnd
)

Parameters
hwnd
A window handle.

Requirements
Platforms: See .NET Framework System Requirements.

DLL: PresentationHost_v0400.dll

.NET Framework Version: Available since 4

See also
WPF Unmanaged API Reference

You might also like