This article has a corresponding video that can be viewed here.
Resource Dictionaries are a powerful feature in WPF and Silverlight that enable developers to organize and consume reusable resources.
After completing this walk through you'll understand how to create and merge resource dictionaries in WPF and Silverlight; how to add, consume and modify resources in the dictionary using the tools provided by the WPF and Silverlight Designer in Visual Studio 2010.
Before diving into resource dictionaries let's first understand what the term "resource" means when used in the context of a resource dictionary or in a resources section of an object in XAML.
A resource is an object declared in XAML. In the below XAML we see examples of typical resources; my: is an alias for the System namespace in mscorlib.
<UserControl.Resources> <LinearGradientBrush x:Key="formBackground" EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="Blue" Offset="0" /> <GradientStop Color="#460000FF" Offset="1" /> </LinearGradientBrush> <my:String x:Key="applicationTitle">Resource Dictionary Demo</my:String> <my:Double x:Key="applicationTitleFontSize">18</my:Double> <SolidColorBrush x:Key="applicationTitleForeground">Yellow</SolidColorBrush> </UserControl.Resources>
One reason to use resources in your applications is to promote object reuse across your application. Object reuse provides consistency across the application. Object reuse also makes it very easy to change the application; since you only need to change the resources and all consumers will pick up the change.
The below XAML consumes the above resources.
<Grid x:Name="LayoutRoot" Background="{StaticResource formBackground}"> <TextBlock Text="{StaticResource applicationTitle}" Foreground="{StaticResource applicationTitleForeground}" FontSize="{StaticResource applicationTitleFontSize}" VerticalAlignment="Top"/> </Grid>
Resources are located in resource dictionaries.
What I have referred to as a resources section is actually the Resources property (WPF Silverlight) which is of type ResourceDictionary. When you add resources to the Resources property, you are actually adding them to a ResourceDictionary exposed by the object.
The Resources property is defined on FrameworkElement and is inherited from any object that has FrameworkElement in its inheritance hierarchy. This means that resources can be located on Windows, UserControls, Grids, Buttons, TextBoxes, ListBoxes, etc.
In addition to an objects Resources property, resources can also be located in a ResourceDictionary XAML file.
Create a new WPF or Silverlight project and add the following XAML.
<Grid x:Name="LayoutRoot"> <Grid.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="Blue" Offset="0" /> <GradientStop Color="#460000FF" Offset="1" /> </LinearGradientBrush> </Grid.Background> <TextBlock Text="Resource Dictionary Demo" Foreground="Yellow" FontSize="18" VerticalAlignment="Top"/> </Grid>
We will now use the "Extract Value to Resource…" feature of the Designer. To exact a property value to a resource, click on the Property Marker, this will open the below Context Menu. Now select, "Extract Value to Resource…"
When the Create Resource dialog opens, change the Key to "formBackground," leave the Destination value to whatever it defaulted to and click OK.
Notice that I have chosen to name the resource by its role, as opposed to what it looks like. Adopting this Key naming convention allows a resource to be changed without causing a conflict with the Key name. For example, if the Key name was BlueGradient and I assigned it to each forms Background property, then later wanted to change it to a green gradient, the name would still be BlueGradient but the color was now green. By naming the Key formBackground, I've not associated any color or type of brush with the name.
In the below image we can see what the Designer tool did for us.
To help us quickly locate the TextBlock properties that have been set, we will now use a very cool feature of the Designer's Properties Window, "Sort by property source."
After extracting the above properties to resources, your XAML will look like the below image.
The required root Grid and application title TextBlock properties are now set for reuse.
Notice the yellow highlighted line of XAML. This alias was added by the Designer tool. When the Designer tool adds an alias, it names the first one, "my" the next alias, "my1", etc. For very small forms with a single alias this may be acceptable. However for most projects you'll want to use meaningful names for your aliases.
You have several options open to you to change these. First, if you define the alias in the XAML file before extracting to a resource, the Designer tool will reuse the alias when referencing the same namespace and assembly. You could also edit the XAML after the Designer tool creates it. After you have worked with WPF or Silverlight for a short time, you'll get an understanding of the aliases you use and can just add them to your new XAML files before you start adding other content to the XAML file.
The below image is the anatomy of a simple WPF or Silverlight application that is composed of hierarchy of objects nested within each other.
Note
Silverlight does not have system scoped resources like WPF does.
When we say resources are scoped, we mean that resources can be defined at various levels of the application hierarchy. Resources defined at a certain scope are available to all elements in or below that scope.
For example, we previously extracted property values to the UserControl scope and the child Grid and TextBlock could access those resources.
Now, what if we wanted to consume those same resources we extracted earlier in another UserControl; how could we accomplish this?
To make the resources available, to other UserControls or Windows in the application, we need to move the resources to the Application scope.
When moving resources to Application scope, you have several options available to you:
For purposes of demonstration, I've cut the UserControl Resources and pasted them into the Application Resources section. Noticed I also cut and pasted the alias "my:" too.
You can also remove the UserControl.Resource from the UserControl's XAML as I have done the Demo.xaml image below.
You'll need to rebuild the application to remove the squiggles from your UserControl's XAML. The UserControl looks exactly as it did, but is now resolving its resources from the Application scope instead of the UserControl scope. We have just enabled reuse of these resources throughout the application. You can also see how Demo.xaml is smaller in size and looks cleaner now that we have moved the resources out of the local XAML file.
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ResourceDictionaryDemo.App" xmlns:my="clr-namespace:System;assembly=mscorlib"> <Application.Resources> <LinearGradientBrush x:Key="formBackground" EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="Blue" Offset="0" /> <GradientStop Color="#460000FF" Offset="1" /> </LinearGradientBrush> <my:String x:Key="applicationTitle">Resource Dictionary Demo</my:String> <my:Double x:Key="applicationTitleFontSize">18</my:Double> <SolidColorBrush x:Key="applicationTitleForeground">Yellow</SolidColorBrush> </Application.Resources> </Application>
<UserControl x:Class="ResourceDictionaryDemo.MainPage" 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" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400" xmlns:my="clr-namespace:System;assembly=mscorlib"> <Grid x:Name="LayoutRoot" Background="{StaticResource formBackground}"> <TextBlock Text="{StaticResource applicationTitle}" Foreground="{StaticResource applicationTitleForeground}" FontSize="{StaticResource applicationTitleFontSize}" VerticalAlignment="Top"/> </Grid> </UserControl>
If your application only requires a few resources, locating them in the Application.xaml or App.xaml would be fine.
However, in most applications the number of resources grows quickly and must be managed early in the application lifecycle.
Resource dictionaries are used to group related resources, then those resource dictionaries are then merged at the Application or other required scope.
What we will do now is:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="UsingResourceDictionaries.App"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Assets/FormDictionary.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>
Tip
In the next step we will be extracting Double and String values to a resource. The Designer tool will add the "my" alias for the System namespace in mscorlib if an alias has not been added.
To make your applications more readable and easier to maintain over time, you can proactively add meaningful aliases before they needed by the Designer as I have done in the yellow highlighted XAML below.
The next logical step from here is to learn how to combine individual resources values into a Style and then apply a single Style to a control.
This MSDN topic, WPF Styling and Templating provides a good starting point for understanding Styles.
MSDN topic WPF Resources Overview
MSDN topic Silverlight Resource Dictionaries
Microsoft values your opinion about our products and documentation. In addition to your general feedback it is very helpful to understand:
Thank you for your feedback and have a great day,
Karl Shifflett Expression Team
Hi,
Thank you for article.
Do you have some advice (recommendation) about using resource dictionary in a complex solution ex: Silverlight Business Application + one or more WCF RIA Service Class Library.
Right now, I am not be able to see - at design tine - resources (added in App.xaml : <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> ...) in Silverlight project of WCF RIA Class Library.
Thank you
Radu Lodina
Radu,
I was able to see the resources located in another project in the solution by following these steps:
1. Installed the latest SL Tools for VS from here:
2. Create a new SL Business Application
3. Added a new SL Class Library to the solution
4. Added a Resource Dictionary
5. Added a SolidColorBrush resource
6. In the main SL project, added a reference to the SL Class Library project
7. In App.xaml inside the <ResourceDictionary.MergedDictionaries> section I added
<ResourceDictionary Source="SilverlightClassLibrary1;component/Dictionary1.xaml" />
8. Open MainPage.xaml in the Designer. Select any control, using the properties window, find a brush property, then click on the property marker. The resource was visible for me.
If you can't get this to work in your project, please send me a link to the project so I can download it and have a look at it.
Have a nice day,
Karl Shifflett
Thank you for response.
My problem is:
How can I can see in my SL Class Library project (at design-time) resource defined in my main project (SL Business Application (App.xaml)) - all projects is in the same solution.
At run-time: resource defined on application level (App.xaml) it's available to all controls instantiated from my SL Class Library.
In my scenario (my VS solution contain):
1. SL Business Application - it's a container (provide common framework functionality to my app : logging, user notification, etc. and more important for this discution: simple theme selection - dynamically add/remove entry from Application.Current.Resources.MergedDictionaries.).
2. One or more WCF RIA Service Class Library - to keep things simple - one or more SL Class Library. Each of this library contain well defined task (there are my module (ex: Accounting, Warehouse, PR)) witch I load dynamically - based of user request. A functional app (SL4) can be found at demo.indecosoft.net user:demo, pass: demo
Now - in your above steps :
A. In step 4: Added a Resource Dictionary - add this resource dictionary in SL Business Application (your main SL project).
B. Change step 7 - to: <ResourceDictionary Source="Dictionary1.xaml" />
C. In SL Class Library project add a simple user control.
D. Apply SolidColorBrush resource defined on step A to user control defined in step C.
I'm sorry, but I don't understand what problem you are having. I can see and apply resources merged in App.xaml, from any project within my solution using the Designer's Apply Resource dialog.
Do you have the Visual Studio 2010 RTM?
Do you have the lastest Silverlight 4 Tools for Visul Studio installed? New version on 5/13/2010. www.microsoft.com/.../details.aspx
Do you have your resource dictionaries merged in App.xaml? In order for the Designer to "see" your resources, they MUST be merged in App.xaml or merged in the Page or UserControl that is consuming them.
Please let me know so I can try and help you, thank you,
This is the best post I ever seen about how to manage resources in WPF, and more than anything, it works like a charm!
Thanks a lot
Thank you for you kind remarks on Visual Studio and this post.
Have a great day,
Karl
Hi Karl,
Great post. Going through the steps I have a better feeling for how the resource dictionaries work. I'm looking at the 3 new Themes recently released that when opened in Blend as a project can be used to create a custom Theme. I like the organization and though its a bit overwhelming at first.. Forgive me for asking a possibly stupid question here, but what is the process to get from creating a new theme based on one of these 3 to using it in an application? I'm confused about which files to add to the application I want to apply the theme to and how to implicitly apply it to a large application.
Might you have a suggestion to complete that process? I'm having a difficult time finding this information.
Regards,
Bob
Bob,
Thank you for your kind words.
Want to be sure I understand your requirements.
You have an existing application, and you would like to be able to use one of the new themes, is that correct? You are looking for some guidance on how to plug the new theme into your application, correct?
Cheers,
Great article. I'm looking forward to building my first WPF app and this article has helped me understand more about using resources. Thanks.