Introduction
There is a popular misconception that XAML does not allow good separation of concerns and code reuse. In fact the opposite is true. WPF enables unique programming techniques which (once you understand it) brings the code reuse and customization to a new level.
WPF and XAML introduced a number of revolutionary programming concepts which can be applied outside of WPF to purely non-visual programming and can be used in other (non .NET) platforms.
From my point of view, the WPF-esq concepts comprise a step above the usual Object Oriented Programming similar in magnitude to what OOP was in comparison to the procedural programming.
Unfortunately Microsoft leadership itself did not quite understand what their engineers came up with and switched their priorities.
As was stated above, the WPF concepts can be generalized and applied outside of WPF domain e.g. to build non-visual software. In fact I published a series of blog posts on applying WPF paradigms outside of WPF domain. This article, however, does not deal with that. It simply presents and classifies the patterns by using WPF examples.
Using the XAML/WPF paradigms described below I managed to program with great speed at the same time producing high quality and high density code (code with large reuse and large amount of functionality per unit of code).
This is not a beginner's WPF tutorial - I assume that the readers are familiar with basic WPF concepts - dependency and attached properties, bindings, styles, templates, data templates, triggers, routed events.
I plan this article as the first installment in a series of 2 or 3 articles. This part is dedicated to patterns of reuse based on Control
s and ControlTemplate
s. The subsequent articles will deal more with MVVM pattern and mapping non-visual objects into visual ones.
Controls and Control Templates
Controls
WPF Control is one of the basic visual units of reuse in WPF. Controls can be placed in XAML code including other controls and made work together using various means. Here we shall go over dos and don'ts of programming with WPF controls based on very simple examples.
Let us first consider a very simple control - it will allow the user to enter some text into an editable field (using e.g. a TextBox
), it will provide a label for that editable field. (The label will give the name of the field explaining what the user is entering). Also the control is going to have a Button
"Save" as an example of doing some action on the entered text. We shall call this control EditableTextAndLabelControl
.
Anti-Pattern - User Control with Code Behind
The simplest and the worst way of creating such control is by using WPF's UserControl
functionality. The code for this anti-pattern is located under UserControlWithCodeBehind
project. Unfortunately the Visual Studio provides an off-the-shelf way to create user controls - all you need to do is to right click on the project within the solution explorer, choose "New Item" under menu "Add" and choose "User Control (WPF)" (do not choose simply "User Control" - this will create a Win Forms User Control). Name the control "EditableTextAndLabelControl".
After clicking OK button you'll see that two files are created: XAML file "EditableTextAndLabelControl.xaml" and code behind file "EditableTextAndLabelControl.xaml.cs". XAML file will serve to specify the layout of the control while the code behind can be used to define the control's properties and behaviors. It is very convenient that the code behind can access the controls defined in XAML by name (but this is a deceptive advantage of programming with the code behind).
In the MainWindow
we display two such controls with labels "MyText" and "MyOtherText". When "Save" button of the corresponding control is pressed, the SaveEvent
of the control is fired. It is handled at the MainWindow
level and we print the following lines underneath the controls e.g.: "Saved string 'Hello' for label 'MyText'":

