UWP 运行时切换UI主题颜色(theme)

在WPF 可以通过DynamicaResource在运行时切换UI的一些属性。在UWP 中已没有DynamicaResource,

而是通过提供ThemeResource和ResourceDictionary.ThemeDictionaries来实现切换预定义甚至自定义的主题颜色。以下将简述在应用程序运行时,响应系统 High-Contrast-Mode 及Color-Settings Dark/Light事件而切换自身UI颜色的一种实现,以及应用程序独立于系统Color-Settings Dark/Light 的变化,而自身提供设置选项实现Dark/Light切换的方法。

响应系统变化的实时切换

ThemeResource 是xaml中一组在运行时可以应用不同值的资源。具体取什么值取决于windows系统的状态。目前ResourceDictionary.ThemeDictionaries中内置支持了 ResourceDictionary.ThemeDictionaries"Light", "Dark", and "HighContrast"三种方式(参考 https://docs.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/xaml-theme-resources)。

通过以下这样的方式定义颜色:

UWP 运行时切换UI主题颜色(theme)_第1张图片

然后在Styles, Setters, Control templates, Property setters, and Animations中使用ThemeResource,那么当系统中Color-Settings 中的 “app mode” 状态切换时,应用程序就会自动地选择对应Key 的ResourceDictionary下定义的资源。

比如定义以下简单的UI来使用这三个资源

UWP 运行时切换UI主题颜色(theme)_第2张图片

我的系统默认color-mode是Light(大多数人默认情况下应该也是Light),如下

UWP 运行时切换UI主题颜色(theme)_第3张图片

那么此时,我运行起这个App的界面是这样的:

然后在系统color-settings中,app mode切换为Dark,程序会自动会响应系统的变化,自动套用ThemeDictionaries中的"Dark"之下的资源,变化如下:

UWP 运行时切换UI主题颜色(theme)_第4张图片

如果此时系统启动High-Contrast-Mode,那么程序也会响应,自动套用ThemeDictionaries中的"HighContrast"之下的资源,每个brush都使用ThemeResouce引用系统定义的资源如SystemColorWindowxxxx,可以观察到当系统的High-Contrast-mode在不同的模式下切换时,应用程序也会作出相应的变化。需要的截图太多了,请下载我的程序https://download.csdn.net/download/mochounv/12555566,运行观察。

关于High-Contrast-mode是另一个topic,可以参考https://docs.microsoft.com/en-us/windows/uwp/design/accessibility/high-contrast-themes

独立于系统变化的实时切换

如果希望自己的App不管在系统切换到啥模式时,都不去响应,而是等到自己想切换时再切换。这也是一种很常见的方式,比如visual studio, 比如系统中的weather程序(当然这两个程序背后的机制是不一样,前者应该不是UWP)。所以这是可以实现,只是没有直接的API,这里提供一种拙略的方式,希望有更好方法的高手提出来借鉴一下。

因为虽然是不响应系统变化,但是还是需要切换资源的,所以资源的定义方式还是跟上面的方式一样,使用也一样。不响应系统的变化,只需要在程序的初始化的地方添加以下语句,

UWP 运行时切换UI主题颜色(theme)_第5张图片

加上这语句后,程序就不响应系统的变化了(注意:不响应Color-Settings中的变化,但是High-Contrast-mode还是正常响应的)。

可以还需要实现这样的目标:

UWP 运行时切换UI主题颜色(theme)_第6张图片

不要认为RequestTheme=xxx就可以了,很抱歉,App.RequestTheme只能在启动时设置,运行时是不能用的。

窗口是关上了,可以在哪里打开这个门呢?

App级别的RequestTheme是不能在运行时设置了,发现还有一个FrameworkElement级别的 RequestedTheme是可以的,那么不管用如何方法,只要将需要切换颜色的FrameworkElement的元素都重新设置RequestTheme就可以了。只是实际的环境下,一个应该的元素何止上百,每次做这样的遍历和重设,这个性能及可维护性如何保证呢。

想通过提供一个基于FrameworkElement的style作为其它style的继承对象,然后在运行修改这个基础style的RequestedTheme值,但这是行不通的,因为在uwp中所有style都是作为staticresource被使用的。

想了半天,还是通过遍历逻辑树来实现了:

UWP 运行时切换UI主题颜色(theme)_第7张图片

你可能感兴趣的:(windows,10,UWP)