Templates in WPF

Templates are an integral part of user interface design in WPF. This article explains templates, their types and how to use them in Windows applications.  

WPF has the following three types of templates:

  • Control Template
  • Items Panel Template
  • Data Template

Control Template

The ControlTemplate of a control defines the appearance of the control. We can change or define a new look and appearance of a control by simply changing the ControlTemplate of a control. ControlTemplates are even more useful when you write your own controls. You can define a default look of your controls. For example, a WPF Button control has a rectangular layout, but using ControlTemplates, you can build a custom button that has a circular layout and changes its color when you mouse over or press it.

The ControlTemplate element in XAML defines a ControlTemplate at design-time. Templates are usually defined as resources using a FrameworkElement's Resources property. The following code snippet is the syntax for defining a ControlTemplate for a Button element.

  1. <Grid>  
  2. <Grid.Resources>  
  3.     <ControlTemplate x:Key="RoundButtonTemplate" />  
  4. </Grid.Resources>  
  5. </Grid>  
OK, let's imagine that we need to create a circular button that looks as in Figure 1 where the outer circle of the button is of a different color than the inner circle and when you mouse over and press the button, it changes the background color.

ok button
           Figure 1

The code snippet in Listing 1 creates a ControlTemplate and adds a Grid as contents of the ControlTemplate. Now, whatever content you put within a ControlTemplate, that is what your control will look like. As you can see from Listing 1, we add two Ellipse elements within a Grid with different radii and different color fills.
  1. <Grid.Resources>  
  2.     <ControlTemplate x:Key="RoundButtonTemplate" >  
  3.         <Grid>                      
  4.       <Ellipse Width="100" Height="100" Name="ButtonBorder"   
  5.                   Fill="OrangeRed"  />  
  6.             <Ellipse Width="80" Height="80" Fill="Orange"  />  
  7.         </Grid>  
  8.     </ControlTemplate>  
  9. </Grid.Resources>  
Listing 1

The following code snippet creates a Button element and sets its Template to the ControlTemplate that we created in Listing 1.
  1. <Button Template="{StaticResource RoundButtonTemplate}" >OK</Button>  
The output generates a Button that looks as in Figure 1.

TargetType Property

The TargetType property is used to restrict the type of element a ControlTemplate can be applied to. The following code snippet ensures that RoundButtonTemplate is applicable on Button elements only.
  1. <ControlTemplate x:Key="RoundButtonTemplate" TargetType="{x:Type Button}" >  
ControlTemplate Triggers

Now how about adding some cool features to this control? Let's animate the button when you mouse over it and press it. We will change the color when you mouse over it and we will decrease the size of the button when it is pressed.

The Triggers property of a ControlTemplate handles the events. The code snippet in Listing 2 adds triggers for IsMouseOver and IsPressed events of Button. On an IsMouseOver event, I changed the color of the InnerCircle of the button. On the IsPressed event, I changed the width and height of InnerCircle and Fill of OuterCircle.
  1. <ControlTemplate.Triggers>  
  2.     <Trigger Property="Button.IsMouseOver" Value="True">  
  3.         <Setter TargetName="InnerCircle" Property="Fill" Value="LightGreen" />  
  4.     </Trigger>  
  5.     <Trigger Property="Button.IsPressed" Value="True">  
  6.         <Setter TargetName="InnerCircle" Property="Width" Value="60" />  
  7.         <Setter TargetName="InnerCircle" Property="Height" Value="60" />  
  8.         <Setter TargetName="OuterCircle" Property="Fill" Value="Gray" />  
  9.      </Trigger>  
  10. </ControlTemplate.Triggers>  
Listing 2

I also changed some code for the Fill property of Ellipses and filled them with gradient brushes as shown in Listing 3.
  1. <Ellipse Width="100" Height="100" Name="OuterCircle" >  
  2.     <Ellipse.Fill>  
  3.         <LinearGradientBrush StartPoint="0,0" EndPoint="0,0.5">  
  4.             <GradientStop Offset="0" Color="OrangeRed"  />  
  5.             <GradientStop Offset="1" Color="Orange" />  
  6.         </LinearGradientBrush>  
  7.     </Ellipse.Fill>  
  8. </Ellipse>  
  9. <Ellipse Width="80" Height="80" Name="InnerCircle">  
  10.     <Ellipse.Fill>  
  11.         <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">  
  12.             <GradientStop Offset="0" Color="White" />  
  13.             <GradientStop Offset="1" Color="OrangeRed" />  
  14.         </LinearGradientBrush>  
  15.     </Ellipse.Fill>  
  16. </Ellipse>  
Listing 3

The new button looks as in Figure 2. If you rollover the button, you will see the background of the inner circle is changed to Green and looks as in Figure 3.

see ok
        Figure 2

If you click on the button, you will see the background of outer circle changes to Gray and the width and height of the inner circle is reduced.

ok
            Figure 3

ItemsPanelTemplate

In the previous example, we saw how a Style element can be used within the resources to group multiple properties of elements and set them using the Style property of elements. However, Style functionality does not end here. Style can be used to group and share not only properties, but also resources and event handlers on any FrameworkElement or FrameworkContentElement.

Styles are resources and used as any other resource and can be applied to the current element, parent element, root element and even on the application level. The scope if styles are similar to any other resources. The resource lookup process first looks up for local styles and if not found, it traverses to the parent element in the logical tree and so on. In the end, the resource lookup process looks for styles in the application and themes.

The Style element in XAML represents a style. The typical definition of the Style element looks as in the following:
  1. <Style>  
  2.    Setters  
  3. </Style>  
As you can see from the definition of Style, a Style has one more Setter element. Each Setter consists of a property and a value. The property is the name of the property and the value is the actual value of that property of the element to that the style will be applied to.

Setters Property

The Setters property of Type represents a collection of Setter and EventSetter objects. Listing 4 uses the Setters property and adds a Setter and EventSetter object.

The code snippet in Listing 4 sets the Setters property of a Style by adding a few Setter elements and one EventSetter element using XAML at design-time.
  1. <Grid>  
  2.     <Grid.Resources>  
  3.         <Style TargetType="{x:Type Button}">  
  4.             <Setter Property="Width" Value="200"/>  
  5.             <Setter Property="Height" Value="30"/>  
  6.             <Setter Property="Foreground" Value="White"/>  
  7.             <Setter Property="Background" Value="DarkGreen"/>  
  8.             <Setter Property="BorderBrush" Value="Black"/>  
  9.               
  10.             <EventSetter Event="Click" Handler="Button1_Click"/>  
  11.         </Style>  
  12.     </Grid.Resources>  
  13.       
  14.     <Button>Click me</Button>  
  15. </Grid>  
Listing 4
 
Summary

In this article, we learned the basics of templates in WPF, their types and how to use them in Windows applications.