WPF Modern UI 主题更换原理
2021-07-14 12:16
标签:www. ems 元素 erp NPU 资源文件 img 字段 initial 代码路径 : FirstFloor.ModernUI.App / Content / SettingsAppearance.xaml 形如 Property = "{ Binding fieldname }" 这种格式的绑定,都是将控件属性绑定到当前 用户控件 DataContext 属性的对象中的。 那我们再打开 SettingsAppearance.cs 文件看一看后台代码: 很显然,控件的 DataContext 属性引用到了 new SettingsAppearanceViewModel(); 那再F12进去分析一下 SettingsAppearanceViewModel 这个类有哪些相关的东西: 首先看一下 Themes 这个属性 ,它是一个 LinkCollection 对象,并返回了 themes 字段: LinkCollection 继承自 ObservableCollection ,百度一下 ObservableCollection这个类,就知道它其实也是用来实现数据绑定的,当集合内的元素发生变化时,集合就会通知外部调用者,此处不多赘述。 此外,SettingsAppearance 类的构造函数中向 themes 添加了一些主题,这里就不贴代码了。 当 SelectedTheme 更改时,set 方法会更改当前的主题源。 对 ThemeSource 这个属性一直F12下去,会找到一个方法 SetThemeSource: 看一下第一个函数 GetThemeDictionary: 这个函数使用 LINQ 从 App.xaml 定义的 MergedDictionaries 中搜索主题资源 看一下 App.xaml 里面的代码: 这里面预定义了两个资源,去相应的地方找到这两个资源文件,其中 ModernUI.Light.xaml 内有大量包含 "WindowBackground" 字符串的 Key ,那这个显然就是主题资源文件了。 接下来的逻辑就比较好理解了:调整 AccentColor ,加入新的主题,移除旧的主题,最后通知属性更改。 那主题更改的渐变动画效果是在哪里触发的呢? 看一下 MainWindon 的基类 MorderWindow , 这里面监听了 AppearanceManager.Current.PropertyChanged 事件: 再找一下 backgroundAnimation 赋值的地方 backgroundAnimation 其实是从资源文件中加载的,找到 ModernWindow.xaml 文件,相关代码: 到这里整个主题更换的流程就很明朗了。 总结一下主题更换的简要流程: WPF Modern UI 主题更换原理 标签:www. ems 元素 erp NPU 资源文件 img 字段 initial 原文地址:https://www.cnblogs.com/ArthurRen/p/WPF_ModernUI.htmlWPF Modern UI 主题更换原理
一 . 如何更换主题?
二 . 代码分析
1.关键 XAML 代码
public partial class SettingsAppearance : UserControl
{
public SettingsAppearance()
{
InitializeComponent();
// a simple view model for appearance configuration
this.DataContext = new SettingsAppearanceViewModel();
}
}
2. Themes
public LinkCollection Themes
{
get { return this.themes; }
}
3. SelectedTheme
public Link SelectedTheme
{
get { return this.selectedTheme; }
set
{
if (this.selectedTheme != value) {
this.selectedTheme = value;
OnPropertyChanged("SelectedTheme");
// and update the actual theme
AppearanceManager.Current.ThemeSource = value.Source;
}
}
}
private void SetThemeSource(Uri source, bool useThemeAccentColor)
{
if (source == null) {
throw new ArgumentNullException("source");
}
var oldThemeDict = GetThemeDictionary();
var dictionaries = Application.Current.Resources.MergedDictionaries;
var themeDict = new ResourceDictionary { Source = source };
// if theme defines an accent color, use it
var accentColor = themeDict[KeyAccentColor] as Color?;
if (accentColor.HasValue) {
// remove from the theme dictionary and apply globally if useThemeAccentColor is true
themeDict.Remove(KeyAccentColor);
if (useThemeAccentColor) {
ApplyAccentColor(accentColor.Value);
}
}
// add new before removing old theme to avoid dynamicresource not found warnings
dictionaries.Add(themeDict);
// remove old theme
if (oldThemeDict != null) {
dictionaries.Remove(oldThemeDict);
}
OnPropertyChanged("ThemeSource");
}
private ResourceDictionary GetThemeDictionary()
{
// determine the current theme by looking at the app resources and return the first dictionary having the resource key ‘WindowBackground‘ defined.
return (from dict in Application.Current.Resources.MergedDictionaries
where dict.Contains("WindowBackground")
select dict).FirstOrDefault();
}
4. 动画
///
///
三 、总结
四、下一篇参考本流程来自己实现一个简单的主题更换功能
下一篇:理解C#中的闭包