BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Windows Presentation Foundation
.NET 4.0+

WPF Control Templates - Creating a Template

The one hundred and sixtieth part of the Windows Presentation Foundation Fundamentals tutorial looks at the basic techniques required to create custom control templates. These can completely change the look and feel of the standard WPF controls.

Control Templates

In recent articles in the WPF tutorial we have used styles to customise the appearance of controls. With the use of styles we've seen how you can centralise a group of property values and apply them to multiple, similar controls for a standardised appearance. We expanded upon styles with property triggers, event triggers and data triggers, each allowing the properties of a control to be amended automatically in response to user actions or other events. We saw how these changes could be instantaneously applied or slowly and smoothly animated.

All of these techniques allow you to change the visuals of controls, customising them to fit the overall style of your application. However, the underlying appearance of the controls remains similar. For example, no matter how you update the standard properties of a WPF button, it is still a rectangular button that shows specified content.

WPF allows even more flexibility for changing the user interface controls with the use of control templates. Instead of merely changing colours, sizes and fonts, a control template completely replaces a control's visual tree, whilst retaining its functionality. With the correct control template, you might create a circular button or a progress bar that appears as a gauge that is similar to a car's speedometer. Either can be achieved with pure XAML.

In this article, and the few that follow, we'll look at the basics of creating and applying control templates to several WPF controls, starting with changes to the standard Button. To begin, create a new WPF application in Visual Studio. Name the solution, "ControlTemplateDemo". Once it is ready, replace the XAML in the main window with the code below:

<Window x:Class="ControlTemplateDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Control Template Demo" Height="250" Width="350">
    <Grid>
        <Button Width="100" Height="50" Click="OKClick">OK</Button>
    </Grid>
</Window>

This code produces a window containing a single button with its Click event registered. Switch to the code behind the window and add the following method to respond to the button being clicked:

private void OKClick(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Hello, world!");
}

Run the program to see the results. Clicking the button should display a message box.

WPF control template demo window

Creating a Control Template

You can create a new template for a control within a ControlTemplate object. This class provides a container for the controls, shapes and other user interface elements that will replace the normal visual tree for the control. You can create and apply the template using the target control's Template property. However, it is more common to create the template as a resource. This way it can be reused, in a similar manner to reusing styles, with a static or dynamic resource reference from within individual controls or as part of a style.

Let's define a control template for the button as a resource within the window's Resources collection. We need to provide a Key for the resource, so that it can be easily referenced, and specify the type of control to which it can be applied, using the TargetType property.

Add the following Window.Resources section to the XAML, immediately after the opening Window tag:

<Window.Resources>
    <ControlTemplate x:Key="MyButtonTemplate" TargetType="Button">
    </ControlTemplate>
</Window.Resources>

Let's apply the empty template to the button by setting its Template property. Update the button's XAML, as follows:

<Button Width="100" Height="50" Click="OKClick"
        Template="{StaticResource MyButtonTemplate}">OK</Button>

If you have the designer pane visible in Visual Studio, you will see that the button vanishes. If you don't use the designer, run the program to see that the button is no longer visible. This is because we have removed the control's entire visual tree and replaced it with the contents of our control template, which is empty.

Let's add some user interface elements to the template. Update the XAML for the ControlTemplate, as follows:

<ControlTemplate x:Key="MyButtonTemplate" TargetType="Button">
    <Grid>
        <Border Background="Black" Margin="5 5 0 0" />
        <Border BorderBrush="Black" BorderThickness="1"
                Background="Yellow" Margin="0 0 5 5">
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">OK</TextBlock>
        </Border>
    </Grid>
</ControlTemplate>

The template includes two Borders and a TextBlock containing the text, "OK". The borders are arranged in a single-cell Grid, using their margins to give the appearance of a box with a drop-shadow.

WPF button with custom control template

Run the program to see the results. Although we have completely replaced the user interface for the button, its functionality is unchanged. Click anywhere within the borders to see the message box appear.

Limitations

This initial example should show how powerful control templates can be when you wish to fundamentally change the appearance of controls in ways that are not possible using simple properties. However, the example has a few limitations. The first is that most properties set against the button are not reflected in the window. For example, changing the button's Background value has no effect.

The second limitation is that the content is currently fixed; if you change the content of the button, the user interface will still show the text, "OK", as this is hard-coded into the control template. A similar problem occurs with the positioning of the items in templates for ItemsControls.

Over the next few articles we will see how to overcome these limitations for the Button class and for other WPF controls.

24 May 2015