如何动态更改 ResourceDictionary
How to change ResourceDictionary Dynamically
我需要动态更改 App.xaml
文件中的 ResourceDictionary
。我试过以下代码:
ResourceDictionary newRes = new ResourceDictionary();
newRes.Source = new Uri("/PsyboInventory;component/TitleBarResource.xaml", UriKind.RelativeOrAbsolute);
this.Resources.MergedDictionaries.Clear();
this.Resources.MergedDictionaries.Add(newRes);
没有错误,但主题没有改变
只需更改:
newRes.Source = new Uri("/PsyboInventory;component/TitleBarResource.xaml", UriKind.RelativeOrAbsolute);
收件人:
newRes.Source = new Uri("TitleBarResource.xaml", UriKind.Relative);
如果您想将它从 Button_OnClick
事件中更改,您应该将应用程序中使用的所有 StaticResource
更改为 DynamicResource
例如更改此:
<Button Style="{StaticResource buttonStyle}" >Click Me!</Button>
为此:
<Button Style="{DynamicResource buttonStyle}" >Click Me!</Button>
这是我用来处理这些情况的class。你可以在我的 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;
}
}
}
点击按钮可以写这段代码
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>
我通过在所有 Window 的构造函数中的 InitializeComponent()
方法上方添加以下代码解决了上述问题。
ResourceDictionary newRes = new ResourceDictionary();
newRes.Source = new Uri("/PsyboInventory;component/TitleBarResource.xaml",UriKind.RelativeOrAbsolute);
this.Resources.MergedDictionaries.Clear();
this.Resources.MergedDictionaries.Add(newRes);
我需要动态更改 App.xaml
文件中的 ResourceDictionary
。我试过以下代码:
ResourceDictionary newRes = new ResourceDictionary();
newRes.Source = new Uri("/PsyboInventory;component/TitleBarResource.xaml", UriKind.RelativeOrAbsolute);
this.Resources.MergedDictionaries.Clear();
this.Resources.MergedDictionaries.Add(newRes);
没有错误,但主题没有改变
只需更改:
newRes.Source = new Uri("/PsyboInventory;component/TitleBarResource.xaml", UriKind.RelativeOrAbsolute);
收件人:
newRes.Source = new Uri("TitleBarResource.xaml", UriKind.Relative);
如果您想将它从 Button_OnClick
事件中更改,您应该将应用程序中使用的所有 StaticResource
更改为 DynamicResource
例如更改此:
<Button Style="{StaticResource buttonStyle}" >Click Me!</Button>
为此:
<Button Style="{DynamicResource buttonStyle}" >Click Me!</Button>
这是我用来处理这些情况的class。你可以在我的 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;
}
}
}
点击按钮可以写这段代码
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>
我通过在所有 Window 的构造函数中的 InitializeComponent()
方法上方添加以下代码解决了上述问题。
ResourceDictionary newRes = new ResourceDictionary();
newRes.Source = new Uri("/PsyboInventory;component/TitleBarResource.xaml",UriKind.RelativeOrAbsolute);
this.Resources.MergedDictionaries.Clear();
this.Resources.MergedDictionaries.Add(newRes);