Here is the significant part of the XAML code of MainWindow
class:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<this:EditableTextAndLabelControl x:Name="MyUserControl1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TheLabel="MyText"
Margin="0,10"/>
<this:EditableTextAndLabelControl x:Name="MyUserControl2"
Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TheLabel="MyOtherText"
Margin="0,10"/>
<TextBlock x:Name="TheSaveEventLog"
Grid.Row="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</Grid>
We simply define the two controls and under them we define a TextBlock
to display the results of firing the SaveEvent
.
The MainWindow.xaml.cs
code is also very simple:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MyUserControl1.SaveEvent += MyUserControl_SaveEvent;
MyUserControl2.SaveEvent += MyUserControl_SaveEvent;
}
void MyUserControl_SaveEvent(string arg1, string arg2)
{
TheSaveEventLog.Text += "\nSaved string \"" + arg2 + "\" for label \"" + arg1 + "\"";
}
}
We access the two user controls by their names and assign MyUserControl_SaveEvent
as a handler for their SaveEvent
. MyUserControl_SaveEvent
function adds a new line to the Text
property of TheSaveEventLog
control.
Now let us take a look to the code of the EditableTextAndLabelControl
itself
. The control's code behind defines two dependency properties TheLabel
and TheEditableText
on the control. It also defines SaveEvent
that fired when the the button is clicked:
public partial class EditableTextAndLabelControl : UserControl
{
public event Action<string, string> SaveEvent = null;
public EditableTextAndLabelControl()
{
InitializeComponent();
SaveButton.Click += SaveButton_Click;
}
void SaveButton_Click(object sender, RoutedEventArgs e)
{
if (SaveEvent != null)
{
SaveEvent(TheLabel, TheEditableText);
}
}
#region TheLabel Dependency Property
public string TheLabel
{
get { return (string)GetValue(TheLabelProperty); }
set { SetValue(TheLabelProperty, value); }
}
public static readonly DependencyProperty TheLabelProperty =
DependencyProperty.Register
(
"TheLabel",
typeof(string),
typeof(EditableTextAndLabelControl),
new PropertyMetadata(null)
);
#endregion TheLabel Dependency Property
#region TheEditableText Dependency Property
public string TheEditableText
{
get { return (string)GetValue(TheEditableTextProperty); }
set { SetValue(TheEditableTextProperty, value); }
}
public static readonly DependencyProperty TheEditableTextProperty =
DependencyProperty.Register
(
"TheEditableText",
typeof(string),
typeof(EditableTextAndLabelControl),
new PropertyMetadata(null)
);
#endregion TheEditableText Dependency Property
}
Note that the mechanism for making the SaveEvent
fire when the "Save" button is clicked is contained within the code behind SaveButton.Click += SaveButton_Click;
, while the binding between the controls and the dependency properties is defined in XAML:
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="TheLabelTextBlock"
Text="{Binding Path=TheLabel, RelativeSource={RelativeSource AncestorType=this:EditableTextAndLabelControl}}"
VerticalAlignment="Bottom"/>
<TextBox x:Name="TheEditableTextTextBox"
Grid.Column="1"
Width="100"
Text="{Binding Path=TheEditableText, RelativeSource={RelativeSource AncestorType=this:EditableTextAndLabelControl}}"
VerticalAlignment="Bottom"
Margin="10,0,10,0"/>
<Button x:Name="SaveButton"
Content="Save"
Width="70"
Grid.Column="2"
VerticalAlignment="Bottom"/>
</StackPanel>
Pattern - Lookless Control
The problem with the (anti-)pattern presented above is that the control is very tightly coupled with the visual representation. Suppose that we want to have different visual representations of the controls e.g. we want to display one of the controls horizontally (as above) and one of them vertically i.e. label being on top of the TextBox
with the "Save" Button
at the bottom. We would have to create two completely different controls with identical code behind functionality and even very similar but not identical XAML code.
In this section, we create a very similar lookless control and show how it can have different visual representations. The code for this section is contained under LooklessControlSample
project.
When you build a lookless control, do not try to nail down its visual representation first. Instead think about what properties and events it has in order to interact with other controls or with the View Model.
Just like in previous section, create a new item, but instead of choosing "User Control (WPF)" as the item type, create simply a C# class EditableTextAndLabelControl
. Make the class public and make it inherit from WPF Control
class:
public class EditableTextAndLabelControl : Control
{
}
Just like in the previous sample, add two string
typed dependency properties to it: TheLabel
and TheEditableText
; also add SaveEvent
of type Action<string, string>
. It is best to use propdp snippet for defining dependency properties in a class. The result will look like this:
public partial class EditableTextAndLabelControl : Control
{
public event Action<string, string> SaveEvent = null;
#region TheLabel Dependency Property
public string TheLabel
{
get { return (string)GetValue(TheLabelProperty); }
set { SetValue(TheLabelProperty, value); }
}
public static readonly DependencyProperty TheLabelProperty =
DependencyProperty.Register
(
"TheLabel",
typeof(string),
typeof(EditableTextAndLabelControl),
new PropertyMetadata(null)
);
#endregion TheLabel Dependency Property
#region TheEditableText Dependency Property
public string TheEditableText
{
get { return (string)GetValue(TheEditableTextProperty); }
set { SetValue(TheEditableTextProperty, value); }
}
public static readonly DependencyProperty TheEditableTextProperty =
DependencyProperty.Register
(
"TheEditableText",
typeof(string),
typeof(EditableTextAndLabelControl),
new PropertyMetadata(null)
);
#endregion TheEditableText Dependency Property
}
This is basically it - we have defined the lookless control. Let us place the controls into the MainWindow.xaml file and see how they look. Here is the XAML code of MainWindow.xaml (in fact it is identical to the one of the previous sample):
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<this:EditableTextAndLabelControl x:Name="MyControl1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TheLabel="MyText"
Margin="0,10"/>
<this:EditableTextAndLabelControl x:Name="MyControl2"
Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TheLabel="MyOtherText"
Margin="0,10"/>
<TextBlock x:Name="TheSaveEventLog"
Grid.Row="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</Grid>
If we try to run the project as is, we shall get an empty window. The reason is that we never defined the visual representation for the lookless control. We should define it as ControlTemplate
. For clarity sake XAML coders usually create a special project folder for templates and styles. Let us create the folder "Themes" in our project and create a WPF Resource dictionary SampleControls.xaml in it. We can define the XML namespace this
by adding the following line to header tag of the resource dictionary: xmlns:this="clr-namespace:LooklessControlSample"
. Then within the ResourceDictionary
we can define our control template:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:this="clr-namespace:LooklessControlSample">
<ControlTemplate x:Key="TheHorizontalTemplateForEditableTextAndLabelControl">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="TheLabelTextBlock"
Text="{Binding Path=TheLabel, RelativeSource={RelativeSource AncestorType=this:EditableTextAndLabelControl}}"
VerticalAlignment="Bottom" />
<TextBox x:Name="TheEditableTextTextBox"
Grid.Column="1"
Width="100"
Text="{Binding Path=TheEditableText, RelativeSource={RelativeSource AncestorType=this:EditableTextAndLabelControl}}"
VerticalAlignment="Bottom"
Margin="10,0,10,0" />
<Button x:Name="SaveButton"
Content="Save"
Width="70"
Grid.Column="2"
VerticalAlignment="Bottom" />
</StackPanel>
</ControlTemplate>
<ResourceDictionary/>
In order to make our MainWindow.xaml file notice the SampleControls.xaml file we need to add the following XAML code to its top:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/SampleControls.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
Note that if the XAML resource dictionary files are located in a different project, the short notation for the Source
property above is not sufficient, one would also need to specify the assembly name.
To make the controls recognize the fact that they have that template, we set their Template
properties to "{StaticResource TheHorizontalTemplateForEditableTextAndLabelControl}"
.
Now if we run our code, we shall see the application that is almost similar to the one of our previous sample except that nothing happens when we press button "Save" on our controls.
There are 3 major ways to make the lookless controls aware of the events happening on its visuals:
- Using built-in WPF Command Functionality
- Using MS Expression Blend SDK
- By accessing control's visual parts from C# code.
We shall describe all of them below.
Communicating between the Visual and Non-Visual Parts of the Lookless Control using built-in WPF Command Functionality
This is the way that most WPF tutorials describe, it is also the worst way of communicating between the visual and non-visual functionality. It is bad because of two reasons:
- Only a few events on a few controls, like
Click
event on a Button
or Menu
controls can be handled using command functionality. - It will require a modification of the lookless control class by adding a
DelegateCommand
object to it.
Since we do not think that this is a good way of communicating between the visual and non-visual functionality and since it has been widely covered elsewhere - we are not going to provide an example for it here.
Communicating between the Visual and Non-Visual Parts of the Lookless Control using MS Expression Blend SDK
This is probably the most elegant way to pass the events from the visual (XAML) to non-visual code. I've described this method in detail in MVVM Pattern Made Simple article applying it to MVVM pattern. The same principle can be applied in lookless controls.
First of all, do not be put down by the words "Expression Blend" - this is just an SDK and you do not have to install MS Expression Blend in order to obtain it. In fact it can be downloaded from MS Expression Blend SDK and used for free. On top of that, we only need two dll files from the SDK: Microsoft.Expression.Interactions.dll and System.Windows.Interactivity.dll and we provide these files together with our code under MSExpressionBlendSDKDlls folder.
Since you download these files from the internet, you'll probably have to unblock them. In order to do it, right click on each of the files, choose Properties menu item and click "Unblock" button.
The project, of course, needs to reference those files and in order to get access to the SDK functionality the following xml namespaces should be added to the top tag of "SampleControls.xaml":
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
Let us add a method Save
to our lookless control EditableTextAndLabelControl
:
public void Save()
{
if (SaveEvent != null)
SaveEvent(TheLabel, TheEditableText);
}
This method simply fires SaveEvent
.
Now we can make the button SaveButton
call method Save
of the EditableTextAndLabelControl
class by adding the following XAML code within the <Button>
tag:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click"
SourceObject="{Binding ElementName=SaveButton}">
<ei:CallMethodAction MethodName="Save"
TargetObject="{Binding RelativeSource={RelativeSource AncestorType=this:EditableTextAndLabelControl}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
Now, if we run the project it will run exactly like the one from the previos section - adding lines when the "Save" button is pressed.
Communicating between the Visual and Non-Visual Parts of the Lookless Control by Accessing Control's Visual Parts from C# code.
This method is most complex and should only be used when it is necessary to get full access to the control's visuals from the C# code. We shall explain this method in detail later in order not to break the narration.
Different Layouts for the same Lookless Control
Here we are going to show how to produce different visual layouts for the same lookless control.
Open the file "SampleControls.xaml" and create another ControlTemplate
almost exactly the same as our "TheHorizontalTemplateForEditableTextAndLabelControl" template, only using vertical StackPanel
orientation instead of horizontal. Let us call this ControlTemplate
"TheVerticalTemplateForEditableTextAndLabelControl":
<ControlTemplate x:Key="TheVerticalTemplateForEditableTextAndLabelControl"
TargetType="this:EditableTextAndLabelControl">
<StackPanel Orientation="Vertical">
<TextBlock x:Name="TheLabelTextBlock"
Text="{Binding Path=TheLabel, RelativeSource={RelativeSource AncestorType=this:EditableTextAndLabelControl}}"
VerticalAlignment="Bottom" />
<TextBox x:Name="TheEditableTextTextBox"
Grid.Column="1"
Width="100"
Text="{Binding Path=TheEditableText, RelativeSource={RelativeSource AncestorType=this:EditableTextAndLabelControl}}"
VerticalAlignment="Bottom"
Margin="10,0,10,0" />
<Button x:Name="SaveButton"
Content="Save"
Width="70"
Grid.Column="2"
VerticalAlignment="Bottom">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click"
SourceObject="{Binding ElementName=SaveButton}">
<ei:CallMethodAction MethodName="Save"
TargetObject="{Binding RelativeSource={RelativeSource AncestorType=this:EditableTextAndLabelControl}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
</ControlTemplate>
Let us assign this template to the second control:
<this:EditableTextAndLabelControl x:Name="MyControl2"
Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Template="{StaticResource TheVerticalTemplateForEditableTextAndLabelControl}"
TheLabel="MyOtherText"
Margin="0,10" />
Here is what we are going to get:

