Silverlight MergedDictionaries – using styles and resources from Class Libraries
If you were developing larger Silverlight/WPF applications and trying to keep things like styles, control templates and other resources organized it can become really hard.
Prior to Silverlight 3 it was hell to be honest π
You had to scatter resources all around your application, on control level and put global ones in App.xaml and soon it would all grow beyond control.
But then nice people from Microsoft introduced lovely little feature called MergedDictionaries that allows you to combine the resources from different places in your application.
The beauty of this simple technique is that you can use resources from different files that can even reside in different Class Libraries in your project and just ‘reference’ them in the application level (App.xaml) and they will immediately become available to all the controls in your application.
Not to mention the moment of reuse: you can group your application resources into assemblies, for example one can hold the Styles, another can contain Control Templates, third can have text resources etc and then you can just reference them in any project and easily (re)use them.
So lets see how to actually accomplish this.
Luckily its very simple. We just need to add few lines to our App.xaml file:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ResourceDictionariesInLib.App"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="/ResourceDictionariesInLib.BasicStyles;component/StylesForShapes.xaml" /> <ResourceDictionary Source="/ResourceDictionariesInLib.FontStyles;component/StylesForFonts.xaml" /> <ResourceDictionary Source="LocalStyles/BasicStyles.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>
As you see here I’m using resources from two different Silverlight Class Libraries and one is from local subfolder called “LocalStyles”.
The format is clear, for resources in DLLs you use:
Source=”/AssemblyName;component/FileName.xaml”
The “component” part is just a keyword that tells the parser that resource is in referenced DLL.
One important catch here is if you are merging resources from DLLs than you need to actually add references to those Class Libraries that hold your resources so in this case i had to Add Reference to two DLLs: ResourceDictionariesInLib.BasicStyles.dll and ResourceDictionariesInLib.FontStyles.dll.
Format for the resource file in the application is self-explanatory.
In order to create a xaml file in some Class Library to hold resources just choose Add->New Item and then select SilverlightResourceDictionary from the list.
Also its important to state here that you can put MergedDictionaries at every level, meaning that you can put them to App.xaml and then those merged resources will be available to every element of your application, but also you can place MergedDictionaries in the CustomControl (in CustomControl.Resources) and then this resources will be available only to this control.
So lets see how those MergedDictionaries of resources can be used.
In the StylesForShapes.xaml file i have some background gradient brushes:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <LinearGradientBrush x:Key="EllipseFillBrush" EndPoint="1,0.5" StartPoint="0,0.5"> <GradientStop Color="Black" Offset="0" /> <GradientStop Color="#FFD41313" Offset="1" /> </LinearGradientBrush> <LinearGradientBrush x:Key="RectangleFillBrush" EndPoint="1,0.5" StartPoint="0,0.5"> <GradientStop Color="Black" Offset="0" /> <GradientStop Color="#FF3AD859" Offset="1" /> </LinearGradientBrush> </ResourceDictionary>
So since i referenced StylesForShapes.xaml file in MergedDictionaries in my App.xaml file i can use styles from that file in any Silverlight control in the whole application.
<Grid x:Name="LayoutRoot" Background="White" Height="348" Width="489"> <Ellipse Fill="{StaticResource EllipseFillBrush}" /> <Rectangle Fill="{StaticResource RectangleFillBrush}" /> </Grid>
You can do the same for any other property like FontSize or FontFamilly.
Just extract property value to a resource and then reuse it in your app.
Another very nice thing about MergedDictionaries is that they are supported by Visual Studio 2010 and Blend 3/4 so if you have DLLs with resources and you merge them in App.xaml then when you are extracting new resources you can specify those resource files in DLL’s as the place where that newly extracted resource will be created.
Here is the example:
In Visual Studio create UserControl and put an Ellipse element on it and set its Fill property to be some nice GradientBrush and then click on the black diamond symbol to the right of the Fill property and in the pop-up menu choose option Extract value to Resource:
After clicking on the Extract Value to Resource menu item you will need to choose where to save the newly created resource and you can here choose any of the resource xaml files in your Class Libraries like this:
So here is how a sample page that uses MergedDictionaries to set styles and fonts on its controls looks like:
And here is the Visual Studio 2010 demo solution.
Have fun! π
hi, nice post!
i’ve a question about based on styles.
if i use a style that is based on a base style (target type control), it only work if they’re both defined in the same resource dictionary.
but if i’ve many rsd, to use with themes, i’ve to define the same base style in all of them?
VS2010, throws an exception if not.
thanks
Hi Pablo,
interesting problem. Can you please create a small project showing this exception and send it to me on webmaster [at] roboblob dot com so i can take a look at it maybe i could figure it out.
Thanks for your feedback!
Great tutorial! thanks!