Templates in WPF are used to customize the UI. We can manipulate both controls as well as data.
Every control in WPF has its default template associated with it. Default template defines a look and feel, basically a style of control.
That's why by default, Button or TextBox shapes are ectangular because it is defined in its default template. Now we can update that template and add our own implementation.
In WPF there are 2 types of Templates,
- Control Template: Customize the appearance
- Data Template: Customize the functionality.
Note
We can define these templates inside App.xaml or in Resource file to reuse them in the application.
Control Template
So by default, this is how the Button looks.
- <Button x:Name="SubmitButton"
- Content="Submit"
- Height="20"
- Width="100"/>
Let's create a custom control to change the shape of this button.
Let's add a ControlTemplate inside a Button to achieve this. But you might get the following error.
As you can see .net framework is giving us compiled time error, specifying Visual tree can only be set once, meaning that ControlTemplate can only have
one child. But we have a couple of tags inside a ControlTemplate.
- <Button x:Name="SubmitButton"
- Content="Submit"
- Height="20"
- Width="100">
- <Button.Template>
- <ControlTemplate>
- <Ellipse Fill="Gray"/>
- <ContentPresenter/>
- </ControlTemplate>
- </Button.Template>
- </Button>
So to overcome this problem, we can add Panel inside ControlTemplate and add any number of tags inside that grid, because grid can have multiple children.
- <Window x:Class="A.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:A"
- mc:Ignorable="d"
- Title="MainWindow" Height="150" Width="300">
- <Grid x:Name="MainGrid">
- <Button x:Name="SubmitButton"
- Foreground="White"
- Height="20"
- Width="100">
- <Button.Template>
- <ControlTemplate x:Name="ButtonElipse">
- <Grid>
- <Ellipse Fill="Gray"/>
- <ContentPresenter
- Content="Submit"
- VerticalAlignment="Center"
- HorizontalAlignment="Center"/>
- </Grid>
- </ControlTemplate>
- </Button.Template>
- </Button>
- </Grid>
- </Window>
As you can see, new ControlTemplate has been assigned to a Button.
Now let's load our ControlTemplate in ResourceDictionary and fetch it from there.
ResourceDictionaryTemplate.xaml
- <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:local="clr-namespace:A">
- <Thickness x:Key="MarginTR">0 5 5 0</Thickness>
- <ControlTemplate x:Key="EllipseButton">
- <Grid>
- <Ellipse Fill="Gray"/>
- <ContentPresenter
- Content="Submit"
- VerticalAlignment="Center"
- HorizontalAlignment="Center"/>
- </Grid>
- </ControlTemplate>
- </ResourceDictionary>
MainWindow.xaml
First, you need to add Window.Resources.
Second use Tag Template to bind the EllipseButton ControlTemplate.
- <Window x:Class="A.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:A"
- mc:Ignorable="d"
- Title="MainWindow" Height="150" Width="300">
- <Window.Resources>
- <ResourceDictionary Source="ResourceDictionaryTemplate.xaml"/>
- </Window.Resources>
- <Grid x:Name="MainGrid">
- <Button x:Name="SubmitButton"
- Foreground="White"
- Template="{StaticResource EllipseButton}"
- Height="20"
- Width="100"/>
- </Grid>
- </Window>
ContentPresenter
Let's display employee information in UI.
For this we are going to need employee class: Employee.cs
- public class Employee
- {
- public int EmpId { get; set; }
- public string EmpName { get; set; }
- public string Designation { get; set; }
- }
MainWindowViewModel: As I am using MVVM, I am updating ViewModel.
But you can do the same in the code behind.
- using A.Entities;
- using Prism.Mvvm;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
-
- namespace A
- {
- class MainWindowViewModel : BindableBase
- {
- #region Properties
- private Employee _empDetails;
-
- public Employee EmpDetails
- {
- get { return _empDetails; }
- set { _empDetails = value; }
- }
-
- #endregion
-
- #region Constructor
- public MainWindowViewModel()
- {
- EmpDetails = new Employee()
- {
- EmpId = 1,
- EmpName = "Rikam",
- Designation = "Software Eng."
- };
- }
- #endregion
- }
- }
Finally, MainWindow.xaml:
- <Window x:Class="A.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:A"
- mc:Ignorable="d"
- Title="MainWindow" Height="150" Width="300">
- <Window.Resources>
- <ResourceDictionary>
- <ResourceDictionary.MergedDictionaries>
- <ResourceDictionary Source="ResourceDictionaryTemplate.xaml"/>
- </ResourceDictionary.MergedDictionaries>
- </ResourceDictionary>
- </Window.Resources>
- <Grid x:Name="MainGrid">
- <ContentPresenter x:Name="EmployeeDetails" Content="{Binding EmpDetails}">
- <ContentPresenter.ContentTemplate>
- <DataTemplate>
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="Auto"/>
- </Grid.RowDefinitions>
- <Grid.ColumnDefinitions>
- <ColumnDefinition/>
- <ColumnDefinition/>
- </Grid.ColumnDefinitions>
- <Label Content="Employee Id:"/>
- <Label Content="{Binding EmpId}"
- Grid.Column="1"/>
- <Label Content="Employee Name:"
- Grid.Row="1"/>
- <Label Content="{Binding EmpName}"
- Grid.Row="1"
- Grid.Column="1"/>
- <Label Content="Employee Designation:"
- Grid.Row="2"/>
- <Label Content="{Binding Designation}"
- Grid.Column="1"
- Grid.Row="2"/>
- </Grid>
- </DataTemplate>
- </ContentPresenter.ContentTemplate>
- </ContentPresenter>
- <Button x:Name="SubmitButton"
- Template="{StaticResource EllipseButton}"
- VerticalAlignment="Bottom"
- Margin="0 0 0 10"
- Foreground="White"
- Height="20"
- Width="100"/>
- </Grid>
- </Window>
We need to use ContentPresenter when we want to use DataTemplate.
Then you must specify its content, and the source from where our inner control is supposed to fetch its data.
Then bind each property as you wish.
I hope this article has helped you to understand Templates in WPF.
If you have in further queries, you can connect with me @