After having worked a while with Silverlight you realize that you often keep a lot of things in resources in your Xaml. Not only do you add Storyboards for your animations, but you often also add styles and templates, and some converters and so on. The resources all of the sudden start taking up most if the rows in your Xaml. It becomes hard to read. Especially since Silverlight is all about styling and templating controls, which results in large amounts of Xaml.
It is also hard to share resources. Say that you have these converters that you use in several of your controls. How do you solve that? Having them declared in multiple places is no good.
In Silverlight 2 there wasn’t much you could do. You would just have to have all of those resources in your Xaml, and if you wanted to share them, they had to be in the App.xaml file.
In Silverlight 3 they have introduced support for what is called MergedDictionaries. I know that that is old school for WPF developers and that WPF supports a wide variety of dictionaries and so on. But now I’m talking about Silverlight, and in Silverlight MergedDictionaries are new for version 3. So what do they offer?
Well, they make it possible for you to store resources in external files. These files are then either embedded in the application as Content or as Resources. This means that we can spread out or resources in several files and just reference them in our controls, or possibly in our applications resources. This makes our Xaml files shorter and easier to read. We only declare our resources in one place and can reuse them in a good way. We can even store them in external assemblies and reuse them across several projects.
Are there any downsides? Well, there probably is. I saw somewhere that there might be performance issues when using it extensively. I have not looked into this at all. According to that blog post, Silverlight would create duplicate resource objects when they were merged. This might be true, but even if it is, I still think that the pros outweighs the cons.
So, how do we do it? I have just finished a project where I used MergedDictionaries quite a bit to make my Xaml files shorter. The Xaml becomes really extensive when you style the ListBox, which I had to do. So I took my ListBox style and placed it in a separate dictionary, creating two readable Xaml files instead of one unreadable. I did however struggle to get it working initially. This is the reason for my post…
There is poor support for this feature in the tools today. I guess that is understandable considering that it is a beta. But it is coming out soon and WPF already has the feature, so you would have hoped that it was a little more stable. Visual Studio 2008 also often complains about the merged resources even if they work. The preview pane of Visual Studoi tends to die. Adding a character and then resaving the Xaml tends to wake it up again though. Unless you have a problem with your Xaml. If the Xaml is incorrect or you have forgot a namespace or so, which is very easy in a big resource, the application tends to just go blank. If there is something wrong with the merging of the dictionaries it generally gives your an less than great error message. But if the Xaml is bad, it can just make the controls invisible. So I spent a fair amount of time trying to get this to work.
I decided that I wanted my resources as “real” resources in my project. That is, compiled into my assembly. The other way is to have them as Content, in which case they are placed in the xap file, but not compiled into the application. But to the execution…
Create new Xaml file. There is now way to do this straight up in Visual Studio. What you do is either add a new Xml file or as I did, add a new Silverlight Usercontrol. After adding the control, just expand the node in the Solution Explorer and delete the cs file. After that we need to make some modifications. Start by selecting the file in the Solution Explorer. Then look in the Properties pane. Change the Build Action to Resource. I also removed the Custom Tool. I don’t know if that is necessary, but i have previously had issues with that…
Then open up the Xaml file and make the following changes. Remove the x:Class, Width and Height attribute and rename the element to ResourceDictionary instead of UserControl (Don’t forget to rename the closing tag as well). And remove the Grid in there… Then you are done. That is a resource dictionary… Then Add your resources in there. Don’t forget to give it a Key or name. I don’t honestly know if there is any difference, but I generally use x:Key for my resources. And yeah…if you are copying a resource from an existing file, don’t forget to add any necessary namespaces.
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Button" x:Key="ButtonStyle">
<Setter Property="FontFamily" Value="Verdana" />
</Style>
</ResourceDictionary>
Oh yeah…there is a tiny little downside to use MergedDictionaries. There is? Well…yes…at least if you are using the Resource option. I don’t know if it is the same with Content. But you have to recompile to get the designer pane to show any changes made to the resources…
The next step is to get it into your control. This is done very simply if you look online. I did however struggle to get this going. I don’t know why. I might suck. But to be honest, I found SEVERAL ways of doing this. And to be honest, there isn’t. There is only 2 ways. One for resources embedded as Resource and one for Content.
Start of by declaring a new ResourceDictionary tag inside your controls resources.
<UserControl x:Class="flickrVIEWR.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.Resources>
<ResourceDictionary>
</ResourceDictionary>
</Grid.Resources>
</Grid>
</UserControl>
This is very similar to what you normally do. Except generally you don’t explicitly declare the ResourceDictionary in there, but instead just declare you resources. It might not be strictly necessary to declare the ResourceDictionary explicitly if you don’t mix local and external resources, but I prefer doing it because it works in all situations and not just in certain cases.
Next we need to declare our MergedDictionaries. The MergedDictionaries is a property on the ResourceDictionary class. So is looks like this
<Grid.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Grid.Resources>
Inside the MergedDictionaries, you need to define your resources. This is done by declaring a ResourceDictionary object inside the MergedDictionaries element. The ResourceDictionary object declares a Source property. This Source property is the secret to getting this to work. It is different depending on the way that the resource has been embedded.
If you follow my example and use the Resource alternative, the Source is defined as follows: /assembly;component/addressToResource. The “assembly” part is basically just the name of you assembly without file extension. The “component” part is a keyword. So if my assembly name i MySilverlightAssembly.dll and the resource is called MyResource.xaml and is placed in a folder called Resources, the Source would be like this
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MySilverlightAssembly;component/Resources/MyResource.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Some people online spoke about a shorter syntax for this, that could be used if the resource is embedded in the local assembly. I would not recommend using this. Use the full syntax as it reduces possible issues.
If the resource has been embedded as Content, the source is basically just a relative url to the file. If the control that I’ve been working on is in the root of the application, the Xaml would look like this
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/MyResource.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
So…that is it. My intro to MergedDictionaries. I really hope this helps someone. And I really hope that you see the upside to using merged dictionaries….