Resource dictionaries in WPF are not shared, unless they are part of
App.xaml. That is, if you have a user control that loads (and uses) some resource dictionary, new instance of the dictionary will be loaded for each instance of the user control. This can (and does) lead to increased loading time and memory footprint.
I wrote a test application that demonstrates the problem. Source code Visio diagrams
Main window has four user control objects: two of type
UserControl1 (red) and two of type
UserControl2 (yellow). I defined a class named
BigFatObject that allocates 200MB of memory. As instances of the class are created, they get sequential numbers: #1, #2, etc. Each user control refers to one instance of
App.xaml and to another instance from
Dictionary1.xaml. You can see that instance #1 from
App.xaml is shared by all controls, but each control has its own instance from
Dictionary1.xaml (#2, #3, #4, and #5 respectively).
As a result, the application has 5 (five) 200MB objects, and its memory footprint is over 1GB in size. In our production code private dictionaries contained not one big object, but lots of small objects (brushes, colors, styles, etc.). This affected not only memory footprint, but also the startup time. Each time a user control was created, the dictionary had to be processed and all objects in it re-created.
Here’s how I use a resource dictionary in my user controls:
<UserControl ...> <UserControl.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Dictionary1.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </UserControl.Resources> </UserControl>
Here’s the relationship between XAML files in the application:
And here’s the object graph:
You can easily observe the duplication.
The solution to this problem is to put shared resource in
App.xaml or include your dictionary from
App.xaml. If you don’t have control over
App.xaml, manually load your shared resources in code as described in this StackOverflow article. If you continue to refer to shared resources from user controls, you will suffer from increased memory footprint and slow load times.
Hello, this is a very interesting article, thank you for it!
What about controls inside ContentPresenter control? Can I force them to use resources from App.xaml?
In theory, everything in your application should be able to use resources from
app.xaml. I just verified that a control dynamically assigned to be a content of a
ContentControl(that internally uses
ContentPresenter) can use resources from
app.xaml. Do you have a specific example when that does not work?