WPF Styles and Templates
Styles
WPF Style is a way to group similar properties in a single Style object and apply to multiple objects in WPF. Style is very useful when you want to use a single unified style for all UI elements. Styles also come handy when you want to implement dymanic styles in WPF and allow users of the app to customize styles of UI elements.
Let's have a look at the XAML code in Listing 1 that generates Figure 1. This code creates a Window with three Buttons, a TextBlock and a TextBox.
<Window x:Class="StylesSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="291" Width="455">
<Grid Height="236" Width="405">
<TextBlock Margin="12,52,26,83" Name="textBlock1"
Background="Gray" Foreground="Orange"
FontFamily="Georgia" FontSize="12"
Width="370" Height="100" />
<TextBox Height="30" Margin="11,16,155,0" Name="textBox1" VerticalAlignment="Top" />
<Button HorizontalAlignment="Right" Margin="0,14,26,0"
Name="button1" VerticalAlignment="Top"
Height="30" Width="120"
FontFamily="Verdana" FontSize="14" FontWeight="Normal"
Foreground="White" Background="DarkGreen"
BorderBrush="Black" >
Browse
</Button>
<Button HorizontalAlignment="Right" Margin="0,0,30,39" Name="button2"
VerticalAlignment="Bottom"
Height="30" Width="120"
FontFamily="Verdana" FontSize="14" FontWeight="Normal"
Foreground="White" Background="DarkGreen"
BorderBrush="Black" >
Spell Check
</Button>
<Button Margin="129,0,156,39" Name="button3" VerticalAlignment="Bottom"
Height="30" FontFamily="Verdana" FontSize="14" FontWeight="Normal"
Foreground="White" Background="DarkGreen"
BorderBrush="Black" >
Save File
</Button>
</Grid>
</Window>
Listing 1
As you can see from Figure 1, all three buttons have the same width, height, background, foreground and fonts and each Button element has the same code.
Figure 1
Here is the Button element code that sets the Height, Width, Foreground, Background and Font properties.
<Button HorizontalAlignment="Right" Margin="0,14,26,0"
Name="button1" VerticalAlignment="Top"
Height="30" Width="120"
FontFamily="Verdana" FontSize="14" FontWeight="Normal"
Foreground="White" Background="DarkGreen"
BorderBrush="Black" >
Browse
</Button>
All of the three buttons have same property values.
Now, imagine you have a large application with many windows and pages and they have many buttons with the same size and look. That means you will copy the same code again and again. Now what if a user wants to change the background color of all the Button elements in the application from Green to Red? That means, we will need to change the Background property of all Button elements in the application.
This duplicate work can be avoided using styles. You can group properties in a Style and set that style for all Button elements. The next time, if you want to change any property, just simply change that property value in the style and you are all set.
The Style element in XAML represents a style. A Style is usually added to the resources of a FrameworkElement. The x:Key is the unique key identifier of the style.
The code snippet in Listing 2 adds a Style to Window Resources and within the Style we use a setter to set the property type and values and we set the Width, Height, Background, Foreground and other properties.
<Window.Resources>
<!-- Green Button Style -->
<Style x:Key="GreenButtonStyle" >
<Setter Property="Button.Width" Value="120"/>
<Setter Property="Button.Height" Value="30"/>
<Setter Property="Button.FontFamily" Value="Verdana"/>
<Setter Property="Button.FontSize" Value="14"/>
<Setter Property="Button.FontWeight" Value="Normal"/>
<Setter Property="Button.Foreground" Value="White"/>
<Setter Property="Button.Background" Value="DarkGreen"/>
<Setter Property="Button.BorderBrush" Value="Black"/>
</Style>
</Window.Resources>
Listing 2
Once a Style is added to the resource dictionary, you can use it by using the Style property of a FrameworkElement. The code snippet in Listing 3 sets the Style of a Button using the StaticResource Markup Extension.
<Button HorizontalAlignment="Right" Margin="0,14,26,0"
Name="button1" VerticalAlignment="Top"
Style="{StaticResource GreenButtonStyle}" >
Browse
</Button>
Listing 3
Style
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 are used as any other resource and can be applied to the current element, parent element, root element and even on application level. The scope of styles are similar to any other resources. The resource lookup process first looks at 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 a Style element looks as in following,
<Style>
Setters
</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.
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Width" Value="200"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="DarkGreen"/>
<Setter Property="BorderBrush" Value="Black"/>
<EventSetter Event="Click" Handler="Button1_Click"/>
</Style>
</Grid.Resources>
<Button>Click me</Button>
</Grid>
Listing 4
BasedOn Property
Styles support inheritance. That means we can create styles based on existing styles. When you inherit a style from an existing style, the settings from a parent style are available in the inherited style. To inherit a style from another style, we set the BasedOn property to StaticResource Markup Extension as the style it is being inherited from.
The code snippet in Listing 5 creates a Style BackForeColorStyle that sets the Background and Foreground properties of the control. Then we create a FontStyle style that sets the font properties but is inherited from the BackForeColorStyle. The last style ButtonAllStyle is inherited from FontStyle. In the end, we set the Style of the button.
<Grid Name="RootLayout">
<Grid.Resources>
<Style x:Key="BackForeColorStyle">
<Setter Property="Control.Background" Value="Green"/>
<Setter Property="Control.Foreground" Value="White"/>
</Style>
<Style x:Key="FontStyle" BasedOn="{StaticResource BackForeColorStyle}">
<Setter Property="Control.FontFamily" Value="Verdana"/>
<Setter Property="Control.FontSize" Value="14"/>
<Setter Property="Control.FontWeight" Value="Normal"/>
</Style>
<Style x:Key="ButtonAllStyle" BasedOn="{StaticResource FontStyle}">
<Setter Property="Button.Width" Value="120"/>
<Setter Property="Button.Height" Value="30"/>
</Style>
</Grid.Resources>
<Button Name="Button1" Style="{StaticResource ButtonAllStyle}" >
Click me
</Button>
</Grid>
Listing 4
The code snippet in Listing 5 generates Figure 2 that shows that the button properties have been set from all of the three styles.
Figure 2
TargetType Property
The TargetType property can be used to get and set the type for which a style is intended. If the TargetType property of a Style is set and you assign a style to the element that is not the type set in TargetType, you will get an error.
If the TargetType property is not set, you must set the x:Key property of a Style.
Let's take a quick look at the code listed in Listing 5. This code creates a Style named GreenButtonStyle and sets a bunch of Button properties.
<Grid>
<Grid.Resources>
<!-- Green Button Style -->
<Style x:Key="GreenButtonStyle" >
<Setter Property="Button.Width" Value="120"/>
<Setter Property="Button.Height" Value="30"/>
<Setter Property="Button.FontFamily" Value="Verdana"/>
<Setter Property="Button.FontSize" Value="14"/>
<Setter Property="Button.FontWeight" Value="Normal"/>
<Setter Property="Button.Foreground" Value="White"/>
<Setter Property="Button.Background" Value="DarkGreen"/>
<Setter Property="Button.BorderBrush" Value="Black"/>
</Style>
</Grid.Resources>
<Button HorizontalAlignment="Right" Margin="0,14,26,0"
Name="button1" VerticalAlignment="Top"
Style="{StaticResource GreenButtonStyle}" >
Browse
</Button>
</Grid>
Listing 5
Now we can simply replace the Style code in Listing 5 with Listing 6 where you may see that we have set the TargetType = “Button” but have removed Button in front of the properties. By setting TargetType fixes that this style can be applied to a Button element only.
<!-- Green Button Style -->
<Style x:Key="GreenButtonStyle" TargetType="Button" >
<Setter Property="Width" Value="120"/>
<Setter Property="Height" Value="30"/>
<Setter Property="FontFamily" Value="Verdana"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="DarkGreen"/>
<Setter Property="BorderBrush" Value="Black"/>
</Style>
Listing 6
Triggers Property
Styles can use triggers within them. The Triggers property of Style represents the triggers applicable on a Style. For example, the following code snippet adds a Trigger for a button when the Button is in a pressed state; it will change the Foreground color of the button to Orange.
<Style.Triggers>
<Trigger Property="IsPressed" Value="true">
<Setter Property = "Foreground" Value="Orange"/>
</Trigger>
</Style.Triggers>
Listing 6 shows the complete code of implementing triggers within a style.
<Grid>
<Grid.Resources>
<!-- Green Button Style -->
<Style x:Key="GreenButtonStyle" TargetType="Button" >
<Setter Property="Width" Value="120"/>
<Setter Property="Height" Value="30"/>
<Setter Property="FontFamily" Value="Verdana"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="DarkGreen"/>
<Setter Property="BorderBrush" Value="Black"/>
<Style.Triggers>
<Trigger Property="IsPressed" Value="true">
<Setter Property = "Foreground" Value="Orange"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Button HorizontalAlignment="Right" Margin="0,14,26,0"
Name="button1" VerticalAlignment="Top"
Style="{StaticResource GreenButtonStyle}" >
Browse
</Button>
</Grid>
Listing 7