wpf 如何动态更改 ResourceDictionary

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33867091/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 13:33:49  来源:igfitidea点击:

How to change ResourceDictionary Dynamically

c#wpfresourcedictionary

提问by Shahid Neermunda

I need to change ResourceDictionaryin App.xamlfile dynamically. I have tried the following code:

我需要改变ResourceDictionaryApp.xaml文件动态。我尝试了以下代码:

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

没有错误,但主题没有改变

回答by Justin CI

In button click you can write this code

在按钮单击中,您可以编写此代码

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

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

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>

回答by Salah Akbari

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_OnClickevent you should change all StaticResourceused in your application to DynamicResourcefor example change this:

如果您想从Button_OnClick事件中更改它,您应该更改StaticResource应用程序中使用的所有内容DynamicResource,例如更改以下内容:

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

To this:

对此:

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

回答by Jammer

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

这是我用于处理这些情况的类。您可以在我的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;
        }
    }
}

回答by Shahid Neermunda

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

我通过InitializeComponent()在所有 Window 的构造函数中添加上面方法的以下代码解决了上述问题。

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