WPF user controls: do not use merged dictionaries for shared resources

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

WpfDoubleResources

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 BigFatObject from 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:

WpfDoubleResXamls

And here’s the object graph:

WpfDoubleResObjects

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.

2 Comments


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

    Reply

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

      Reply

Leave a Reply to David Cancel reply

Your email address will not be published. Required fields are marked *