Question

The WPF documentation on MergedDictionaries suggests that if you load two ResourceDictionaries in XAML, the second loaded one will be able to reference the first. The Windows Phone documentation on MergedDictionaries does not explicity state this but I assume the same rules apply. However the following does not work in my Windows Phone App.xaml,

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="View/ThemeDictionaries/LightThemeResourceDictionary.xaml"/>
    <ResourceDictionary Source="View/ThemeDictionaries/MainResourceDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>

The debug says the MainResourceDictionary line cannot reference SubTitleTextColor which is defined in LightThemeResourceDictionary - I have checked the spelling of the reference.

Is this type of loading not possible in Windows Phone? How do I work around it?

Was it helpful?

Solution

Based on the Silverlight Resources documentation (much more applicable than the WPF ones), this scenario won't work. There are 2 ways to get around this:

  • merge the first dictionary into the second one instead of the app's dictionary.
  • create an attached property that has a List<ResourceDictionary> that will manually merge them into one giant ResourceDictionary and set the application's resources to it.

OTHER TIPS

Thanks to Abe for the help, although in the end I went with a 'resolver' class that is included as a merged dictionary and resolves to the appropriate theme dictionary. The reasons are beyond the scope of he original question:

  1. You can load the appropriate dictionary at initialisation stage in App.xaml.cs without later having to overwrite the resources programatically based on user choice (before you would have to merge in a default theme, say Light at initialisation, and if the user had selected Dark then merge in the Dark theme later)
  2. Most importantly, If you do later overwrite the theme resources then other resources defined at initialisation that reference the overwritten resources will not change!

The code is based on an idea by this blogger.

ThemeResourceDictionaryResolver.cs

using System;
using System.IO;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Resources;
using System.IO.IsolatedStorage;

namespace YourAppName.View
{
    public enum ApplicationTheme 
    {
        Dark,
        Light
    }

    public class ThemeResourceDictionaryResolver : ResourceDictionary
    {
        public ThemeResourceDictionaryResolver() : base()
        {
            ApplicationTheme theme;
            if (System.ComponentModel.DesignerProperties.IsInDesignTool)
            {
                // Set here which dictionary you want to be loaded in Blend
                theme = ApplicationTheme.Light;
            }
            else
            {
                ApplicationTheme theme;
                if (!IsolatedStorage.ApplicationSettings.TryGetValue("ApplicationTheme", out theme))
                {
                    // The 'standard' way to get the global phone theme
                    Visibility darkBGVisibility = (Visibility)Application.Current.Resources["PhoneDarkThemeVisibility"];
                    theme = (darkBGVisibility == Visibility.Visible) ? ApplicationTheme.Dark : ApplicationTheme.Light;
                }
            }
            // Change the URI string as appropriate - this way refers to the Dictionaries 
            // which are set to 'Build: Page'. I couldn't get to work when set to Build as
            // Content and using the simpler URI scheme.
            Uri uri = new Uri(string.Format("YouAppName;component/View/Themes/{0}ThemeResourceDictionary.xaml", theme), UriKind.RelativeOrAbsolute);
            ResourceDictionary res = this.LoadXaml<ResourceDictionary>(uri);
            this.MergedDictionaries.Add(res);
        }


        // For some reason a simple ResourceDictionary() { Source = uri }; does not work, 
        // need to use this instead
        T LoadXaml<T>(Uri uri)
        {
            StreamResourceInfo info = Application.GetResourceStream(uri);
            if (info != null)
            {
                using (StreamReader reader = new StreamReader(info.Stream))
                {
                    return (T)XamlReader.Load(reader.ReadToEnd());
                }
            }
            return default(T);
        }

    }
}

MainResourceDictionary.xaml

...

<ResourceDictionary.MergedDictionaries>
    <views:ThemeResourceDictionaryResolver />
</ResourceDictionary.MergedDictionaries>

<!-- StaticResources that refer to the theme StaticResources can go here -->

...

App.xaml

...

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="View/Themes/MainResourceDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>

...
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top