Two controls of the same type are styled in two different ways by two different templates.
Using WPF Styles instead of Templates
Very often WPF developers prefer to use Style
s instead of ControlTemplate
s. The Style
would allow to set Template
property on a control, but it can also be used for setting other properties e.g. Width
, Height
, alignments and so on. Also a style without a key (but with TargetType
property defined) can be considered a default style for the control. E.g. if we assume that in majority of cases we'll need the horizontal template, we can make the corresponding style to be the default while in order for the control to get a vertical style one would have to provide the key.
Such styles are defined in Themes/SampleControls.xaml
file of the sample:
<Style TargetType="this:EditableTextAndLabelControl">
<Setter Property="Template"
Value="{StaticResource TheHorizontalTemplateForEditableTextAndLabelControl}" />
</Style>
<Style TargetType="this:EditableTextAndLabelControl"
x:Key="TheVerticalStyleForEditableTextAndLabelControl">
<Setter Property="Template"
Value="{StaticResource TheVerticalTemplateForEditableTextAndLabelControl}" />
</Style>
The controls, defined in MainWindow.xaml
file should not be setting the Template
any more (Style
s will do it for them). The horizontal control does not have to define anything extra (the default style will be applied to it by default), while the vertical one, should set its style to the corresponding resource:
<this:EditableTextAndLabelControl x:Name="MyControl1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TheLabel="MyText"
Margin="0,10" />
<this:EditableTextAndLabelControl x:Name="MyControl2"
Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Style="{StaticResource TheVerticalStyleForEditableTextAndLabelControl}"
TheLabel="MyOtherText"
Margin="0,10" />
Further Reuse by using Orientation Dependency Property
Note, that in the example above, the horizontal and vertical representations of the control are very similar. They both consist of the same building blocks: a TextBlock
, a TextBox
and a Button
. In general they do not have to be similar and can consists of totally different building blocks - the visual design is entirely up to the developer. Many times, however, it makes sense that the controls will be somewhat similar, and in such case, we can improve the code reuse further as we discuss in this subsection.
The code for this sample can be found under LooklessControlWithOrientationPropertySample
solution. EditableTextAndLabelControl
in this project is almost exactly the same as above, only it has one extra dependency property - TheOrientation
:
#region TheOrientation Dependency Property
public Orientation TheOrientation
{
get { return (Orientation)GetValue(TheOrientationProperty); }
set { SetValue(TheOrientationProperty, value); }
}
public static readonly DependencyProperty TheOrientationProperty =
DependencyProperty.Register
(
"TheOrientation",
typeof(Orientation),
typeof(EditableTextAndLabelControl),
new PropertyMetadata(Orientation.Horizontal)
);
#endregion TheOrientation Dependency Property
This property can be used in the Control Template to define the orientation of the control. This is exactly what we did in SampleControls.xaml
file:
<ControlTemplate x:Key="TheTemplateForEditableTextAndLabelControl"
TargetType="this:EditableTextAndLabelControl">
<StackPanel Orientation="{Binding Path=TheOrientation, RelativeSource={RelativeSource TemplatedParent}}">
<TextBlock x:Name="TheLabelTextBlock"
Text="{Binding Path=TheLabel, RelativeSource={RelativeSource AncestorType=this:EditableTextAndLabelControl}}"
VerticalAlignment="Bottom" />
<TextBox x:Name="TheEditableTextTextBox"
Grid.Column="1"
Width="100"
Text="{Binding Path=TheEditableText, RelativeSource={RelativeSource AncestorType=this:EditableTextAndLabelControl}}"
VerticalAlignment="Bottom"
Margin="10,0,10,0" />
<Button x:Name="SaveButton"
Content="Save"
Width="70"
Grid.Column="2"
VerticalAlignment="Bottom">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click"
SourceObject="{Binding ElementName=SaveButton}">
<ei:CallMethodAction MethodName="Save"
TargetObject="{Binding RelativeSource={RelativeSource AncestorType=this:EditableTextAndLabelControl}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
</ControlTemplate>
At the top of the template, we bind the StackPanel
's Orientation
property to TheOrientation
property of the control:
<StackPanel Orientation="{Binding Path=TheOrientation, RelativeSource={RelativeSource TemplatedParent}}">
In MainWindow.xaml
file (where the controls are used), we have to set the corresponding control's orientations:
<this:EditableTextAndLabelControl x:Name="MyControl1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TheLabel="MyText"
TheOrientation="Horizontal"
Margin="0,10" />
<this:EditableTextAndLabelControl x:Name="MyControl2"
Grid.Row="1"
TheOrientation="Vertical"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TheLabel="MyOtherText"
Margin="0,10" />
Note that in this case, we have only one control template for both horizontal and vertical representations of the control. The extra property TheOrientation
gave us another degree of freedom in control's customization!
Note, also, that we can add more dependency properties to the control in defining e.g. margins between different elements within the control, colors, etc.
Finally I'd like to discuss the binding between the Orientation
property of the StackPanel
and TheOrientation
property of the EditableTextAndLabel
control that so greatly increased the flexibility of our visual representation:
<StackPanel Orientation="{Binding Path=TheOrientation, RelativeSource={RelativeSource TemplatedParent}}">
Since it is defined within ControlTemplate
of the control, we can use TemplatedParent
mode to bind it to a property on the control. Another, more generic way of performing this binding would be by using AncestorType
mode:
<StackPanel Orientation="{Binding Path=TheOrientation, RelativeSource={RelativeSource AncestorType=this:EditableTextAndLabelControl}}">
This binding mode can be used, even when the control's component is not defined within the ControlTemplate
of the control (as long as we are sure that the component is contained within the control).
A shorthand for {Binding Path=TheOrientation, RelativeSource={RelativeSource TemplatedParent}}
, BTW, is {TemplateBinding TheOrientation}
- which we could have used above.
A Non-Invasive Method of Adding a Property to a Control
Assume that you want to add a property (like we added TheOrientation
property to EditableTextAndLabel
control), without modifying the control itself. It can be useful when e.g. you do not have a code for the control and when you do not want to or cannot derive another class from it, or when you want to apply the same property to many different unrelated controls.
WPF provides an easy way of doing it by employing attached properties.
Project LooklessControlWithOrientationAttachedPropertySample
contains the corresponding sample. As you can see, its code is similar to the one in the previous sample, aside from the fact that TheOrientation
property is defined as an attached property in a static class AttachedProperties
:
#region TheOrientation attached Property
public static Orientation GetTheOrientation(DependencyObject obj)
{
return (Orientation)obj.GetValue(TheOrientationProperty);
}
public static void SetTheOrientation(DependencyObject obj, Orientation value)
{
obj.SetValue(TheOrientationProperty, value);
}
public static readonly DependencyProperty TheOrientationProperty =
DependencyProperty.RegisterAttached
(
"TheOrientation",
typeof(Orientation),
typeof(AttachedProperties),
new PropertyMetadata(Orientation.Horizontal)
);
#endregion TheOrientation attached Property
The references to the property are also updated to reflect the fact that it is now an attached property. Here is the line containing the binding to this property from SampleControls.xaml
file:
<StackPanel Orientation="{Binding Path=(this:AttachedProperties.TheOrientation), RelativeSource={RelativeSource TemplatedParent}}">
Note that within the binding path, attached properties are defined in parenthesis.
Also the lines within MainWindow.xaml
file where the attached properties are set need to be modified:
<this:EditableTextAndLabelControl x:Name="MyControl1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TheLabel="MyText"
this:AttachedProperties.TheOrientation="Horizontal"
Margin="0,10" />
<this:EditableTextAndLabelControl x:Name="MyControl2"
Grid.Row="1"
this:AttachedProperties.TheOrientation="Vertical"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TheLabel="MyOtherText"
Margin="0,10" />
Generic Paradigms Represented by our Lookless Control Samples
Skeleton-Meat Paradigm
The lookless control provides an illustration for a WPF paradigm repeated again and again within the framework - I call it Skeleton-Meat paradigm.
Skeleton is represented by some simple functionality that nails down the public interface of a reusable component. In case of the lookless controls the Skeleton is defined by our EditableTextAndLabelControl
class and consists of its properties, events and functions.
Meat part is built around the Skeleton. It is usually much more complex than the Skeleton. It reflects the Skeleton's properties and mimics Skeleton's behaviors. It can also provide its own interactions and behaviors, except that they are always private behaviors of the component and do not affect the component's interaction with other components.
In our case Meat is represented by the Style
and TemplateControl
objects defined in XAML.
Note that Meat part has access to Skeleton part (it needs to know the properties it should display and/or modify and the behaviors it needs to mimic). Skeleton part is usually completely unaware about the Meat - I say usually, because sometimes for more complex controls the C# Skeleton of a control might have some 'vague' knowledge about various parts within the control's Template
.
Note that in MainWindow.xaml
file where our lookless controls are used, we plug in the control itself, defining its properties for external interactions - the Meat part is essentially not used there.
Non-Invasiveness
The second paradigm that I'd like to discuss here is Non-Invasiveness. WPF provides a way to add a property to a control without modifying the control itself by using Attached Properties. Moreover, this property can be used both within C# and XAML code for modifying the control's look and behavior.
From my viewpoint, it is very important because it allows better separation of concerns. E.g. the control itself can contain only core properties for the main interactions with the parts of the application external to the control while some look and feel issues can be managed by attaching properties to the control.
Attached events are also part of Non-Invasiveness paradigm and will be discussed later.
Composition Hierarchy
Another paradigm that we observed is Composition Hierarchy. We can compose controls out of other controls which are in turn composed of finer controls etc. In our case, MainWindow
control consists of two EditableTextAndLabelControl
objects (placed within a Grid
panel and with a TextBlock
for displaying the messages). In their turn EditableTextAndLabelControl
objects consist of a TextBlock
a TextBox
and a Button
.
MainWindow
in our case is more like a UserControl
, but the same Composition Hierarchy concept can be applied to lookless controls. One can assemble a bunch of lookless controls into "super" lookless control within its template while connecting their properties that we want to manipulate at the "super" lookless control level by using bindings. In our case, we connected Text
property of a TextBlock
to TheLabel
property and Text
property of a TextBox
to TheEditableText
property of the lookless control.
We could also create more properties on our EditableTextAndLabelControl
that would be in charge of e.g. label text color and editable text color - e.g. we could have defined LabelForeground
and EditableTextForeground
properties on our EditableTextAndLabelControl
and connect them to the corresponding components' properties within the template using bindings.
Restyling the Lookless Controls
Note that since Meat part is not used for external interactions, it can be easily swapped without affecting the whole application. In our case, we showed how, by using two different templates, we can present our lookless control in two different ways - horizontally and vertically. One can come up with much more dramatic examples, like in e.g. Creating a look-less custom control in WPF where analog and digital clocks are created based on the same lookless control, or The power of Styles and Templates in WPF where a WPF ListBox
control is re-styled into the Solar system.
Note that all of the built-in WPF controls are lookless controls and thus allow tremendous customization. Most of the 3rd party controls at least for Teleric and DevExpress frameworks are also lookless controls.
Accessing Elements Defined in XAML Control Template from the C# Code of the Control
Now, as I promised above, I'd like to show how to access parts of the template from the C# code of a lookless control. In this case, the Skeleton obtains some knowledge of the Meat so that it might impose some restrictions on how the Meat (the Template
) can be constructed. This should only applied when some complex behaviors (e.g. resizing etc.) is expected from the control and is totally unnecessary for our simple EditableTextAndLabelControl
but to keep things simple I'll use our control for this example.
The code for this sample is located under FindingTemplatePartInCodeSample
project. Instead of using Expression Blend SDK functionality, we get a reference to the button defined by the template from the C# code and add a handler to its Click
event, firing SaveEvent
of the control when it happens.
The ControlTemplate
defined in SampleControls.xaml
file becomes only simpler. It does not need references to the Expression Blend SDK and its button does not have any triggers:
<Button x:Name="PART_SaveButton"
Content="Save"
Width="70"
Grid.Column="2"
VerticalAlignment="Bottom" />
Note that the name of the button was changed to have prefix "PART_". This is a general convention for parts of the control that C# code expects to find.
EditableTextAndLabelControl
code was changed in the following way. I removed method Save()
and instead added the following code:
Button _saveButton = null;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (this.Template == null)
return;
_saveButton = this.Template.FindName("PART_SaveButton", this) as Button;
if (_saveButton != null)
_saveButton.Click += _saveButton_Click;
}
void _saveButton_Click(object sender, RoutedEventArgs e)
{
if (SaveEvent != null)
SaveEvent(TheLabel, TheEditableText);
}
OnApplyTemplate()
method pulls the button control out of the template by its name "PART_SaveButton". It also adds _saveButton_Click
handler to the Button
's Click
event.
Note that using this method breaks the principle that the Skeleton does not know anything about the Meat and so, the method should be used as little as possible.
Dependency or Attached Property Change Detection Pattern
When a dependency or attached property is defined, one can specify a callback to be fired when this property changes. This can be sometimes very useful, as it allows to fire events, or do some other processing within the Skeleton ones a property changes on the control.
E.g. let us assume that we want to remove the button from our EditableTextAndLabelControl
and instead fire the SaveEvent
once TheText
property changes. Note that binding on the Text
property of the TextBox
(defined in the XAML template) has control over when to change the TheText
to which it binds. By default it which change on focus lost, while if we set UpdateSourceTrigger
property of the binding to PropertyChanged
it will start changing on every character typed or deleted.
The code for this sample is located under DependencyPropertyChangeDetectionSample
project.
The definition of TheEditibleText
dependency property now includes a callback - OnEditableTextChanged
. This callback calls our old Save()
method which in turn fires the SaveEvent
:
public static readonly DependencyProperty TheEditableTextProperty =
DependencyProperty.Register
(
"TheEditableText",
typeof(string),
typeof(EditableTextAndLabelControl),
new PropertyMetadata(null, OnTheEditableTextChanged)
);
private static void OnTheEditableTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((EditableTextAndLabelControl)d).Save();
}
The template defined in SampleControls.xaml
file, now does not have the "Save" Button
, and the binding of property Text
of its TextBox
control now has UpdateSourceTrigger
set to PropertyChanged
so that every key stroke will invoke SaveEvent
:
<TextBox x:Name="TheEditableTextTextBox"
Grid.Column="1"
Width="100"
Text="{Binding Path=TheEditableText,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource AncestorType=this:EditableTextAndLabelControl}}"
VerticalAlignment="Bottom"
Margin="10,0,10,0" />
Here is how the app will look when the user types "Hello World" in MyOtherText
control:

