Overview


Download the code: http://gallery.technet.microsoft.com/WPF-Control-Template-462749f0

One thing that really attracted me to WPF was the facility where I could override the default layout and behaviour of practically any control. Wielding this type of power has led me to create some stunning controls with minimal effort.

Today I’m going to show you how you can make your life easier by using WPF Control Templates. Control Templates can be implemented and referenced in a number of different ways. We will focus on the simplest form whereby a Control Template is referenced using the Template property on a control.

The star of our show today will be a Button. We will override both the layout and behaviour of this Button. The button will have an image; by default a button control does not support one. Whenever the mouse moves over the button, we will change the color of the border that surrounds it. We will create a class that inherits from Button so we can add an Image property but also use the features that come standard with a button.

Creating the project

For the purpose of this article we will need to create a WPF Application. You can do so by following these steps:

  1. Open Visual Studio 2010
  2. File -> New Project and select WPF Application
  3. Rename the Application  to ButtonControlTemplate and click OK



Figure 1:
Visual Studio Template Selector

At this point Visual Studio will open showing the Window Designer and XAML. Right click anywhere on the Window Designer and select View Code from the context menu.

When the code window opens, move outside of the MainWindow Class and create a new class called ButtonTemplate. The ButtonTemplate Class will inherit from Button and this will be the class we use in our XAML to create the buttons on the main window.

Public Class ButtonTemplate 
    Inherits Button 
    Public Property Image As String
End Class

 

This will be the last we see of the code window during this story. At this point we build the application and navigate back to the Window Designer.

For XAML to have any idea of our new ButtonTemplate class we need to set a namespace in our XAML. When you have done this your code should be similar to below:

<Window x:Class="MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ButtonControlTemplate"
    Title="MainWindow" Height="350" Width="525">
    <Grid>



    </Grid>
</Window>

Notice that we have added a namespace ‘local’ as shown here:

xmlns:local="clr-namespace:ButtonControlTemplate"

Our newly created buttons are going to need an image from the project. The images that are included are Add, Save, Delete and Refresh. They will exist in a folder called Images in the root of the project. Images are provided in the download for this article.

 



Figure 2:
 Button Control Template Project with Images

Perfect. Now it’s time to add our Control Template. Control Templates are usually created in the Resource element of the control that is hosting the control that consumes the resource. In this instance the Grid control will be hosting our buttons so it only makes sense to create our Control Template resource in the Grid Control.

    <Grid> 
        <Grid.Resources> 
            <ControlTemplate x:Key="buttonTemplate" TargetType="{x:Type Button}">

The Control Template element above has a Key of buttonTemplate. We use this key from the ButtonTemplate control to reference the Control Template from the Grid Resource.

                <Border x:Name="buttonTemplateBorder" 
                        BorderBrush="LightBlue" BorderThickness="1">

This Border will appear around our custom button control and will change color in the event the mouse moves over it.

                    <Border.Background> 
                        <ImageBrush ImageSource="{Binding 
                          RelativeSource={RelativeSource Mode=TemplatedParent},
                          Path=Image}" Stretch="Fill"/>

The Border Background is changed here by setting the ImageSource of the ImageBrush. The RelativeSource of the Binding has a mode set to TemplatedParent, advertising that it expects the control which is having the template applied has a property called Path for which it can binding to.   

                   </Border.Background> 
              </Border> 
            <ControlTemplate.Triggers>

A Control Template provides numerous triggers for which it can respond to. The triggers are Trigger, DataTrigger, EventTrigger, MultiTrigger and MultiDataTrigger. We will only be using the <Trigger> element in this article. The definitions for all triggers can be found here.

                    <Trigger Property="Button.IsMouseOver" Value="true"> 
                        <Setter TargetName="buttonTemplateBorder" 
                          Property="BorderBrush" Value="Orange"/>

Our Control Template trigger basically captures a mouse over button event and by using a Setter, the color of the border is changed on the Border in the Control Template. The Setter makes this happen by binding the Border Controls Background property to the TargetName property that we configured on the Setter. So whenever a mouse is above our button the border color will change.

                    </Trigger> 
                </ControlTemplate.Triggers> 
            </ControlTemplate> 
        </Grid.Resources>

 

We have also added a button to the window to utilise our control template.

        <local:ButtonTemplate Image="Images/Add.png" 
                  Template="{StaticResource buttonTemplate}" 
                  Height="22" Width="22" Margin="12,12,469,277" />
    </Grid>

Here we have added a button (Figure 3 will have four buttons) to our Grid. We used the <local> namespace to source our ButtonTemplate and we created our button from that. Here we set the location of our image using the Image property. We need to indicate that our button is using a Control Template by setting the Template Property. A StaticeResource is used and will include a ResourceKey which is wired up to our Control Template using the template Key buttonTemplate.

Below is a list of the code used throughout this article

<Window x:Class="MainWindow" 
    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation 
    xmlns
:x=http://schemas.microsoft.com/winfx/2006/xaml 
    xmlns:local="clr-namespace:ButtonControlTemplate" 
          Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
        <Grid.Resources> 
            <ControlTemplate x:Key="buttonTemplate" TargetType="{x:Type Button}"> 
                <Border x:Name="buttonTemplateBorder" 
                        BorderBrush="LightBlue" BorderThickness="1"> 
                    <Border.Background> 
                        <ImageBrush ImageSource="{Binding 
                          RelativeSource={RelativeSource Mode=TemplatedParent},
                          Path=Image}" Stretch="Fill"/> 
                    </Border.Background> 
                </Border> 
                <ControlTemplate.Triggers>                     
                    <Trigger Property="Button.IsMouseOver" Value="true"> 
                        <Setter TargetName="buttonTemplateBorder" 
                          Property="BorderBrush" Value="Orange"/> 
                    </Trigger> 
                </ControlTemplate.Triggers> 
            </ControlTemplate> 
        </Grid.Resources>
        <local:ButtonTemplate Image="Images/Add.png" 
            
Template="{StaticResource buttonTemplate}" 
            
Height="22" Width="22" Margin="12,12,469,277" /> 
        
<local:ButtonTemplate Image="Images/Save.png" 
            
Template="{StaticResource buttonTemplate}" 
            
Height="22" Width="22" Margin="40,12,441,277" /> 
        <local:ButtonTemplate Image="Images/Refresh.png" 
            
Template="{StaticResource buttonTemplate}" 
            
Height="22" Width="22" Margin="68,12,413,277" /> 
        <local:ButtonTemplate Image="Images/Delete.png" 
            
Template="{StaticResource buttonTemplate}" 
            
Height="22" Width="22" Margin="96,12,385,277" /> 
    </Grid>
</Window>




Figure 3:
Shows buttons on a window that utilise our Control Template

Conclusion

Today we have seen how simple it is to incorporate a Control Template into your application

 Resources