I have lately been working on a somewhat larger Silverlight application for a client here in New Zealand. The application is being built using PRISM, which means that it is loaded in a composite/ modular way. And with this modular/composite loading, being able to share resources between different modules becomes pretty interesting as it makes it easier to get all modules to share the same look and feel. So this got me to rehash a topic I have already talked about before, merged dictionaries.
This is obviously not a PRISM only thing to do, but it often becomes a little more sought after when the application starts getting spread out over several different projects… Luckily, it is very easy to share resources between projects in Silverlight.
The first thing to do is to create a class library project in Visual Studio, which will create an almost empty project for you. All you have to do to make it completely empty is to delete the Class1.cs file.
After you have created a completely empty project, it is time time to create some resources. This is easiest to do by adding a new item to the project, and selecting the “Silverlight Resource Dictionary” item. This will create a new XAML file with a ResourceDictionary as the root element.
I’m working with VS2010 and Silverlight 4. In earlier versions, I believe the “Silverlight Resource Dictionary” item was missing, and we had to create our own, which isn’t terribly hard, but still annoying. Just create a new XML file and add the following XML to it
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</ResourceDictionary>
The above is exactly the same XAML that gets create for us automatically when adding a new “Silverlight Resource Dictionary”.
If you look at the build action for the new XAML file, you will notice that it is set up to be built as a “Page”. This makes it fairly easy to reference it from XAML, and thus fairly easy to add it as a “merged dictionary” to your pages or application.
There are 2 interesting things to mention about this. The first one is the idea of a “merged dictionary”. All resource dictionaries in Silverlight has a property called “MergedDictionaries”. You normally don’t see it as you generally use a shorthand syntax for adding resources to the dictionaries as follows
<UserControlx:Class="ExternalResourceConsumer.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">
<UserControl.Resources>
<ControlTemplatex:Key="MyButtonTemplate">
<GridBackground="Goldenrod">
<ContentPresenterMargin="10"/>
</Grid>
</ControlTemplate>
</UserControl.Resources>
<Gridx:Name="LayoutRoot"Background="White">
<ButtonTemplate="{StaticResource MyButtonTemplate}"Content="Hello World"/>
</Grid>
</UserControl>
But if you extend that syntax and specifically write out the ResourceDictionary element, you will see that you get access to the MergedDictionaries property as follows
<UserControlx:Class="ExternalResourceConsumer.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">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary ... />
</ResourceDictionary.MergedDictionaries>
<ControlTemplatex:Key="MyButtonTemplate">
<GridBackground="Goldenrod">
<ContentPresenterMargin="10"/>
</Grid>
</ControlTemplate>
</ResourceDictionary>
</UserControl.Resources>
<Gridx:Name="LayoutRoot"Background="White">
<ButtonTemplate="{StaticResource MyButtonTemplate}"Content="Hello World"/>
</Grid>
</UserControl>
By adding additional ResourceDictionary elements to the MergedDictionaries, we can merge resources from several resource dictionaries into one. The ResourceDictionary element contains only one interesting attribute, Source. The Source attribute expects a Uri to another resource dictionary. And if the other resource dictionary is in the same project, this Uri can simply be “MyResourceFolder/MyResource.xaml” or whatever location you have placed the resource file in.
But when we have a resource that is in a separate assembly, we get into the second interesting thing I talked about before. Because this requires us to do 2 things to get it to work. First of all, we obviously need to add a reference to the assembly that contains the resource dictionary. Otherwise we can obviously not reference it. Next, we need to use a special Uri when setting the Source. The Uri format is “/{assembly name};component/{path to resource}”.
So if we move the beautiful MyButtonTemplate to an external resource dictionary called MyResource.xaml and is located in an assembly called ExternalResourceDemo the XAML looks like this
<UserControlx:Class="ExternalResourceConsumer.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">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionarySource="/ExternalResourceDemo;component/MyResource.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Gridx:Name="LayoutRoot"Background="White">
<ButtonTemplate="{StaticResource MyButtonTemplate}"Content="Hello World"/>
</Grid>
</UserControl>
That’s all there is to it. This makes it very easy to place all of our common resources (styles, templates, colors, fonts etc) in external libraries that can then just be referenced to give you access to them. This makes it a lot simpler to get a consistent look and feel across multiple applications or modules.
And you can obviously, especially obvious if you look at the name of the property name, add as many merged dictionaries as you want. Just add more ResourceDictionary elements.
Merged dictionaries work well with default styles as well. Just give your style a target type and skip the x:Key and you are good to go as along as it is set as a MergedDictionary. A good idea is also to merge the external dictionaries in the App.xaml resources when possible, as it causes less overhead and duplication of information.
And even though there is very little code to even look at, I have made a solution available for down load here: ExternalResourceDemo.zip (42.46 kb)
Cheers!