Bookmark and Share Share...    Subscribe to this feed Feed   About me...


Merged ResourceDictionaries

Problems loading merged resource dictionaries in .NET 4.0

I experienced a problem, when I am trying to merge resource dictionaries at app-level. As soon as I changed the target framework from 3.5 to 4.0 they don't get loaded anymore. It seems as if they have changed something in the behavior of MergedResourceDictionaries in .NET 4.0.

I found a way how to fix this problem. Just add a dummy default style in the resource dictionary where you merge all resources together. See the following example:

 
<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Styles/DefaultStyle.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>
 
 
 
<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="DefaultStyle/Button.xaml"/>
    </ResourceDictionary.MergedDictionaries>
 
    <Style TargetType="Control" BasedOn="{StaticResource {x:Type Control}}" />
 
</ResourceDictionary>
 
 

Improve the performance of merged ResourceDictionaries

Each time a control references a ResourceDictionary XAML creates a new instance of it. So if you have a custom control library with 30 controls in it and each control references a common dictionary you create 30 identical resource dictionaries!

 
<ResourceDictionary.MergedDictionaries>
   <SharedResourceDictionary Source="/MyControlLibrary;component/Themes/Brushes.xaml"  />
</ResourceDictionary.MergedDictionaries>
 
 

To get rid of this problem, I created the SharedResourceDictionary. You can use it the same way as a conventional ResourceDictionary. The only suptile difference is, that if it is instanced multiple times, the resources are loaded only once.

 
 
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", 
"WPFTutorial.Utils")]
 
/// <summary>
/// The shared resource dictionary is a specialized resource dictionary
/// that loads it content only once. If a second instance with the same source
/// is created, it only merges the resources from the cache.
/// </summary>
public class SharedResourceDictionary : ResourceDictionary
{
    /// <summary>
    /// Internal cache of loaded dictionaries 
    /// </summary>
    public static Dictionary<Uri, ResourceDictionary> _sharedDictionaries =
        new Dictionary<Uri, ResourceDictionary>();
 
    /// <summary>
    /// Local member of the source uri
    /// </summary>
    private Uri _sourceUri;
 
    /// <summary>
    /// Gets or sets the uniform resource identifier (URI) to load resources from.
    /// </summary>
    public new Uri Source
    {
        get { return _sourceUri; }
        set
        {
            _sourceUri = value;
 
            if (!_sharedDictionaries.ContainsKey(value))
            {
                // If the dictionary is not yet loaded, load it by setting
                // the source of the base class
                base.Source = value;
 
                // add it to the cache
                _sharedDictionaries.Add(value, this);
            }
            else
            {
                // If the dictionary is already loaded, get it from the cache
                MergedDictionaries.Add(_sharedDictionaries[value]);
            }
        }
    }
}
 
 



 Comments on this article

Show all comments
AVEbrahimi
Commented on 14.May 2009
Seems great, I'll check it and post results here.
I've very long startup time in my big WPF project...
Andrew
Commented on 28.May 2009
Looks nice, but is this SharedResourceDictionary Blend "friendly"?
Christian Moser
Commented on 28.May 2009
Hi Andrew,

No, unfortunately the current versions of Blend cannot deal with it :-( I am searching for another solution that is fast and also supported by Blend.
Andrew
Commented on 1.June 2009
Looks like I've found a solution which address the same issue as yours, but it is a Blend friendly - check it out http://www.drwpf.com/blog/Home/tabid/36/EntryID/10/Default.aspx - in section "Manage a Collection of Resource Dictionaries in Code and Merge them at the Element Level" there is class "SharedResources".
DJanjicek
Commented on 31.July 2009
Hi Andrew,

since totday I'm using MergedDictionaries in my Silverlight project and I'm facing huge performance problems. The app is consuming almost 1GB of memory after a few clicks. Your solution could help me out of this trouble but I have no idea how to implement your code and how to use it.

Could you help me with this?
Sergey
Commented on 10.August 2009
I agree with DJanjicek.
Andrew, could you share an example of using your class?
Cameron
Commented on 24.August 2009
Just be aware... we were using the SharedResourceDictionary in our project, until we found out that it was holding onto XAML pages that had been closed, and thus were not being garbage collected.
HDW
Commented on 31.October 2009
_sourceUri = new Uri(value.OriginalString); allows garbage collection.

Also wrapping access to _sharedDictionaries in lock (((ICollection)_sharedDictionaries).SyncRoot) and wrapping access to MergedDictionaries in lock (((ICollection)MergedDictionaries).SyncRoot) makes the class thread safe.
fmunkert
Commented on 9.November 2009
SharedResourceDictionary seems not be compatible with the {ThemeDictionary ...} markup extensions. An InvalidOperationException is thrown which states that ThemeDictionaryExtension can be used with ResourceDictionary only.
There might be other code in WPF which does not work if you derive from ResourceDictionary.
Lee Campbell
Commented on 12.May 2010
Thanks Christian,
FYI: I have added a colleagues expansion on the problem referencing this post on this site
http://leecampbell.blogspot.com/2010/05/mergeddictionaries-performance-problems.html
Mike
Commented on 2.July 2010
I'm having some issues with this solution in the designer. I am trying to use the designer in VS2010. Using this, I get an error when using the designer, and I can't get any code completion. Any ideas, if this works in the designer?
Fran Herrera
Commented on 31.August 2010
Same here. I'm receiving a NotSupportedException when using SharedResourceDictionary on design time. When running the app, everything seems to work. VS2010Express.

Name
E-Mail (optional)
Comment
About Christian Moser