Now, assume that we want to detect a change of a dependency (or attached) property on a control, but we do not have access to the code that defines that property and therefore cannot add a handler to it.
A standard way of dealing with this situation would be to define our own attached or dependency property, bind it to the changing property and detect the change of our property (whose code we have access to). Indeed, this is what we've done to the Text
property of the TextBox
control. In the example above, we are detecting when it changes by binding it to TheEditableText
property of our control and defining a callback on TheEditableText
property.
Behavior Pattern
This is a great pattern in order to improve the separation of concerns. To the best of my knowledge, it was first introduced by Expression Blend SDK.
It is actually very easy to create behavior functionality without using Expression Blend SDK and here I show how. In fact, as will be shown in the subsequent article(s), the behavior pattern is not unique to WPF and can be used for purely non-visual functionality - a slight modification to the IBehavior Interface presented in this article can make it completly WPF agnostic.
Behavior is a C# object which by being attached to another object, e.g. a WPF control, changes its behavior by adding behavior specific handlers to the object's events. Behavior knows the WPF object it modifies while the WPF object does not have any knowledge of the behavior(s) attached to it. Behavior is thus part of the Meat, but since it is built in C# it has more power to transform the object than Meat contained in XAML.
The best way to attach a behavior to a WPF object is non-invasively - via an attached property. Usually behaviors are defined as XAML resources and attached to WPF objects in XAML.
To see a behavior sample, open BehaviorSample
project. IBehavior
is an interface that all behaviors should implement:
public interface IBehavior
{
void Attach(FrameworkElement el);
void Detach(FrameworkElement el);
}
Static class AttachedProperties
contains TheBehavior
attached property that allows to attach a behavior to any FrameworkElement
. The property change callback method OnBehaviorChanged
calls OnDetach
method for the old behavior and OnAttach
method for the new:
private static void OnTheBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement el = (FrameworkElement)d;
IBehavior oldBehavior = (IBehavior) e.OldValue;
if (oldBehavior != null)
oldBehavior.Detach(el);
IBehavior newBehavior = (IBehavior) e.NewValue;
if (newBehavior != null)
newBehavior.Attach(el);
}
ChangeOpacityOnMouseOverBehavior
defines a behavior that changes opacity of an element to 0.5 when the mouse moved on top of the element and then changes it back to 1 when the mouse moves out:
public class ChangeOpacityOnMouseOverBehavior : IBehavior
{
public void Attach(FrameworkElement el)
{
el.MouseEnter += el_MouseEnter;
el.MouseLeave += el_MouseLeave;
}
void el_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
FrameworkElement el = (FrameworkElement)sender;
el.Opacity = 1;
}
void el_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
FrameworkElement el = (FrameworkElement)sender;
el.Opacity = 0.5;
}
public void Detach(FrameworkElement el)
{
el.MouseLeave -= el_MouseLeave;
el.MouseEnter -= el_MouseEnter;
}
}
Finally inside MainWindow.xaml
file we define a Grid
panel in the center of the window with green Background
and attach the behavior to it:
<Window.Resources>
<this:ChangeOpacityOnMouseOverBehavior x:Key="TheChangeColorBehavior" />
</Window.Resources>
<Grid>
<Grid HorizontalAlignment="Center"
VerticalAlignment="Center"
Height="30"
Width="100"
Background="Green"
this:AttachedProperties.TheBehavior="{StaticResource TheChangeColorBehavior}" />
</Grid>
As a result, a green rectangle is displayed in the middle of the window, whose opacity reduces when mouse is placed over it:

