Introduction
The resource dictionary is a simple way to simplify the coding of WPF views, but the syntax can be less than obvious. In this short tip, I present a brief description of the following:
- Defining constants within a resource dictionary within a view.
- Defining styles within a resource dictionary within a view.
- Using items in a resource dictionary in a separate file in the same assembly.
- Using items located in a resource dictionary in a separate assembly.
It is assumed that you have a basic understanding of WPF, including styles.
Background
The new WPF view designer soon learns that she wants to create controls that have the same look and feel, and that entering the same text time and time again is tedious. The solution of course is to use a resource dictionary, whereby common values such as the width of a button or the style for a group box are stored in a common area, and referenced by multiple controls.
This has the advantage that development is quicker as styles can be reused, the application has a more consistent look and feel as similar controls use the same style, and the application styles are easily modified as they are defined in a common location.
Defining A Constant
The following example defines a constant in a view's resource dictionary:
<Window x:Class="WpfResourceDictionaryDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib"
Background="#DCE8F3"
Title="Resource Dictionary Demo Application"
Height="350"
Width="600">
<Window.Resources>
<ResourceDictionary>
<System:Double x:Key="ButtonWidth">80</System:Double>
</ResourceDictionary>
</Window.Resources>
<Grid Margin="10">//
The constant is called 'ButtonWidth
', it is a double
, and it has the value 80
.
Using the constant is quite simple:
<Button Grid.Row="6" Grid.Column="0" Content="Press Me"
Width="{StaticResource ButtonWidth}" HorizontalAlignment="Left"/>
Thus, the width of the control has been set equal to the value defined by 'ButtonWidth
'. Note that the Double
type is defined in the System namespace
which references the mscorlib
component.
Defining A Style
The following example defines a style in a view's resource dictionary:
<Window x:Class="WpfResourceDictionaryDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib"
Background="#DCE8F3"
Title="Resource Dictionary Demo Application"
Height="350"
Width="600">
<Window.Resources>
<ResourceDictionary>
<System:Double x:Key="ButtonWidth">80</System:Double>
<Style x:Key="groupBoxStyle" TargetType="GroupBox">
<Setter Property="Margin" Value="3"/>
<Setter Property="Padding" Value="5,5,5,5"/>
<Setter Property="Background"
Value="{StaticResource ResourceKey=backgroundBrush}"/>
<Setter Property="BorderBrush" Value="Black"/>
</Style>
</ResourceDictionary>
</Window.Resources>
The style called 'groupBoxStyle
' can be applied to a group box as follows:
<GroupBox Header="Styles Example One" Style="{StaticResource groupBoxStyle}">
<Label>Styles defined in the window XAML</Label>
</GroupBox>
The style is easily modified as follows:
<GroupBox Grid.Row="8" Grid.Column="0"
Name="_borderBottom" Header="Override a resource dictionary style">
<GroupBox.Style>
<Style TargetType="GroupBox" BasedOn="{StaticResource groupBoxStyle}">
<Style.Triggers>
<DataTrigger Binding="
{Binding ElementName=_checkBoxYellowBackground, Path=IsChecked}"
Value="true">
<Setter Property="Background" Value="LightYellow" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=_checkBoxYellowBackground,
Path=IsChecked}" Value="false">
<Setter Property="Background" Value="LightCoral" />
</DataTrigger>
</Style.Triggers>
</Style>
</GroupBox.Style>
<CheckBox Grid.Row="8" Grid.Column="0"
x:Name="_checkBoxYellowBackground" Content="Yellow Background"/>
</GroupBox>
Thus, the group box style element overrides the 'canned' style and sets the background colour according to the check state of a check box.
Creating A Resource Dictionary File
Clearly a view's resource dictionary is very useful, but what if we want multiple views to have the same resources? The answer is to add a resource dictionary to the project. This is no more than a file with one element called ResourceDictionary
. Here is a simple example:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Brush x:Key="backgroundBrush">#DCE8F3</Brush>
<Style x:Key="groupBoxStyleRedBorder" TargetType="GroupBox">
<Setter Property="Margin" Value="3"/>
<Setter Property="Padding" Value="5,5,5,5"/>
<Setter Property="Background" Value="PaleVioletRed"/>
<Setter Property="BorderBrush" Value="Blue"/>
<Setter Property="BorderThickness" Value="1"/>
</Style>
<Style x:Key="borderRedNoLine" TargetType="Border">
<Setter Property="Background" Value="PaleVioletRed"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
</ResourceDictionary>
Thus, the dictionary defines a brush constant, and two styles.
In order to use the resource dictionary items in our view, we must modify the Window.Resources
element as follows:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
<System:Double x:Key="ButtonWidth">80</System:Double>
</ResourceDictionary>
</Window.Resources>
Now we can use the items in the external resource dictionary as if they were defined in the view. For example:
<Border Grid.Row="2" Grid.Column="0"
Style="{StaticResource borderRedNoLine}">
<GroupBox Header="Styles Example Two"
Style="{StaticResource groupBoxStyleRedBorder}">
<Label>Styles defined in a dictionary in the application assembly</Label>
</GroupBox>
</Border>
Using A Resource Dictionary In A Separate Assembly
What if we have multiple applications which want to share the same styles? The answer is simple, we allow them to access a resource dictionary in a shared assembly, typically a class library.
Let's assume that we have created a separate class library called WpfExternalDictionary.dll containing a resource dictionary in a file called ResourceDictionary.xaml located in a folder called View. We add a reference to the file in the Window.Resources
element as follows:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceDictionary.xaml"/>
<ResourceDictionary Source="pack:
//application:,,,/WpfExternalDictionary;component/View/ResourceDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<System:Double x:Key="ButtonWidth">80</System:Double>
</ResourceDictionary>
</Window.Resources>
The items in the resource dictionary may now be used as if they were defined in the view XAML.
Example Application and Class Library
I have created a simple demonstration application and a separate class library, which illustrate the concepts described above. The link is of course at the start of this article.
History
- 14th September, 2017: First version