Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merging dictionaries into multiple user controls - does this affect memory?

Tags:

wpf

xaml

I have a UI project containing (so far) 18 XAML resources, which are merged into App.xaml like so:-

<Application ...>
   <Application.Resources>
       <ResourceDictionary>
           <ResourceDictionary.MergedDictionaries>
               <ResourceDictionary Source="pack://application:,,,/foo.Client.Common;component/UIStyles/Colours.xaml" />
               <ResourceDictionary Source="pack://application:,,,/foo.Client.Common;component/UIStyles/Buttons.xaml" />
               <ResourceDictionary Source="pack://application:,,,/foo.Client.Common;component/UIStyles/Menus.xaml" />
               // etc..
           </ResourceDictionary.MergedDictionaries>
       </ResourceDictionary>
   </Application.Resources>
</Application>

When I edit any of the XAML views in this project I get intellisense (Resharper) on the style names contained in these resources.

Now, the application also implements a "plug-in" architecture, and there are several class library projects containing views and view models; these get dynamically loaded at runtime. Although the application runs fine, I don't get style name intellisense when I edit XAML views in these projects. I can get the intellisense to work by merging the necessary styles into a view's XAML, e.g.:-

<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/foo.Client.Common;component/UIStyles/Buttons.xaml" />
            //etc..
        </ResourceDictionary.MergedDictionaries>

        // User control-specific styles go here.
    </ResourceDictionary>
</UserControl.Resources>

By doing this in each user control, am I "duplicating" each resource and therefore bloating the application's memory requirements? If so, is there any way around it? What if I created a resource file in the class library, merged the 15 "core" resources into that, then merged this one resource into my views? Will it still result in the same issue?

Failing this I guess I'll have to keep the "merge XAML" commented out in each view, and temporarily reinstate it only when I need to work on a view.

like image 984
Andrew Stephens Avatar asked Apr 26 '26 17:04

Andrew Stephens


1 Answers

Good question. I have the same problem.

There are essentially two problems here:

1) Annoying duplication in the Xaml code - I am not talking about the duplication of actual resources - rather, you have to write <ResourceDictionary> everywhere.

2) The actual duplication of resources - wasting resources, plus: you will lose the benefit of swapping out the styles on runtime, if they are not placed in the same place.

HOw can you solve these problems?

By creating new xaml file, calling it SharedResourceDictionary.xaml, which includes all the resources. This will be included by App.xaml.

This will essentially allow you to pull the ResourceDictionary inside other xaml components, in a short way, just include the SharedResourceDictionary.xaml.

The second trick is to make sure the resources are created 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]);
            }
        }
    }
}

If that doesn't work, there's some comments below: http://www.wpftutorial.net/MergedDictionaryPerformance.html

It's also possible to explore the land of xaml ifdef code:

Does XAML have a conditional compiler directive for debug mode?

like image 178
Erti-Chris Eelmaa Avatar answered Apr 28 '26 06:04

Erti-Chris Eelmaa