Dotnet Desktop WPF Advanced Netframeworkdesktop 4.8
Dotnet Desktop WPF Advanced Netframeworkdesktop 4.8
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).
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.
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.
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
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>
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.
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.
XAML
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>
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.
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.
XAML
<StackPanel>
<StackPanel.Children>
<!--<UIElementCollection>-->
<Button>First Button</Button>
<Button>Second Button</Button>
<!--</UIElementCollection>-->
</StackPanel.Children>
</StackPanel>
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
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
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.
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.
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.
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.
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
C#
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 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.
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.
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.
For more information about the XAML language specification, download [MS-XAML]
from the Microsoft Download Center.
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.
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
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.
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.
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.
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
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.
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 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
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
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
<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>
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.
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:
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 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.
Attribute Description
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.
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
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.
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 .
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.
Prerequisites
x:Code
Prerequisites
This topic assumes that you have read the XAML in WPF and have some basic
knowledge of the CLR and object-oriented programming.
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>
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
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.
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.
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.
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.
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.
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.
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.
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.)
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
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.
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.
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 (<>).
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.
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.
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.
*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.
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.
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.
<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 .
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.
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.
The syntax takes the following possible named tokens and following values:
clr-namespace: The CLR namespace declared within the assembly that contains the
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.
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>
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.
3. If the short name + public key token of a qualified name matches the assembly
that the markup was loaded from, return that 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.
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.
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.
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.
For an example of using XAML namescope APIs in code, see Define a Name Scope.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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} .
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.
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.
Mode: value is a constant name from the BindingMode enumeration. For example,
{Binding Mode=OneWay} .
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.
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.
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.
XmlNamespaceManager
Remarks
) Important
Describing data binding at a basic level is not covered in this topic. See Data Binding
Overview.
7 Note
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
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 Values
Value Description
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.
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.
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:
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.
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.
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
In the WPF XAML reader implementation, the handling for this markup extension is
defined by the ComponentResourceKey class.
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 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.
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
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:
For example, to specify the date of June 1, 2010, use the following string (time
components are all entered as 0):
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.
<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
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 .
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
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.
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
<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
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
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}" .../>
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.
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
<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.
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.
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
StaticResource can also be used in a verbose attribute usage that specifies the
XML
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.
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 Values
Value Description
sourceProperty Another dependency property that exists on the type being templated,
specified by its DependencyProperty.Name.
- or -
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
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
XML
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.
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.
<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
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.
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.
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.
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.
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.
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 .
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
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 / 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 ( # ).
Multiple Indexers
XAML
or
XAML
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
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.
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.
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.
propertyName must resolve to be the name of a dependency property that exists on the
specified TargetName type.
Attached Properties
XML
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.
<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.
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.
<object
xmlns:ignorablePrefix="ignorableUri"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="ignorablePrefix"...>
<ignorablePrefix1:ThisElementCanBeIgnored/>
</object>
<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
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.
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" .
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.
<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.
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" .
See also
mc:Ignorable Attribute
XAML in WPF
Base Elements
Article • 02/06/2023
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
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:
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.
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.
If you create a class that derives from ContentElement, you inherit the following
functionality in addition to that provided by DependencyObject:
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.
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.
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#
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
C#
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
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#
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.
It has properties set by a dynamic resource. (See the XAML Resources for more
information about dynamic resources.)
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#
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
myButton.Background = myBrush;
try {
To avoid throwing this exception, you can use the IsFrozen method to determine
whether a Freezable is frozen.
C#
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
myButton.Background = myBrush;
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.
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>
<StackPanel>
</StackPanel>
</Page>
To use the Freeze attribute, you must map to the presentation options namespace:
http://schemas.microsoft.com/winfx/2006/xaml/presentation/options .
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"
"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#
myButton.Background = myBrush;
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.
Easy cloning: the Freezable class has already implemented several methods that
produce deep clones.
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.
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.
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);
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#
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#
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.
element's rendering position and the rendering position of its neighbor elements and
children.
7 Note
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#
XAML
C#
XAML
The following example shows how to apply Padding to a parent Border element.
C#
XAML
<Border Background="LightBlue"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="45"
Padding="25">
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#
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>
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
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
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;
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>
<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>
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.
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#
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
IsFrozen
Freezable Objects Overview
How-to Topics
How to: Handle a Loaded Event
Article • 02/06/2023
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#
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
C#
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 properties that are set by a dynamic resource. For more information about
dynamic resources, see the XAML Resources.
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#
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#
myButton.Background = myBrush;
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
XAML
XAML
XAML
XAML
<Button Content="Flip me!" Padding="5"
RenderTransformOrigin="0.5,0.5">
<Button.RenderTransform>
<ScaleTransform ScaleY="-1" />
</Button.RenderTransform>
</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.
C#
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
Example
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);
}
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#
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.
C#
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.
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.
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
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.
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.
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.
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
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.
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);
}
/*
* 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");
// now render the altered version, with the element built up and
initialized
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#
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 SingletonPanel()
{
}
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.
The following lists the terminology that is used with dependency properties:
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#
XAML
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.
XAML
<Button Content="Button!">
<Button.Background>
<ImageBrush ImageSource="wavy.jpg"/>
</Button.Background>
</Button>
C#
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.
Resources
Data binding
Styles
Animations
Metadata overrides
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
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
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.
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
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.
C#
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
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>
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.
See also
Custom Dependency Properties
Read-Only Dependency Properties
XAML in WPF
WPF Architecture
Attached Properties Overview
Article • 03/17/2022
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.
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).
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.
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#
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.
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.
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 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:
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#
AttachedPropertyBrowsableAttribute
AttachedPropertyBrowsableForChildrenAttribute
AttachedPropertyBrowsableForTypeAttribute
AttachedPropertyBrowsableWhenAttributePresentAttribute
For more advanced usage scenarios for dependency properties and attached
properties, see Custom Dependency Properties.
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.
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.
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.
C#
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.
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#
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:
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.
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.
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.
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, 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.
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.
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
Prerequisites
This topic assumes that you understand dependency properties from the perspective of
a consumer of existing dependency properties on WPF applications.
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.
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
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.
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.
7 Note
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.
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#
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.
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#
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#
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#
C#
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.
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".
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.
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.
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.
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.
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.
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>
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.
1. Property system coercion. For details on coercion, 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.
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:
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.
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 .
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 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.
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.
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.
See also
DependencyObject
DependencyProperty
Dependency Properties Overview
Custom Dependency Properties
Dependency Property Callbacks and Validation
Read-Only Dependency Properties
Article • 02/06/2023
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.
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.
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.
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.
See also
Dependency Properties Overview
Custom Dependency Properties
Styling and Templating
Property Value Inheritance
Article • 02/06/2023
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
See also
Dependency Property Metadata
Attached Properties Overview
Dependency Property Value Precedence
Dependency Property Security
Article • 02/06/2023
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
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.
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.
The following example code (and subsequent examples) is a pseudo-C# example that
violates this rule and explains the problem:
C#
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.
C#
C#
C#
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.
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.
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#
// ...
}
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#
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#
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.
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 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.
C#
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#
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
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#
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#
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.
C#
C#
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.
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.
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.
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>
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-->...
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.
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#
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.
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.
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#
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.
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.
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 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.
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.
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.
XAML
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 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:
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.
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.
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
Prerequisites
This topic assumes that you have read Routed Events Overview and XAML in WPF.
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
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.
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.
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.
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.
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#
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.
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.
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.
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.
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.
Once class handling on a node is complete, the instance listeners are considered.
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.
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.
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.
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.
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.
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.
IsMouseCapturedChanged.
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.
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).
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.
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.
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.
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.
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.
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.
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 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.
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#
C#
SomeEventWeakEventManager.AddHandler(source, OnSomeEvent);
Similarly, if your code uses the following pattern to unsubscribe from an event:
C#
source.SomeEvent -= new SomeEventEventHandler(OnSomeEvent);
C#
SomeEventWeakEventManager.RemoveHandler(source, OnSomeEvent);
C#
WeakEventManager<EventSource, SomeEventEventArgs>.AddHandler(source,
"SomeEvent", source_SomeEvent);
C#
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);
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);
}
}
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#
C#
SomeEventWeakEventManager.AddHandler(source, OnSomeEvent);
C#
SomeEventWeakEventManager.RemoveHandler(source, OnSomeEvent);
See also
WeakEventManager
IWeakEventListener
Routed Events Overview
Data Binding Overview
Events How-to Topics
Article • 02/06/2023
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 Handles keyword as part of the event handler definition. This technique is
not shown here; see Visual Basic and WPF Event Handling.
XAML
C#
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#
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#
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
C#
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#
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
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.
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#
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.
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.
XAML
<StackPanel>
<Button Background="AliceBlue"
KeyDown="OnButtonKeyDown"
Content="Button1"/>
</StackPanel>
C#
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#
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#
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#
// If source is a Button.
if (source != null)
{
source.Background = Brushes.SlateGray;
}
}
C#
// 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.
XAML
<StackPanel KeyDown="OnTextInputKeyDown">
<Button Click="OnTextInputButtonClick"
Content="Open" />
<TextBox> . . . </TextBox>
</StackPanel>
C#
C#
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.
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.
Windows 7.
Terminology
The following terms are used when touch is discussed.
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 touch device represents a device that produces touch input, such as a single
finger on a touchscreen.
ComboBox
ContextMenu
DataGrid
ListBox
ListView
MenuItem
TextBox
ToolBar
TreeView
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.
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.
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.
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.
ManipulationStarting
ManipulationStarted
ManipulationDelta
ManipulationInertiaStarting
ManipulationCompleted
ManipulationBoundaryFeedback
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.
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
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 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 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.
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#
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.
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#
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.
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.
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#
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
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.
Command Library
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#
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.
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.
XAML
<StackPanel>
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Command="ApplicationCommands.Properties" />
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
C#
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.
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#
this.InputBindings.Add(OpenCmdKeybinding);
C#
ApplicationCommands.Open.InputGestures.Add(OpenCmdKeyGesture);
CommandBinding
A CommandBinding associates a command with the event handlers that implement the
command.
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#
this.CommandBindings.Add(OpenCmdBinding);
C#
C#
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#
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.
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).
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#
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.
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#
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#
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#
navigationMenu.Items.Add(item1);
navigationMenu.Items.Add(item2);
navigationMenu.Items.Add(item3);
navigationMenu.Items.Add(item4);
KeyboardNavigation.SetTabNavigation(navigationMenu,
KeyboardNavigationMode.Cycle);
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.
XAML
When the TextBox obtains keyboard focus, the Background property of the TextBox is
changed to LightBlue.
C#
if (source != null)
{
// Change the TextBox color when it obtains focus.
source.Background = Brushes.LightBlue;
When the TextBox loses keyboard focus, the Background property of the TextBox is
changed back to white.
C#
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
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.
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
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.
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.
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.
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.
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.
application.
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>
</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" .
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#
C#
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;
}
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#
e.Handled = true;
}
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
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.
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);
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#
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#
if (source != null)
{
ComboBoxItem selectedCursor = source.SelectedItem as ComboBoxItem;
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#
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.
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#
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#
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#
In order to use the command in an application, event handlers which define what the
command does must be created
C#
C#
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#
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
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.
C#
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.
C#
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#
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#
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 (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
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
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);
C#
XAML
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Open"
Executed="OpenCmdExecuted"
CanExecute="OpenCmdCanExecute"/>
</Window.CommandBindings>
C#
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
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();
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:
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.
You've written the ink equivalent of a "hello world" application with only 12 keystrokes!
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>
XAML
C#
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.
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.
C#
using System;
using System.Windows;
using System.Windows.Controls;
class Program : Application
{
Window win;
InkCanvas ic;
[STAThread]
static void Main(string[] args)
{
new Program().Run();
}
}
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.
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
The following code sets the editing mode based on the value of a CheckBox:
C#
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#
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.
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>
Next, add the following button event handlers to the code behind file, inside the
MainWindow class:
C#
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
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 Window1()
{
InitializeComponent();
}
if (status == RecognitionStatus.NoError)
textBox1.Text = result.TopString;
else
MessageBox.Show("Recognition failed");
}
else
{
MessageBox.Show("No stroke detected");
}
}
}
}
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.
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#
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#
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.
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:
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.
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();
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());
}
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.
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
Architecture
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.
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.
C#
using System;
using System.Windows.Media;
using System.Windows;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Input;
using System.Windows.Ink;
C#
[ThreadStatic]
static private Pen pen = null;
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#
The following C# code demonstrates a custom InkCanvas class that uses a customized
DynamicRenderer and collects custom strokes.
C#
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
Architecture
Conclusion
Architecture
The StylusPlugIn is the evolution of the StylusInput APIs, described in Accessing and
Manipulating Pen Input.
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.
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#
The following example demonstrates a custom InkCanvas that filters the ink.
C#
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 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).
How to: Collect Stylus Point Data and Create Ink Strokes
How to: Enable Your Control to Accept Input from the Mouse
Putting it together
Conclusion
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#
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;
}
C#
public InkControl()
{
C#
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#
stylusPoints.Add(eventPoints);
}
5. Override the OnStylusMove method and add the StylusPoint data to the
StylusPointCollection object that you created earlier.
C#
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#
C#
base.OnMouseLeftButtonDown(e);
C#
base.OnMouseMove(e);
Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
}
C#
base.OnMouseLeftButtonUp(e);
if (stylusPoints == null)
{
return;
}
Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
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#
public InkControl()
{
// Add an InkPresenter for drawing.
ip = new InkPresenter();
this.Content = ip;
stylusPoints.Add(eventPoints);
}
base.OnMouseLeftButtonDown(e);
base.OnMouseMove(e);
Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
}
base.OnMouseLeftButtonUp(e);
if (stylusPoints == null)
{
return;
}
Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
stylusPoints = null;
}
}
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:
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.
The following diagram illustrates the hypothetical situation where the StylusPlugIns
collection of a UIElement contains stylusPlugin1 , a DynamicRenderer, and
stylusPlugin2 , in that order.
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.
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.
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
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.
C#
C#
DrawingAttributes inkDA;
DrawingAttributes selectDA;
C#
// In the constructor.
// Selection drawing attributes use dark gray ink.
selectDA = new DrawingAttributes();
selectDA.Color = Colors.DarkGray;
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#
set
{
mode = value;
C#
C#
C#
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#
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#
C#
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();
}
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;
// 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();
DynamicRenderer renderer;
public InkSelector()
{
mode = InkMode.Ink;
// In the constructor.
// Selection drawing attributes use dark gray ink.
selectDA = new DrawingAttributes();
selectDA.Color = Colors.DarkGray;
inkDA.AttributeChanged += new
PropertyDataChangedEventHandler(DrawingAttributesChanged);
selectDA.AttributeChanged += new
PropertyDataChangedEventHandler(DrawingAttributesChanged);
static InkSelector()
{
// Allow ink to be drawn only within the bounds of the control.
Type owner = typeof(InkSelector);
ClipToBoundsProperty.OverrideMetadata(owner,
new FrameworkPropertyMetadata(true));
}
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);
}
Mouse.Capture(this);
if (e.StylusDevice != null)
{
return;
}
Point pt = e.GetPosition(this);
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);
}
}
base.OnMouseMove(e);
if (e.StylusDevice != null)
{
return;
}
if (e.LeftButton == MouseButtonState.Released)
{
return;
}
Point pt = e.GetPosition(this);
stylusPoints.Add(collectedPoints);
AddPointsToHitTester(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);
}
base.OnMouseLeftButtonUp(e);
Point pt = e.GetPosition(this);
stylusPoints.Add(collectedPoints);
AddPointsToHitTester(collectedPoints);
AddStrokeToPresenter();
stylusPoints = null;
Mouse.Capture(null);
}
if (mode == InkMode.Ink)
{
// Add the stroke to the InkPresenter.
newStroke.DrawingAttributes = inkDA.Clone();
presenter.Strokes.Add(newStroke);
}
set
{
mode = value;
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.
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#
inkCanvas1.Strokes.AddPropertyData(timestamp, DateTime.Now);
}
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 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;
}
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
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;
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;
if (converter.CanConvertFrom(typeof(string)))
{
StrokeCollection newStrokes =
converter.ConvertFrom(strokesString) as StrokeCollection;
presenter.Strokes.Clear();
presenter.Strokes.Add(newStrokes);
}
}
InitializeEraserHitTester(points);
}
if (e.StylusDevice != null)
{
return;
}
Point pt = e.GetPosition(this);
InitializeEraserHitTester(collectedPoints);
}
AddPointsToEraserHitTester(points);
}
if (e.StylusDevice != null)
{
return;
}
if (e.LeftButton == MouseButtonState.Released)
{
return;
}
Point pt = e.GetPosition(this);
AddPointsToEraserHitTester(collectedPoints);
}
StopEraseHitTesting(points);
}
if (e.StylusDevice != null)
{
return;
}
Point pt = e.GetPosition(this);
StopEraseHitTesting(collectedPoints);
}
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;
if (inkCanvas1.IsGestureRecognizerAvailable)
{
inkCanvas1.EditingMode = InkCanvasEditingMode.InkAndGesture;
inkCanvas1.Gesture += new
InkCanvasGestureEventHandler(inkCanvas1_Gesture);
inkCanvas1.SetEnabledGestures(
new ApplicationGesture[] { ApplicationGesture.ScratchOut });
}
}
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>
<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 Window1()
{
InitializeComponent();
}
Point pt = e.GetPosition(ic);
DragDropEffects effects =
DragDrop.DoDragDrop(ic, dataObject,
DragDropEffects.Move);
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>
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>
XAML
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>
<InkCanvas.LayoutTransform>
<ScaleTransform ScaleX="-1" ScaleY="1" />
</InkCanvas.LayoutTransform>
</InkCanvas>
</Canvas>
How to: Analyze Ink with Analysis Hints
Article • 07/27/2022
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>
<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>
<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"/>
C#
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Threading;
public FormAnalyzer()
{
InitializeComponent();
}
/// <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)
{
/// <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
XAML
<Canvas>
<InkCanvas Name="inkCanvas1" Background="LightBlue"
Height="200" Width="200"
Canvas.Top="20" Canvas.Left="20" />
C#
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;
VisualCollection visualChildren;
RotateTransform rotation;
rotateHandle.DragDelta += new
DragDeltaEventHandler(rotateHandle_DragDelta);
rotateHandle.DragCompleted += new
DragCompletedEventHandler(rotateHandle_DragCompleted);
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;
}
if (rotation != null)
{
handleRect.Transform(rotation.Value);
}
/// <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.
if (deltaY.Equals(0))
{
return;
}
// Convert to degrees.
angle = angle * 180 / Math.PI;
if (Double.IsNaN(angle))
{
return;
}
/// <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);
// 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;
}
}
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#
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#
if (devices.Count > 0)
{
// Get the Type of InputManager.
Type inputManagerType = typeof(System.Windows.Input.InputManager);
if (stylusLogic != null)
{
// Get the type of the stylusLogic returned from the call to
StylusLogic.
Type stylusLogicType = stylusLogic.GetType();
}
}
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.
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 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.
) Important
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.
Event Summary
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.
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.
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.
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.
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.
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.
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
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#
Inside of the MouseMove event handler, call the DoDragDrop method to initiate the
drag-and-drop operation. The DoDragDrop method takes three parameters:
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.
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;
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;
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#
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#
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
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
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.
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
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#
For more examples of code that creates a data object, see Create a Data Object.
The following example shows how to use the SetData(String, Object) method to add
data to a data object in multiple formats.
C#
// 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);
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#
// 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.
C#
// 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.
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.
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.
Prerequisites
You need Visual Studio to complete this walkthrough.
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>
2. In the Add New Item dialog box, change the name to Circle.xaml , and click Add.
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" />
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;
}
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
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>
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.
2. Add the following OnMouseMove override to provide class handling for the
MouseMove event.
C#
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.
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#
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.
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.
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.
2. Add the following OnDrop override to provide class handling for the Drop event.
C#
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.
5. Drag the text to a Circle control and drop it. The Circle changes from blue to green.
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.
2. Add the following OnDragOver override to provide class handling for the
DragOver event.
C#
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.
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.
2. In the Circle class, declare a private Brush variable named _previousFill and
initialize it to null .
C#
3. Add the following OnDragEnter override to provide class handling for the
DragEnter event.
C#
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#
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.
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>
C#
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.
C#
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;
}
}
}
}
}
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.
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
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
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();
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#
Description
The following example code is a condensed version of the code shown above.
Code
C#
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#
Description
The following example code is a condensed version of the code shown above.
Code
C#
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#
Description
The following example code is a condensed version of the code shown above.
Code
C#
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#
Description
The following example code is a condensed version of the code shown above.
Code
C#
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#
// 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, 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#
// 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;
}
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#
// 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, 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.
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#
// 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;
}
}
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#
// 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.
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#
// 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[];
}
Code
C#
// 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#
// 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
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.
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>
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
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.
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 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 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 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.
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 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.
1. The lookup checks for the requested key within the resource dictionary defined by
the element that sets the property:
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.
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:
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>
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
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#
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.
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.
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
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.
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
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
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#
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 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
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
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
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
See also
Paint an Area with a System Brush
Use SystemFonts
Use SystemParameters
Documents
Article • 07/26/2022
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.
7 Note
For more detailed information on flow document features and how to create them,
see Flow Document Overview.
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.
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).
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
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:
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
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.
2. Defining information relationships that add notes or other data related to the part.
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
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:
Outputting documents in the native print spool output format of Windows Vista.
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.
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.
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.
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#
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#
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.
See also
System.Windows.Documents.Serialization
XpsDocumentWriter
XpsDocument
Documents in WPF
Printing Overview
XML Paper Specification
Annotations
Article • 02/06/2023
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
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#
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.
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 & 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.
The following example demonstrates how to implement the event handler of such a list
box that serves as the comments pane.
C#
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 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.
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">
<xsd:complexType name="AnnotationsType">
<xsd:sequence>
<xsd:element name="Annotation" minOccurs="0" maxOccurs="unbounded"
type="anc:AnnotationType" />
</xsd:sequence>
</xsd:complexType>
</xsd:sequence>
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" />
<!-- 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>
</xsd:schema>
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"/>
* <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>
<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>
<!-- 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:schema>
XML
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.
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
<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()
{
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.
7 Note
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.
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.
The following sections will go over each of these areas in more detail.
For the purposes of flow content, there are two important categories:
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()
{
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()
{
mySection.Blocks.Add(myParagraph1);
mySection.Blocks.Add(myParagraph2);
mySection.Blocks.Add(myParagraph3);
this.Content = myFlowDocument;
}
}
}
BlockUIContainer
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>
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 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);
myList.ListItems.Add(myListItem1);
myList.ListItems.Add(myListItem2);
myList.ListItems.Add(myListItem3);
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>
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...
</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... ");
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 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()
{
this.Content = myFlowDocument;
}
}
}
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>
C#
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>
C#
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.
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.
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.
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.
XAML
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<RichTextBox>
<FlowDocument>
</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 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>
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#
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
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.
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.
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.
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.
XAML
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<RichTextBox>
<FlowDocument>
</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:
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#
The following example creates a new Run element and inserts it at the beginning of the
Span.
C#
C#
spanx.Inlines.Remove(spanx.Inlines.LastInline);
The following example clears all of the contents (Inline elements) from the Span.
C#
spanx.Inlines.Clear();
Note that this list only includes nonabstract types distributed with the Windows SDK.
You may use other types that inherit from TextElement.
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.
Table Basics
Table Containment
Row Groupings
[Related Topics]
Table Basics
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.
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>
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>
<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.
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).
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.
First, a FlowDocument is created to host the Table, and a new Table is created and added
to the contents of the FlowDocument.
C#
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());
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#
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#
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#
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];
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#
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#
C#
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#
C#
table1.RowGroups[0].Rows.Add(new TableRow());
currentRow = table1.RowGroups[0].Rows[3];
See also
Table Overview
How to: Change the FlowDirection of
Content Programmatically
Article • 02/06/2023
XAML
<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#
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
C#
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>
<!-- 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>
</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.
<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>
C#
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>
C#
myTextBlock.TextTrimming = TextTrimming.CharacterEllipsis;
There are currently three options for trimming text: CharacterEllipsis, WordEllipsis, and
None.
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 two TextPointers that will specify the text range the
Span will cover
TextPointer myTextPointer1 =
myParagraph.ContentStart.GetPositionAtOffset(10);
TextPointer myTextPointer2 =
myParagraph.ContentEnd.GetPositionAtOffset(-5);
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.
C#
C#
C#
C#
secx.Blocks.Remove(secx.Blocks.LastBlock);
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.
C#
C#
Run runx = new Run("Text to insert...");
spanx.Inlines.InsertBefore(spanx.Inlines.FirstInline, runx);
C#
C#
spanx.Inlines.Remove(spanx.Inlines.LastInline);
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.
C#
C#
C#
C#
flowDoc.Blocks.Remove(flowDoc.Blocks.LastBlock);
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.
C#
7 Note
C#
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;
C#
C#
tbl.Columns.Remove(tbl.Columns[3]);
C#
tbl.Columns.RemoveAt(2);
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.
C#
7 Note
C#
C#
C#
C#
C#
C#
tbl.RowGroups.Remove(tbl.RowGroups[0]);
C#
tbl.RowGroups.RemoveAt(0);
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
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>
<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>
<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>
<Section BreakPageBefore="True"/>
<Section><Paragraph>... and another section, preceded by a
PageBreak</Paragraph></Section>
<Paragraph><LineBreak/></Paragraph>
</FlowDocument>
How to: Use FlowDocument Column-
Separating Attributes
Article • 02/06/2023
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).
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.
Broad support for international text. For more information, see Globalization for
WPF.
Unicode for all text. Font behavior and selection no longer require charset or
codepage.
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.
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.
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.
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.
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.
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
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.
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
The following example shows the effect of y-direction antialiasing. In this case, the top
and bottom of the letter show a smooth curve.
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.
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
Gamma level Describes the level of the pixel color component 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
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:
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
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.
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).
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.
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#
// Use a Bold font weight beginning at the 6th character and continuing
for 11 characters.
formattedText.SetFontWeight(FontWeights.Bold, 6, 11);
C#
The following examples illustrate several ways of creating interesting visual effects by
modifying the stroke, fill, and highlight of converted 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.
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).
DT_HIDEPREFIX None Not supported. Remove the '&' from the string
before constructing the FormattedText object.
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.
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.
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.
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#
// 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);
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.
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);
}
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.
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).
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.
Rich mapping between characters and glyphs that support ligatures, positional
forms, alternates, and other font substitutions.
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.
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
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
The following markup example shows how to define superscripts and subscripts for a
font, using properties of the Typography object.
XAML
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
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:
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
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
The following markup example shows how to disable standard ligature glyphs for the
Palatino Linotype font, using properties of the Typography object.
XAML
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
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
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>
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
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
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
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
The following code example accomplishes the same task as the previous markup
example.
C#
MyParagraph.Inlines.Add(new LineBreak());
Typography Class Properties
The following table lists the properties, values, and default settings of the Typography
object.
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.
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.
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
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
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#
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
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");
C#
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#
XML
<PropertyGroup>
<AssemblyName>FontLibrary</AssemblyName>
<OutputType>library</OutputType>
...
</PropertyGroup>
...
<ItemGroup>
<Resource Include="Kooten.ttf" />
<Resource Include="Pesca.ttf" />
</ItemGroup
XAML
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.
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.
Name File
Kootenay Kooten.ttf
Lindsey Linds.ttf
Miramonte Miramo.ttf
Pericles Peric.ttf
Pescadero Pesca.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.
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#
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.
C#
See also
FontSizeConverter
Glyphs
Article • 02/06/2023
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.
2. Print scenarios.
Previous printer drivers, output from Win32 applications to the fixed format.
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.
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).
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 flags
[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 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"
/>
</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
<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 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"
/>
</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#
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#
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
C#
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
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
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
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
7 Note
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
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
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>
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>
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
7 Note
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.
XAML
XAML
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
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.
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;
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
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#
drawingContext.DrawRoundedRectangle(System.Windows.Media.Brushes.PapayaWhip,
null, new Rect(new System.Windows.Size(formattedText.Width + 50,
formattedText.Height + 5)), 5.0, 5.0);
See also
FormattedText
Drawing Formatted Text
How to: Draw Text to a Visual
Article • 02/06/2023
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#
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:
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>
< <!-- Less than symbol -->
> <!-- Greater than symbol -->
& <!-- Ampersand symbol -->
" <!-- 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
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.)
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:
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.
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.
The following illustration depicts the print subsystem and defines the portions provided
by Microsoft, and the portions defined by software and hardware vendors:
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.
The following example demonstrates how to query the PrintCapabilities of a printer and
create a PrintTicket using code.
C#
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;
// 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()
The following example demonstrates how to create a LocalPrintServer and access its
default PrintQueue by using code.
C#
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.
C#
The AddJob methods also provide ways to print. See Programmatically Print XPS Files.
for details.
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.
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:
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.
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.
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.
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#
// 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.
Use the dictionary's Remove and Add methods to remove the entry and then
re-add it with the desired value.
3. Create a PrintBooleanProperty object and set its Name to "IsShared" and its Value
to true .
5. Create a PrintStringProperty object and set its Name to "ShareName" and its Value
to an appropriate String.
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#
// 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);
// 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.
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#
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());
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.");
}
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
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#
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.
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).
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#
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.
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#
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);
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
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.
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};
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.
3. Enumerate the members of the dictionary. For each of them, do the following.
C#
PrintPropertyDictionary printQueueProperties =
defaultPrintQueue.PropertiesCollection;
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.
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.
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.
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);
// 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.");
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
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.
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.
C#
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. ";
}
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#
C#
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.
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.
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
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.
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
{
//
// 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
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
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.
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.
Provide extra space in margins because localized text often requires more space. Extra space
allows for possible overhanging characters.
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 .
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 use duplicate Uid properties (remember this tip when you use the copy-and-paste
command).
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
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.
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.
English:
German:
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.
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
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".
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 .
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:
Button_1:System.Windows.Controls.Button.$Content Button OK
ComboBox_1:System.Windows.Controls.ComboBox.$Content ComboBox
Button_1:System.Windows.Controls.Button.$Content Button OK
ComboBox_1:System.Windows.Controls.ComboBox.$Content ComboBox
Generate
The last step of localization involves creating the newly localized satellite assembly. This can be
accomplished with the following LocBaml command:
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.
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:
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.
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
Observe that even the background gradient brushes are flipped correctly when the root
FlowDirection is changed:
FlowDirection="LeftToRight"
FlowDirection="RightToLeft"
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:
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>
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.
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.
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
Ϩ
The following example shows a hexadecimal character reference. Notice that it has an x
in front of the hexadecimal number.
XAML
Ϩ
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
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.
International Text
WPF includes built-in processing for all Microsoft .NET Framework supported writing
systems.
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
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.
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:
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.
XML
<Resource Include="data\picture1.jpg"/>
<EmbeddedResource Include="data\stringtable.en-US.restext"/>
C#
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.
Reduces the need to readjust position and size of controls after text is translated.
Localization can be reduced to the point that it is little more than string translation.
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>
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
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
The following graphic shows the grid produced by the previous code.
Grid
XAML
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="FirstColumn"/>
<ColumnDefinition SharedSizeGroup="SecondColumn"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" SharedSizeGroup="FirstRow"/>
</Grid.RowDefinitions>
</StackPanel>
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
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:
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.
The following example shows how to add localization comments to a XAML file.
FontSize = "12"
Microsoft
</TextBlock>
Localization Meaning
attributes
FontFamily The font family property of the TextBlock element cannot be changed but it is
(Unmodifiable visible to the localizer.
Readable)
$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.
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.
Category Meaning
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.
XAML
XAML
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>
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.
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 >
<Separator/>
</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.
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.
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 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">
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.
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">
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.
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
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:
Substitution:
This property specifies the type of number substitution to perform. It takes one of the
following NumberSubstitutionMethod enumeration values:
Context: If the number culture is an Arabic or Persian culture, it specifies that the
digits depend on the context.
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.
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).
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);
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>
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:
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.
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:
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>
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.
asmpath or -asmpath {filedirectory] If your XAML code contains custom controls, you must supply the asmpath to the custom control assembly.
7 Note
If you need a list of the options when you are running the tool, enter LocBaml.exe and then press Enter.
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:
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:
HelloApp.g.en-US.resources:window1.baml,Stack1:System.Windows.Controls.StackPanel.$Content,Ignore,FALSE, FALSE,,#Text1;#Text2;
BAML Name. The name of the BAML resource with respect to the source language satellite assembly.
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.
The following table shows how these fields map to the delimited values of the .csv file:
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.
1. Use the following syntax to generate a new HelloApp.resources.dll file. Mark the culture as en-US (/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:
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.
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:
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;
}
}
}
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 .
Example
The following example shows how to use a grid.
XAML
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
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">
</ResourceDictionary>
This code defines a string resource, localizedMessage , of type String, from the
System namespace in mscorlib.dll.
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
4. Use the string resource from code-behind, using code like the following.
C#
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"/>
C#
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.
What's Next
XAML
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#
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.
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.
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.
7 Note
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.
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.
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.
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.
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.
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.
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.
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.
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] .
The following table contains a list of the XAML feature-support classes that are defined
in System.Xaml.
NullExtension {x:Null}
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.
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.
XamlReader
XamlWriter
XamlParseException
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.
The WPF control may host one or more Windows Forms controls using XAML.
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 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 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.
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.
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.
For more information, see Windows Forms and WPF Property Mapping.
Behavior
The following table describes interoperation behavior.
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.
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.
The WindowsFormsHost class acquires messages from the WPF message loop,
which is implemented by the ComponentDispatcher class.
The following sections describe these parts of the process in more detail.
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.
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.
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.
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.
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.
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.
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 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 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.
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.
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.
Sizing Algorithm
The WindowsFormsHost element uses the following procedure to size the hosted
control:
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.
BindingSource CollectionViewSource
Button Button
CheckBox CheckBox
ContextMenuStrip ContextMenu
DataGridView DataGrid
DateTimePicker DatePicker
GroupBox GroupBox
Label Label
LinkLabel No equivalent control. You can use the Hyperlink class to host hyperlinks
within flow content.
ListBox ListBox
MonthCalendar Calendar
Panel Canvas
PictureBox Image
PrintDialog PrintDialog
PrintPreviewControl DocumentViewer
ProgressBar ProgressBar
RadioButton RadioButton
RichTextBox RichTextBox
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
ToolTip ToolTip
TrackBar Slider
TreeView TreeView
UserControl UserControl
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.
Ensures that property value changes on the host are automatically detected and
translated to the hosted control or element.
7 Note
- 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
FlowDirection.RightToLeft
maps to RightToLeft.Yes.
- 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.
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.
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.
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
FontStyle
FontWeight
If Bold is false ,
FontWeight is set to
Normal.
Windows Forms hosting Windows Presentation Interoperation
Foundation behavior
If Italic is false ,
FontStyle is set to
Normal.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
WindowsFormsIntegration
System.Windows.Forms
XAML
<Grid Name="grid1">
</Grid>
5. In Design view or XAML view, select the Window element.
C#
9. At the top of the file, add the following Imports or using statement.
C#
using System.Windows.Forms;
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.
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.
WindowsFormsIntegration
System.Windows.Forms
XAML
xmlns:wf="clr-
namespace:System.Windows.Forms;assembly=System.Windows.Forms"
5. In the Grid element add the following XAML.
XAML
<Grid>
<WindowsFormsHost>
<wf:MaskedTextBox x:Name="mtbDate" Mask="00/00/0000"/>
</WindowsFormsHost>
</Grid>
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.
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.
1. Launch Visual Studio, and open the New Project dialog box.
2. In the Window category, select the Windows Forms Control Library template.
5. Click OK to create the project. The default project contains a single control named
UserControl1 .
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
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.
C#
C#
public class MyControlEventArgs : EventArgs
{
private string _Name;
private string _StreetAddress;
private string _City;
private string _State;
private string _Zip;
private bool _IsOK;
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.
C#
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.
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.
The following image shows the complete application, including the control embedded
in the WPF application:
Creating the Project
To start the project:
4. For the location, specify the same top-level folder that contains the MyControls
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.
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 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>
<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.
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 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.
C#
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;
buttons.
C#
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 .
C#
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.
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.
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.
6. Click the COM Components tab, select the Windows Media Player control, and
then click OK.
7. In Solution Explorer, right-click the UserControl1 file, and then click Rename.
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.
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.
XAML
<Grid Name="grid1">
</Grid>
C#
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 .
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.
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();
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.
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.
WindowsFormsIntegration
System.Windows.Forms
System.Drawing
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>
XAML
<!-- Default layout. -->
<Canvas Grid.Row="0" Grid.Column="0">
<WindowsFormsHost Background="Yellow">
<wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
</WindowsFormsHost>
</Canvas>
Sizing to Content
The WindowsFormsHost element ensures that the hosted control is sized to display its
content properly.
XAML
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.
XAML
XAML
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.
To see the effects of setting properties on the hosted control, follow these steps:
XAML
C#
b.Top = 20;
b.Left = 20;
}
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.
XAML
Docking
WindowsFormsHost element supports WPF docking. Set the Dock attached property to
dock the hosted control in a DockPanel element.
XAML
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:
XAML
C#
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.
XAML
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:
XAML
<StackPanel.RenderTransform>
<ScaleTransform CenterX="0" CenterY="0" ScaleX="0.5" ScaleY="0.5"
/>
</StackPanel.RenderTransform>
<WindowsFormsHost Background="Yellow">
<wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
</WindowsFormsHost>
</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.
XAML
<StackPanel.RenderTransform>
<RotateTransform CenterX="200" CenterY="50" Angle="180" />
</StackPanel.RenderTransform>
<WindowsFormsHost Background="Yellow">
<wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
</WindowsFormsHost>
</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.
To set padding and margins for a hosted control, follow these steps:
1. Copy the following XAML into the Grid element:
XAML
XAML
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.
XAML
flp.WrapContents = true;
flp.Controls.Add(b);
}
}
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.
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.
WindowsFormsIntegration
System.Windows.Forms
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">
XAML
<Grid.Resources>
<DataTemplate x:Key="ListItemsTemplate">
<TextBlock Text="{Binding Path=ContactName}"/>
</DataTemplate>
</Grid.Resources>
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>
XAML
The details of each customer record are displayed in several TextBox controls.
The Binding class binds the TextBox controls to the appropriate fields in the
database.
XAML
XAML
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 .
This code declares the BindingSource component and associated helper classes
that connect to the database.
C#
C#
public MainWindow()
{
InitializeComponent();
4. Open MainWindow.xaml.
This code assigns the BindingSource component as the data context and populates
the Customers and Orders adapter objects.
C#
BindingListCollectionView cv = CollectionViewSource.GetDefaultView(
this.nwBindingSource) as BindingListCollectionView;
This method handles the CurrentChanged event and updates the current item of
the data binding.
C#
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.
Prerequisites
You need the following components to complete this walkthrough:
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>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup >
<Model3DGroup.Children>
<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>
PresentationCore
PresentationFramework
WindowsBase
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.
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();
}
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.
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.
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.
5. Click OK to create the project. The default project contains a single control named
UserControl1 .
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
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.
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.
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"/>
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>
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>
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.
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#
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#
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#
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.
C#
C#
Build the solution. The build will produce a DLL named MyControls.dll.
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.
4. For the location, specify the same top-level folder that contains the MyControls
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.
PresentationFramework
System.Xaml
WindowsBase
WindowsFormsIntegration
Name Text
groupBox3 radioSizeTen 10
groupBox3 radioSizeTwelve 12
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#
public Form1()
{
InitializeComponent();
}
wpfAddressCtrl.OnButtonClick +=
new MyControls.MyControl1.MyControlEventHandler(
avAddressCtrl_OnButtonClick);
wpfAddressCtrl.Loaded += new RoutedEventHandler(
avAddressCtrl_Loaded);
}
The Form1_Load method in the preceding code shows the general procedure for hosting
a 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.
C#
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.
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:
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.
C#
C#
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 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.
C#
The RemoveCursorMapping method deletes the default mapping for the Cursor
property.
C#
C#
The Form1_Load method handles the Load event and performs the following
initialization.
Calls the methods you defined earlier in the walkthrough to set up the
property mappings.
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.
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:
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>
C#
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
C#
// The AddClipMapping method adds a custom
// mapping for the Clip property.
private void AddClipMapping()
{
wfHost.PropertyMap.Add(
"Clip",
new PropertyTranslator(OnClipChange));
}
if (cb != null)
{
cb.Region = this.CreateClipRegion();
}
}
path.StartFigure();
path.AddEllipse(new System.Drawing.Rectangle(
0,
0,
(int)wfHost.ActualWidth,
(int)wfHost.ActualHeight ) );
path.CloseFigure();
The AddClipMapping method adds a new mapping for the Clip property.
The OnClipChange method translates the Clip property to the Windows
FormsRegion property.
C#
The RemoveCursorMapping method deletes the default mapping for the Cursor
property.
C#
C#
if (b != null)
{
cb.BackgroundImage = new
System.Drawing.Bitmap(@"C:\WINDOWS\Santa Fe Stucco.bmp");
}
}
C#
The WindowLoaded method handles the Loaded event and performs the following
initialization.
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.
Enabling localization.
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:
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>
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" .
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).
5. In the Properties window, set the value of the Text property to "Hola" .
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();
}
10. Copy the following line into the first PropertyGroup in the project file.
XML
<UICulture>en-US</UICulture>
Console
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>
2. In the Command Prompt window, use the following command to extract resource
strings into a temporary file.
Console
3. Open the temp.csv file with Visual Studio or another text editor. Replace the string
"Hello" with its Spanish translation, "Hola" .
Console
Console
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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:
Mnemonics and accelerators that work both when focus is within a Win32
component and when it is within a WPF component.
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
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.
Constant alpha and color keys are not supported. Win32 layered window capabilities
vary by platform.
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 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 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).
Calling ComponentDispatcher methods on a thread will only invoke event handlers that
were registered on that thread.
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.
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 .
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: raised for all messages that the message pump processes.
ThreadPreprocessMessage: raised for all messages that were not handled during
ThreadFilterMessage.
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.
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.
C++
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.
Instantiate the HwndHost subclass and put it under the right WPF element
text
text
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
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++
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));
}
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++
C++
#undef TranslateAccelerator
virtual bool TranslateAccelerator(System::Windows::Interop::MSG%
msg,
ModifierKeys modifiers) override
{
::MSG m = ConvertMessage(msg);
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++
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++
m.time = msg.time;
POINT pt;
pt.x = msg.pt_x;
pt.y = msg.pt_y;
m.pt = pt;
return m;
}
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++
if (request != nullptr)
return ((IKeyboardInputSink^) this)->KeyboardInputSite-
>OnNoMoreTabStops(request);
}
C++
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.
C++
refuses to process the mnemonic if the focused HWND is not inside the dialog box.
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#
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 .
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.
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.
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>
<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>
<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>
C#
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#
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#
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#
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,
C#
C#
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#
C#
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;
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 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.
a. Create a new HwndSource object with the parent window as its parent
parameter.
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.
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.
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.
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++
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
C++
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.
C++
The latter part of the GetHwnd function assigns values to those fields for later use while
myPage is still in scope.
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++
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,
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.
Layout
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++
this->Height = allotedHeight;
this->Width = allottedWidth;
this->Background = gcnew SolidColorBrush(Colors::LightGray);
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++
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++
C++
C++
C++
public:
delegate void ButtonClickHandler(Object ^, MyPageEventArgs ^);
WPFPage();
WPFPage(int height, int width);
event ButtonClickHandler ^OnButtonClicked;
C++
From WPFPage.h:
C++
From WPFPage.cpp:
C++
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.
(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.
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 .
1. Right-click win32clock project and select References..., and inside that dialog:
3. Click Add New Reference, click Browse tab, enter C:\Program Files\Reference
Assemblies\Microsoft\Framework\v3.0\PresentationCore.dll, and click OK.
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).
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:
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;
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++
Then you create the WPF content class by calling its constructor:
C++
C++
source->RootVisual = page;
And in the final line, return the HWND for the HwndSource:
C++
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);
C++
ShowWindow(placeholder, SW_HIDE);
C++
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.
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>
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);
}
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
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.
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.
C++
HRESULT
CRendererManager::EnsureD3DObjects()
{
HRESULT hr = S_OK;
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;
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.
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;
}
C++
HRESULT
CRendererManager::TestSurfaceSettings()
{
HRESULT hr = S_OK;
//
// 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!
//
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;
}
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.
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.
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
To avoid the performance penalty, write code specifically for the multi-monitor case. The
following list shows one way to write multi-monitor code.
2. Use the MonitorFromPoint GDI method to find the monitor that is displaying the
point.
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.
//
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.
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
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.
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.
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
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.
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.
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.
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:
The Win32 Application Wizard opens and displays the Welcome screen.
2. Click Next.
4. Click Finish.
The D3DContent project is generated.
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.
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.
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.
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);
protected:
CRenderer();
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;
}
C++
#pragma once
class CRenderer;
class CRendererManager
{
public:
static HRESULT Create(CRendererManager **ppManager);
~CRendererManager();
HRESULT EnsureDevices();
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;
};
C++
//+--------------------------------------------------------------------
---------
//
// CRendererManager
//
// Manages the list of CRenderers. Managed code pinvokes into this
class
// and this class forwards to the appropriate CRenderer.
//
//---------------------------------------------------------------------
---------
#include "StdAfx.h"
//+--------------------------------------------------------------------
---------
//
// 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;
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]));
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;
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;
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;
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);
}
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;
//
// 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!
//
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);
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);
//+--------------------------------------------------------------------
---------
//
// Member:
// CRendererManager::Render
//
// Synopsis:
// Forward to the current renderer
//
//---------------------------------------------------------------------
---------
HRESULT
CRendererManager::Render()
{
return m_pCurrentRenderer ? m_pCurrentRenderer->Render() : S_OK;
}
C++
#pragma once
HRESULT Render();
protected:
HRESULT Init(IDirect3D9 *pD3D, IDirect3D9Ex *pD3DEx, HWND hwnd,
UINT uAdapter);
private:
CTriangleRenderer();
IDirect3DVertexBuffer9 *m_pd3dVB;
};
C++
//+--------------------------------------------------------------------
---------
//
// CTriangleRenderer
//
// Subclass of CRenderer that renders a single, spinning triangle
//
//---------------------------------------------------------------------
---------
#include "StdAfx.h"
struct CUSTOMVERTEX
{
FLOAT x, y, z;
DWORD color;
};
//+--------------------------------------------------------------------
---------
//
// 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;
*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);
// 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();
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
));
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++
#pragma once
#include <d3d9.h>
#include <d3dx9.h>
#include <assert.h>
#include "RendererManager.h"
#include "Renderer.h"
#include "TriangleRenderer.h"
9. Open dllmain.cpp in the Code Editor and replace the automatically generated code
with the following code.
C++
IFC(EnsureRendererManager());
pManager->SetSize(uWidth, uHeight);
Cleanup:
return hr;
}
IFC(EnsureRendererManager());
pManager->SetAlpha(!!fUseAlpha);
Cleanup:
return hr;
}
IFC(EnsureRendererManager());
pManager->SetNumDesiredSamples(uNumSamples);
Cleanup:
return hr;
}
IFC(EnsureRendererManager());
pManager->SetAdapter(screenSpacePoint);
Cleanup:
return hr;
}
IFC(EnsureRendererManager());
IFC(pManager->GetBackBufferNoRef(ppSurface));
Cleanup:
return hr;
}
return pManager->Render();
}
11. Replace the automatically generated code with the following code.
C++
LIBRARY "D3DContent"
EXPORTS
SetSize
SetAlpha
SetNumDesiredSamples
SetAdapter
GetBackBufferNoRef
Render
Destroy
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
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.
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();
//
// 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.
//
// 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();
}
HRESULT.Check(SetAdapter(p));
}
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;
[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();
}
<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>
3. Copy the DLL that contains the Direct3D9 content to the bin/Debug folder.
See also
D3DImage
Performance Considerations for Direct3D9 and WPF Interoperability
Performance
Article • 08/10/2023
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.
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.
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.
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:
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.
The following features and capabilities are hardware accelerated for rendering tier 1 and
rendering tier 2:
Feature Notes
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.
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.
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.
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.
Tool Description
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.
~\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
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
Object Behavior
Application Resources
Text
Data Binding
Controls
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.
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.
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.
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.
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.
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 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.
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.
When a change occurs to the value of a dependency property that is marked with
metadata affecting the measure or arrange passes.
Action Tree building (in ms) Render—includes tree building (in ms)
Top-down 11 96
The following code example demonstrates how to create a tree top down.
C#
myCanvas.Children.Add(parentPanel);
myCanvas.Children.Add(textBlock);
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.
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.
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.
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.
XAML
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
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:
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.
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.
C#
// 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.
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.
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.
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
C#
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#
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;
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.
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.
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.
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>
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>
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:
Print scenarios.
Previous printer drivers, output from Win32 applications to the fixed format.
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
<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.
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#
// Set a maximum width and height. If the text overflows these values,
an ellipsis "..." appears.
formattedText.MaxTextWidth = 300;
formattedText.MaxTextHeight = 240;
// Use a Bold font weight beginning at the 6th character and continuing
for 11 characters.
formattedText.SetFontWeight(FontWeights.Bold, 6, 11);
The following markup sample illustrates two ways of setting text content within a
FlowDocument:
XAML
<FlowDocument>
The following markup sample illustrates these two ways of setting a text property, in this
case, the FontWeight property:
XAML
<!-- 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.
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.
The following markup example shows multiple TextBlock elements used to display the
hyperlinks:
XAML
<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
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
The following table shows the performance cost of displaying 1000 Hyperlink elements
with and without an underline.
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.
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.
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.
Data binding 1000 TextBlock objects Binding time Render time -- includes binding
(ms) (ms)
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.
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.
To an ObservableCollection<T> 20
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
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 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.
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.
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.
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.
7 Note
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
Navigation to Object
CompositionTarget.Rendering Event
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#
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.
CompositionTarget.Rendering Event
The CompositionTarget.Rendering event causes WPF to continuously animate. If you use
this event, detach it at every opportunity.
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.
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.
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.
You can also implement your own splash screen by using native Win32 graphics. Display
your implementation before the Run method is called.
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.
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.
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.
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.
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.
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>
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.
If you must use the XmlSerializer class, you can achieve better performance if you pre-
generate the serialization assembly.
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.
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
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.
Initializing a cache.
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.
2. In the File menu, click New, and then click New Project.
3. Under Installed Templates, select the programming language you want to use
(Visual Basic or Visual C#).
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.
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.
1. In Solutions Explorer, right-click the project name, and then click Properties.
4. In the Target framework (all configurations) list, select .NET Framework 4. (Do not
select .NET Framework 4 Client Profile.)
5. Click OK.
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.
3. In the Target framework list, select .NET Framework 4. (Do not select .NET
Framework 4 Client Profile.)
b. Select the .NET tab, select System.Runtime.Caching , and then click OK.
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.
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.
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#
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#
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#
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#
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#
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#
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.
3. Close the message box 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.
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();
}
if (fileContents == null)
{
CacheItemPolicy policy = new CacheItemPolicy();
policy.AbsoluteExpiration =
DateTimeOffset.Now.AddSeconds(10.0);
policy.ChangeMonitors.Add(new
HostFileChangeMonitor(filePaths));
See also
MemoryCache
ObjectCache
System.Runtime.Caching
Caching in .NET Framework Applications
Threading model
Article • 10/27/2023
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.
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.
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 .
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.
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" />
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;
if (_runCalculation)
{
StartStopButton.Content = "Stop";
StartStopButton.Dispatcher.InvokeAsync(CheckNextNumber,
DispatcherPriority.SystemIdle);
}
else
StartStopButton.Content = "Resume";
}
_num += 2;
C#
_num += 2;
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.
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.
When the Pause button is pressed, all windows under the same thread become
nonresponsive. Any window under a different thread continues to work normally.
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>
</Grid>
</Window>
C#
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace SDKSamples
{
public partial class MultiWindow : Window
{
public MultiWindow() =>
InitializeComponent();
System.Windows.Threading.Dispatcher.Run();
}
}
}
The Task.Delay(TimeSpan) task is used to cause the current thread to pause for five
seconds when the Pause button is pressed.
C#
C#
private void SameThreadWindow_Click(object sender, RoutedEventArgs e)
=>
new MultiWindow().Show();
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#
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 .
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.
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();
((Storyboard)Resources["HideWeatherImageStoryboard"]).Begin(this);
((Storyboard)Resources["ShowClockFaceStoryboard"]).Stop(ClockImage);
((Storyboard)Resources["HideClockFaceStoryboard"]).Begin(ClockImage);
//Update UI text
fetchButton.IsEnabled = true;
fetchButton.Content = "Fetch Forecast";
weatherText.Text = weather;
}
if (rand.Next(2) == 0)
return "rainy";
else
return "sunny";
}
((Storyboard)Resources["ShowWeatherImageStoryboard"]).Begin(ClockImage);
((Storyboard)Resources["ShowClockFaceStoryboard"]).Begin(ClockImage, true);
}
}
C#
((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
C#
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#
((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 .
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.
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
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
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.
Syntax
C++
void Activate(
const ActivateParameters* pParameters,
__deref_out_ecount(1) LPUNKNOWN* ppInner,
);
Parameters
pParameters
ppInner
Requirements
Platforms: See .NET Framework System Requirements.
DLL:
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
ppForwarder
A pointer to the address of an IDispatch interface.
Requirements
Platforms: See .NET Framework System Requirements.
DLL:
This API supports the Windows Presentation Foundation (WPF) infrastructure and is not
intended to be used directly from your code.
Syntax
C++
void Deactivate()
Requirements
Platforms: See .NET Framework System Requirements.
DLL:
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.
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:
This API supports the Windows Presentation Foundation (WPF) infrastructure and is not
intended to be used directly from your code.
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:
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.
Syntax
C++
Parameters
errorMsg
The error message.
Requirements
Platforms: See .NET Framework System Requirements.
DLL:
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.
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:
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.
Syntax
C++
Parameters
hwnd
A window handle.
Requirements
Platforms: See .NET Framework System Requirements.
DLL: PresentationHost_v0400.dll
See also
WPF Unmanaged API Reference