WPF中,每一個元素都有Resources屬性,同時本身能夠建立ResourcesDictionary,經過 <ResourceDictionary.MergedDictionaries>添加單獨定義的resources供多個xaml之間公用 html
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! java
<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. web
[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]); } } } }
另一篇文章介紹了應用這個類取得的改進。 c#
http://leecampbell.blogspot.hk/2010/05/mergeddictionaries-performance-problems.html app
I don’t normally like to blatantly plagiarise other people’s comments, but this seems to be a little know bug that sounds like it should be shared. ide
A colleague of mine emailed our internal tech list the following email post
I strongly urge everyone working with WPF to use this or at least benchmark it in your own applications if you use ResourceDictionaries.MergedDictionaries. I consider this to be a huge problem in WPF. I’m not sure if it exists in Silverlight, but I would assume it does. this
I was just debugging a very long render delay in some WPF code and I came across this little tidbit: google
http://www.wpftutorial.net/MergedDictionaryPerformance.html spa
The quote of interest is: 「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!」
Normally that isn’t a huge problem, but when you consider the way that I personally (and have suggested to others) that they organize their resources in Prism projects it gets to be a **serious**problem. For example, let’s say we have this project structure:
/MyProject.Resources /Resources -Buttons.xaml -DataGrid.xaml -Global.xaml -Brushes.xaml -WindowChrome.xaml -Icons.xaml /MyProject.Module1 /Resources -Module1Resources.xaml (References all Dictionaries in /MyProject.Resources/Resources/*) /Views -View1.xaml -View2.xaml /MyProject.Module2 /Resources -Module2Resources.xaml (References all Dictionaries in /MyProject.Resources/Resources/*) /Views -View1.xaml -View2.xaml /MyProject.Shell /Resources -ShellResources.xaml /Views -MainShell.xamlIf in your views you reference the module-level ResourceDictionary (which helps for maintainability and modularity) then every time you create an instance of View1.xaml for example, you would have to parse all the ResourceDictionaries in /MyProject.Resources/Resources/* every time. This isn’t really a memory concern but it is a huge performance concern. There can potentially be thousands of lines of XAML code to parse and the time really does add up.
I recently switched all of the MergedDictionary references:
<ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source=」/SomeDictionary.xaml」 /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary>To use the attached SharedResourceDictionary which shadows the Source property and keeps a global cache of all ResourceDictionaries parsed:
<ResourceDictionary> <ResourceDictionary.MergedDictionaries> <SharedResourceDictionary Source=」/SomeDictionary.xaml」 /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary>And I saw a performance increase of almost two orders of magnitude … From almost 6000ms to 200ms. I’ve attached this code; I used the basic sample implementation in the link above so this is considered public information for client purposes.
Cheers,
Charlie
Thanks to Charlie Robbins (Lab49) for expanding on Christian’s blog post and for letting me re-print your email.