Click here to Skip to main content
15,886,026 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
This is just a rough draft for a POC!

The Dictionary hierarchy is;
  Colors
  Brushes
  Styles

So the ordering is important


I'm trying to change a theme in WPF, I can do it like this;
XML
+        private void ChangeTheme(string themeName)
+        {
+            ResourceDictionary resource = null;
+            using (FileStream fs = new FileStream("../../../Resources/ResourceDictionaries/" + themeName + ".xaml", FileMode.Open, FileAccess.Read))
+                resource = (ResourceDictionary)XamlReader.Load(fs);
+
+            Application.Current.Resources.MergedDictionaries.Clear();
+            Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary()
+            { Source = new Uri("pack://application:,,,/Resources/ResourceDictionaries/dictionary1.xaml") });
+            Application.Current.Resources.MergedDictionaries.Add(resource);
+            Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary()
+            { Source = new Uri("pack://application:,,,/Resources/ResourceDictionaries/Monotone.Brushes.xaml") });
+            Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary()
+            { Source = new Uri("pack://application:,,,/Resources/ResourceDictionaries/Monotone.xaml") });
+        }


But if I add more ResourceDictionaries to the project I would have to come back here and modify to the list.

What I have tried:

So I thought I would do it this way but it doesn't seem to work. Theme doesn't change! The new theme gets loaded, the old dictionaries get transferred to dictionaryCollection and everything gets added back to Application.Current.Resources.MergedDictionariy but the new theme is not shown?

I've googled for a couple of hours and everything I've found says this should work?

XML
private void ChangeTheme(string themeName)
{
    ResourceDictionary resource = null;
    string file = "../../../Resources/ResourceDictionaries/" + themeName + ".xaml";
    //using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
    //    resource = (ResourceDictionary)XamlReader.Load(fs);

    resource = new ResourceDictionary();
    resource.Source = new Uri(file, UriKind.Relative);

    ResourceDictionary rd = GetActualResourceDictionary();
    if (rd != null)
        Application.Current.Resources.MergedDictionaries.Remove(rd);

    // Create collection to hold old RecourceDictionaries
    System.Collections.ObjectModel.Collection<ResourceDictionary> dictionaryCollection = new
        System.Collections.ObjectModel.Collection<ResourceDictionary>();

    // Copy REsourceDictionaries left after removing the Theme
    foreach (ResourceDictionary dict in Application.Current.Resources.MergedDictionaries)
        dictionaryCollection.Add(dict);

    Application.Current.Resources.MergedDictionaries.Clear();
    Application.Current.Resources.MergedDictionaries.Add(resource);

    foreach (ResourceDictionary dict in dictionaryCollection)
        Application.Current.Resources.MergedDictionaries.Add(dict);
}

//NOTE This works but the
static ResourceDictionary GetActualResourceDictionary()
{
    // get the actual ResourceDictionary
    foreach (ResourceDictionary res in Application.Current.Resources.MergedDictionaries)
    {
        if (res.Source != null)
        {
            string source = res.Source.ToString();
            if (source.ToUpper().Contains("THEME"))
                return res;
        }
    }
    return null;
}
Posted
Updated 21-Nov-19 20:58pm

1 solution

You have missed one important thing out of your example here; how you're actually using your styles inside your XAML. A theme will only be able to change a resource if it's a DynamicResource, so any StaticResource entries will maintain their original styling, regardless of what you do to the resource dictionaries.
 
Share this answer
 
Comments
Mike Hankey 22-Nov-19 8:24am    
Pete, thanks for your input. I'm a complete NOOB, please bear with me.

I have a colors.xaml file that defines the colors that I'm using.
Then I have a brushes.xaml file that defines the brushes using the colors and all brushes are declared dynamic.
Then I have a styles.xaml file that defines the style for all the controls and these are declared as dynamic.

In my example above the first listing works fine, all the colors change between dark and light themes.
But the code in the 2nd listing does not work and I'm wondering if the temporary storage in the temp list is causing the problem?

I hope I've answered your question.
Pete O'Hanlon 22-Nov-19 8:56am    
Mike, in this section:
ResourceDictionary rd = GetActualResourceDictionary();
if (rd != null)
Application.Current.Resources.MergedDictionaries.Remove(rd);

You're only removing one dictionary. Are you sure that's what you should be doing?
Mike Hankey 22-Nov-19 9:01am    
Pete,
Yes I only remove the Color.xaml file because everything is based on defined colors.
The reason I save the rest off into temp list is because the order is important since everything is based on colors.
Pete O'Hanlon 22-Nov-19 9:06am    
Something else to look at is whether or not the UriKind is correct. Try changing it to UriKind.RelativeOrAbsolute.
Mike Hankey 22-Nov-19 9:30am    
I did try that.

In your opinion should what I tried work?
Is this the way you would do it?

Thanks Pete

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900