Shahid Neermunda
Shahid Neermunda

Reputation: 1357

How to change ResourceDictionary Dynamically

I need to change ResourceDictionary in App.xaml file dynamically. I have tried the following code:

ResourceDictionary newRes = new ResourceDictionary();
newRes.Source = new Uri("/PsyboInventory;component/TitleBarResource.xaml", UriKind.RelativeOrAbsolute);
this.Resources.MergedDictionaries.Clear();
this.Resources.MergedDictionaries.Add(newRes);

There is no error, but the theme not change

Upvotes: 5

Views: 13566

Answers (4)

Justin CI
Justin CI

Reputation: 2741

In button click you can write this code

var app = (App)Application.Current;
app.ChangeTheme(new Uri("New Uri here"));

ChangeTheme:

public partial class App : Application
    {
        public ResourceDictionary ThemeDictionary
        {
            // You could probably get it via its name with some query logic as well.
            get { return Resources.MergedDictionaries[0]; }
        }
    
        public void ChangeTheme(Uri uri)
        {
            ThemeDictionary.MergedDictionaries.Clear();
            ThemeDictionary.MergedDictionaries.Add(new ResourceDictionary() { Source = uri });
        } 
       
    }   

    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary x:Name="ThemeDictionary">
                    <ResourceDictionary.MergedDictionaries>
                        <ResourceDictionary Source="/Themes/ShinyRed.xaml"/>
                    </ResourceDictionary.MergedDictionaries>
                </ResourceDictionary>
    </ResourceDictionary.MergedDictionaries>

Upvotes: 4

Shahid Neermunda
Shahid Neermunda

Reputation: 1357

I solved above problem by adding following code above InitializeComponent() method in all Window's constructor.

ResourceDictionary newRes = new ResourceDictionary();
newRes.Source = new Uri("/PsyboInventory;component/TitleBarResource.xaml",UriKind.RelativeOrAbsolute);
this.Resources.MergedDictionaries.Clear();
this.Resources.MergedDictionaries.Add(newRes);

Upvotes: 0

Salah Akbari
Salah Akbari

Reputation: 39956

Just change:

newRes.Source = new Uri("/PsyboInventory;component/TitleBarResource.xaml", UriKind.RelativeOrAbsolute);

To:

newRes.Source = new Uri("TitleBarResource.xaml", UriKind.Relative);

If you want to change it from a Button_OnClick event you should change all StaticResource used in your application to DynamicResource for example change this:

<Button Style="{StaticResource buttonStyle}" >Click Me!</Button>

To this:

<Button Style="{DynamicResource buttonStyle}" >Click Me!</Button>

Upvotes: 2

Jammer
Jammer

Reputation: 10208

Here is the class I use for handling these situations. You can find a complete demo in my GitHub Demo.

namespace JamSoft.CALDemo.Modules.SkinManager
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Windows;

    using JamSoft.CALDemo.Modules.SkinManager.Core;
    using JamSoft.CALDemo.Modules.SkinManager.Core.Exceptions;

    /// <summary>
    /// The skin manager class
    /// </summary>
    public class SkinManager : DependencyObject, ISkinManager
    {
        /// <summary>
        /// The current skin property
        /// </summary>
        public static readonly DependencyProperty CurrentSkinProperty = DependencyProperty.Register(
            "CurrentSkin", 
            typeof(Skin), 
            typeof(SkinManager), 
            new UIPropertyMetadata(Skin.Null, OnCurrentSkinChanged, OnCoerceSkinValue));

        /// <summary>The default skin name</summary>
        private const string DefaultSkinName = "Default";

        /// <summary>The _skin finder</summary>
        private readonly SkinsFinder _skinFinder = new SkinsFinder();

        /// <summary>The _skins</summary>
        private List<Skin> _skins = new List<Skin>();

        /// <summary>
        /// Initializes a new instance of the <see cref="SkinManager"/> class.
        /// </summary>
        public SkinManager()
        {
            Initialize();
        }

        /// <summary>Gets the skins.</summary>
        /// <value>The skins.</value>
        public ObservableCollection<Skin> Skins
        {
            get
            {
                return new ObservableCollection<Skin>(_skins);
            }
        }

        /// <summary>Gets or sets the current skin.</summary>
        /// <value>The current skin.</value>
        public Skin CurrentSkin
        {
            get
            {
                return (Skin)GetValue(CurrentSkinProperty);
            }

            set
            {
                SetValue(CurrentSkinProperty, value);
            }
        }

        /// <summary>Loads the specified skin or the default if specified skin isn't found.</summary>
        /// <param name="skinName">Name of the skin.</param>
        public void LoadSkin(string skinName)
        {
            var skin = _skins.FirstOrDefault(x => x.Name.Equals(skinName)) ?? _skins.FirstOrDefault(x => x.Name == DefaultSkinName);
            CurrentSkin = skin;
        }

        /// <summary>
        /// Called when [coerce skin value].
        /// </summary>
        /// <param name="d">The <paramref name="d"/>.</param>
        /// <param name="baseValue">The base value.</param>
        /// <returns>the coerced skin <see langword="object"/></returns>
        private static object OnCoerceSkinValue(DependencyObject d, object baseValue)
        {
            if (baseValue == null)
            {
                return Skin.Null;
            }

            return baseValue;
        }

        /// <summary>
        /// Called when [current skin changed].
        /// </summary>
        /// <param name="d">The <paramref name="d"/>.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnCurrentSkinChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            try
            {
                Skin oldSkin = e.OldValue as Skin;
                oldSkin.Unload();
                Skin newSkin = e.NewValue as Skin;
                newSkin.Load();
            }
            catch (SkinException ex)
            {
                Console.WriteLine(ex);
            }
        }

        /// <summary>Initializes <c>this</c> instance.</summary>
        private void Initialize()
        {
            _skinFinder.Initialize();
            _skins = _skinFinder.SkinsList;
        }
    }
}

Upvotes: 0

Related Questions