Note that the above pattern will only allow to have no more than one behavior attached to one object. This is not always convenient. In order to attach multiple behaviors to the same object we can define an attached property TheBehaviors
instead of TheBehavior
. This property can be of type IEnumerable<IBehavior>
.
Example of attaching multiple behaviors to the same object is located under AttachingMultipleBehiorsToObjectSample project. Instead of TheBehavior
attached property, here we have TheBehaviors
property of the type IEnumerable<IBehavior>
. On top of ChangeOpacityOnMouseOverBehavior
, we also define ChangeWidthBehavior
which expands the visual element when the mouse is over it and reverts it to the original size when the mouse is moved away. In MainWindow.xaml file we create an array two such behaviors and attach them to the Grid
panel by using TheBehaviors
attached property:
<Window.Resources>
<x:Array Type="this:IBehavior" x:Key="TheBehaviors">
<this:ChangeOpacityOnMouseOverBehavior/>
<this:ChangeWidthBehavior />
</x:Array>
</Window.Resources>
<Grid>
<Grid HorizontalAlignment="Center"
VerticalAlignment="Center"
Height="30"
Width="100"
Background="Green"
this:AttachedProperties.TheBehaviors="{StaticResource TheBehaviors}" />
</Grid>
When running the sample, you can see that not only the opacity of the green rectangle in the center of the windows changes, but also the rectangle expands horizontally when the mouse is over it.
Template Parts and Loose Coupling
Perhaps the most important advantage related to ControlTemplate
s is the fact that they allow to achieve a great degree of independence between different parts of a control (Loose Coupling).
We shall start with a simple fact that any Control
object is essentially replaced in the visual tree by its template. The control object will still exist in the visual tree, of course, but only as a container. To illustrate this, please open ControlTemplateReplacementSample
project.
All of the project's significant code is located in MainWindow.xaml
file. We define a very simple template within Window.Resources
section:
<ControlTemplate x:Key="MyControlTemplate">
<Grid Background="Yellow">
<TextBlock Text="Hello World" Margin="30"/>
</Grid>
</ControlTemplate>
and then assign this template to a control:
<Control x:Name="MyControl"
Template="{StaticResource MyControlTemplate}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
as a result, when we open the window, we see text "Hello World" within a yellow rectangle, just as if we placed the code of the template within the main window instead of the Control
"MyControl":

