3

In 'enterprise-level' application we are loading from externall assembly one big ResourceDictionary containing many merged dictionaries which contain another merged dictionaries and so on ... and then assign this one big loaded resource to Application.Current.Resources as a merged resource. As a result Application.Current.Resources contains one big merged resource with lots of nestig levels of another mergerd resources. The idea is to make it flat which means iterate throughout this one big resource and assign keys to Application.Current.Resources instead of adding it as a merged resource. Something like this:

var flattedKeyValues = new Dictionary<object, object>();
var alreadyFlattenedResources = new List<string>();

AddAllLevelKeysFromResource(loadedBigResource, flattedKeyValues, alreadyFlattenedResources);

foreach (var keyValue in flattedKeyValues)
{
    System.Windows.Application.Current.Resources.Add(keyValue.Key, keyValue.Value);
} 

where:

// recursive method
    private static void AddAllLevelKeysFromResource(ResourceDictionary rootResDictionary, Dictionary<object, object> keyValues, List<string> alreadyFlattenedResources)
    {
        if (alreadyFlattenedResources.Contains(rootResDictionary.Source.OriginalString))
        {
            return; //to not to unnecessary iterate twice already iterated resource
        }

        foreach (var resDictionary in rootResDictionary.MergedDictionaries)
        {
            AddAllLevelKeysFromResource(resDictionary, keyValues, alreadyFlattenedResources);
        }
        AddFirstLevelKeysFromResource(rootResDictionary, keyValues);

        alreadyFlattenedResources.Add(rootResDictionary.Source.OriginalString);
    }

and

private static void AddFirstLevelKeysFromResource(ResourceDictionary resDictionary, Dictionary<object, object> keyValues)
{
    foreach (var key in resDictionary.Keys)
    {
        if (keyValues.ContainsKey(key))
        {
            keyValues[key] = resDictionary[key]; // because later added key should override previous key
        }
        else
        {
            keyValues.Add(key, resDictionary[key]);
        }
    }
}

However it doesn't work because some of the styles/resources items are not set correctly. Is it possible to flat resource like this? Or maybe it is not enough to just copy the keys and values because each mergerd resource object contain some other required informations for his keys? (we mostly use DynamicResources)

Meho
  • 31
  • 1
  • 3
    The comment "because later added key should override previous key" implies that you're assuming the dictionary entries are enumerated in the order in which you declared them. That's not the case. – Clemens Oct 12 '17 at 10:13
  • Using `var alreadyFlattenedResources = new HashSet();` probably enhances the performance of `Contains` (`O(1)` vs. `O(n)`). And if you're *always* overriding entries for existing keys, then there is no need for `ContainsKey` and you can simply use `keyValues[key] = resDictionary[key];` all the time. -- but as @Clemens mentioned, the order in which dictionary entries are traversed is not guaranteed. – Corak Oct 12 '17 at 10:22
  • @Clemens - ok lets forget about duplicated keys. I've checked this and there is not much resources with the same key. Even with only unique keys in this one big loaded resource it doesn't work. After running application some of the UI elements are dispalyed correctly but some not so it's not the case i believe. – Meho Oct 12 '17 at 11:15
  • @Clemens: or maybe the keys order is not correct? For example one item reffers to key which is "below" him. But i'm iterating throughout the most nested resources first so this should be fine – Meho Oct 12 '17 at 11:22
  • "The idea is to make it flat" is probably pointless in the first place. For what reason would you want to do that at all? – Clemens Oct 12 '17 at 11:38
  • @Clemens: for performance reason. All our views heavily use resources. Views are very lightweight and all apperance and behaviour stuff are referenced from resources (styles, templates and others...). We can change application "look and fell" by loading another assembly containing all these resources (and assign it to Application.Current.Resources). This one big resource has many nesting levels and contains thousands of keys. Iterating through such big tree to find particular key must be time consuming and every time the view is switched for example then – Meho Oct 12 '17 at 13:37
  • @Clemens: sorry - the last sentence is not finished: This one big resource has many nesting levels and contains thousands of keys. Iterating through such big tree to find particular key must be time consuming and for example switching between views is not very fast probably because many ui elements has to find their related resources. – Meho Oct 12 '17 at 13:44
  • Despite that some of the UI elements aren't displayed correctly, do you actually observe any significant performance gain by "flattening" the resource dictionary? – Clemens Oct 12 '17 at 13:48
  • @Clemens: After performance measurements gain is significant. Changing between views is almost 3 times faster with flat resources compared to "tree-like" resources - application is much more 'smoother'. – Meho Oct 16 '17 at 06:08
  • By the way - [here is similar case](https://stackoverflow.com/questions/6693320/mergeddictionaries-and-resource-lookup) – Meho Oct 17 '17 at 06:48

0 Answers0