|
|
|
|
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.
|
|
|
|
|