The main example of Template Parts Loose Coupling pattern is located under MultipleTemplatePartsSample
project. It defines one lookless control MyTestControlWithHeader
. This control has 3 dependency properties - HeaderTemplate
, MainTemplate
and EventLog
. Two first properties are of ControlTemplate
type; they correspond to the two templates - one for the control's header and another for the "main" part of the control. The third property is just a string representing a "log" of some visual events happening on the control.
The lookless control also defines a method LogClickEvent()
. At each invocation it appends the following line to the EventLog
string: "Click Received":
public class MyTestControlWithHeader : Control
{
#region HeaderTemplate Dependency Property
public ControlTemplate HeaderTemplate
{
get { return (ControlTemplate)GetValue(HeaderTemplateProperty); }
set { SetValue(HeaderTemplateProperty, value); }
}
public static readonly DependencyProperty HeaderTemplateProperty =
DependencyProperty.Register
(
"HeaderTemplate",
typeof(ControlTemplate),
typeof(MyTestControlWithHeader),
new PropertyMetadata(null)
);
#endregion HeaderTemplate Dependency Property
#region MainTemplate Dependency Property
public ControlTemplate MainTemplate
{
get { return (ControlTemplate)GetValue(MainTemplateProperty); }
set { SetValue(MainTemplateProperty, value); }
}
public static readonly DependencyProperty MainTemplateProperty =
DependencyProperty.Register
(
"MainTemplate",
typeof(ControlTemplate),
typeof(MyTestControlWithHeader),
new PropertyMetadata(null)
);
#endregion MainTemplate Dependency Property
#region EventLog Dependency Property
public string EventLog
{
get { return (string)GetValue(EventLogProperty); }
set { SetValue(EventLogProperty, value); }
}
public static readonly DependencyProperty EventLogProperty =
DependencyProperty.Register
(
"EventLog",
typeof(string),
typeof(MyTestControlWithHeader),
new PropertyMetadata(null)
);
#endregion EventLog Dependency Property
public void LogClickEvent()
{
EventLog += "\nClick Recieved";
}
}
The control's style and template are defined within MainWindow.xaml
file:
<Style TargetType="this:MyTestControlWithHeader">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="this:MyTestControlWithHeader">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Control x:Name="HeaderControl"
Template="{Binding Path=HeaderTemplate, RelativeSource={RelativeSource TemplatedParent}}" />
<Control x:Name="MainControl"
Grid.Row="1"
Template="{Binding Path=MainTemplate, RelativeSource={RelativeSource TemplatedParent}}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
As you can see, the control's template consists of a Grid
panel with two rows - both rows contain Control
objects. The upper row contains Control
named "HeaderControl" - whose Template
property is bound to HeaderTemplate
property of the MyTestControlWithHeader
object. The lower row contains Control
named "MainControl" whose Template
property is bound to MainTemplate
property of the MyTestControlWithHeader
object.
The important thing is that we can plug any two templates as HeaderTemplate
and MainTemplate
properties and make them work together via MyTestControlWithHeader
functionality without being actually aware of one another.
This is exactly what we do - we define two templates: MyHeaderTemplate1
and MyMainTemplate1
(their names were chosen to underscore that they can be easier replaced) and plug them into the main control:
<this:MyTestControlWithHeader HeaderTemplate="{StaticResource MyHeaderTemplate1}"
MainTemplate="{StaticResource MyMainTemplate1}"/>
Here is code for "MyHeaderTemplate1" template:
<ControlTemplate x:Key="MyHeaderTemplate1">
<Grid Height="50"
Background="Yellow">
<StackPanel Orientation="Horizontal">
<Button Content="Button to Click"
Height="25"
Width="120"
Margin="5,0">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:CallMethodAction TargetObject="{Binding RelativeSource={RelativeSource AncestorType=this:MyTestControlWithHeader}}"
MethodName="LogClickEvent" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
</Grid>
</ControlTemplate>
It contains a button whose click results in calling LogClickEvent
method on the containing MytestControlWithHeader
object.
Here is the "MyMainTemplate1" template:
<ControlTemplate x:Key="MyMainTemplate1">
<Grid Background="Green">
<TextBlock x:Name="LogText"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="Black"
Text="{Binding Path=EventLog, RelativeSource={RelativeSource AncestorType=this:MyTestControlWithHeader}}" />
</Grid>
</ControlTemplate>
It defines a text block whose Text
property is bound to EventLog
property of the containing MyTestControlWithHeader
object.
Now, if you run the application - clicking on the button in the header will result to adding a text line "Click Received" to the main part of the control:

As you see, the two template parts have no knowledge whatsoever of one another. They have some knowledge of the containing lookless control, and communicate via its methods and properties. Clicking on the header Button
invokes LogClickEvent()
method of the lookless control (via MS Expression Blend SDK plumbing). This method adds a text line to the EventLog
property of the same object, which in turn has Text
property of the TextBlock
within the MainTemplate
bound to it.
Conclusions
In this article we discussed practical patterns for code reuse based on WPF Control
s and ControlTemplate
functionality. In the subsequent article(s) we plan to discuss View-View Model based patterns which have even higher potential for code reuse and separation of concerns.
Acknowledgement
A hat tip to my colleague Chad Wright for pointing some errors in this article.