Click here to Skip to main content
15,393,638 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.
   
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
Pete O'Hanlon 22-Nov-19 10:54am
   
I really should have looked closer at your code, that's not the way you should be loading your RD's. You're trying to load them from the xaml file, which you aren't going to be shipping. What you need to do is load them using a Pack URI like this:

Window.Resources.MergedDictionaries.Add(new ResourceDictionary { Source = new Uri("pack://application:,,,/MikeSample;component/Brushes.xaml", UriKind.RelativeOrAbsolute) });
Mike Hankey 22-Nov-19 11:01am
   
Yeah I changed them all to packs, I'm learning fairly quickly.

I bought the WPF 4.5 Unleashed and while it's a good book it doesn't go into much detail but covers most everything.

What I'm finding on the web, if I can find it usually doesn't work but gives me a general idea and I can most times figure out what needs to be done, but still struggling in other areas.

Can you recommend any in-depth books or tuts?
Pete O'Hanlon 25-Nov-19 9:28am
   
Sorry Mike, I missed this. If I were starting off now, I'd read the WPF articles here by Josh Smith, Karl Shifflett, Daniel Vaughan and Sacha Barber. They have everything pretty much covered.
Mike Hankey 25-Nov-19 9:44am
   
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