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.
A colleague of mine emailed our internal tech list the following email
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.
I was just debugging a very long render delay in some WPF code and I came across this little tidbit:
The quote of interest is: “Each time a control references a
ResourceDictionaryXAML 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.xaml
If 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.
Thanks to Charlie Robbins (Lab49) for expanding on Christian’s blog post and for letting me re-print your email.