![](/img/trans.png)
[英]How can I get whether Windows 10 Anniversary Update or later is using its light or dark theme in a WPF app?
[英]Is there any way to make a WPF app respect the system choice of dark/light theme in Windows 10?
Windows 10 最近添加了深色模式; 有没有办法让我的 WPF 应用程序尊重这个设置? 最好是一个可以自动翻转它的开关,但如果没有,我想我可以在某处读取系统设置并切换到我的代码或其他东西中的备用主题......
没有直接的 API/事件可以从 wpf 检测暗模式或高对比度模式。 这在 uwp 中可用。 但是有一种方法可以通过 WMI 查询来检测主题更改事件,以查看相关注册表项的注册表更改。 您将在此处找到详细信息。 我有一个简化的类,您可以通过它检测注册表更改。
public class ThemeWatcher
{
private const string RegistryKeyPath = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
private const string RegistryValueName = "AppsUseLightTheme";
private static WindowsTheme windowsTheme;
public WindowsTheme WindowsTheme
{
get { return windowsTheme; }
set { windowsTheme = value; }
}
public void StartThemeWatching()
{
var currentUser = WindowsIdentity.GetCurrent();
string query = string.Format(
CultureInfo.InvariantCulture,
@"SELECT * FROM RegistryValueChangeEvent WHERE Hive = 'HKEY_USERS' AND KeyPath = '{0}\\{1}' AND ValueName = '{2}'",
currentUser.User.Value,
RegistryKeyPath.Replace(@"\", @"\\"),
RegistryValueName);
try
{
windowsTheme = GetWindowsTheme();
MergeThemeDictionaries(windowsTheme);
var watcher = new ManagementEventWatcher(query);
watcher.EventArrived += Watcher_EventArrived;
SystemParameters.StaticPropertyChanged += SystemParameters_StaticPropertyChanged;
// Start listening for events
watcher.Start();
}
catch (Exception ex)
{
// This can fail on Windows 7
windowsTheme = WindowsTheme.Default;
}
}
private void MergeThemeDictionaries(WindowsTheme windowsTheme)
{
string appTheme = "Light";
switch (windowsTheme)
{
case WindowsTheme.Light:
appTheme = "Light";
break;
case WindowsTheme.Dark:
appTheme = "Dark";
break;
case WindowsTheme.HighContrast:
appTheme = "HighContrast";
break;
}
App.Current.Resources.MergedDictionaries[0].Source = new Uri($"/Themes/{appTheme}.xaml", UriKind.Relative);
}
private void SystemParameters_StaticPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
windowsTheme = GetWindowsTheme();
MergeThemeDictionaries(windowsTheme);
ThemeChangedArgument themeChangedArgument = new ThemeChangedArgument();
themeChangedArgument.WindowsTheme = windowsTheme;
App.WindowsThemeChanged?.Invoke(this, themeChangedArgument);
}
private void Watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
windowsTheme = GetWindowsTheme();
MergeThemeDictionaries(windowsTheme);
ThemeChangedArgument themeChangedArgument = new ThemeChangedArgument();
themeChangedArgument.WindowsTheme = windowsTheme;
App.WindowsThemeChanged?.Invoke(this, themeChangedArgument);
}
public WindowsTheme GetWindowsTheme()
{
WindowsTheme theme = WindowsTheme.Light;
try
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RegistryKeyPath))
{
object registryValueObject = key?.GetValue(RegistryValueName);
if (registryValueObject == null)
{
return WindowsTheme.Light;
}
int registryValue = (int)registryValueObject;
if (SystemParameters.HighContrast)
theme = WindowsTheme.HighContrast;
theme = registryValue > 0 ? WindowsTheme.Light : WindowsTheme.Dark;
}
return theme;
}
catch (Exception ex)
{
return theme;
}
}
}
为逻辑实现创建真实的枚举:
public enum WindowsTheme
{
Default = 0,
Light = 1,
Dark = 2,
HighContrast = 3
}
将相关资源文件添加到项目中。
定义将在发生注册表更改时通过事件处理程序传递的回调参数。
public class ThemeChangedArgument
{
public WindowsTheme WindowsTheme { set; get; }
}
现在开始观看从 App.xaml.cs 的 OnStartup 方法更改的主题。
public partial class App : Application
{
private ThemeWatcher themeWatcher;
private WindowsTheme systrayTheme = WindowsTheme.Light;
public static EventHandler<ThemeChangedArgument> WindowsThemeChanged;
.......
protected override void OnStartup(StartupEventArgs e)
{
.......................
themeWatcher = new ThemeWatcher();
systrayTheme = themeWatcher.GetWindowsTheme();
themeWatcher.StartThemeWatching();
if(WindowsThemeChanged != null)
{
WindowsThemeChanged -= OnWindowsThemeChanged;
}
WindowsThemeChanged += OnWindowsThemeChanged;
.......................
}
private void OnWindowsThemeChanged(object sender, ThemeChangedArgument e)
{
systrayTheme = e.WindowsTheme;
//Now do whatever you want to do with this updated theme.
}
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
try
{
if (WindowsThemeChanged != null)
{
WindowsThemeChanged -= OnWindowsThemeChanged;
}
Application.Current?.Shutdown();
Process.GetCurrentProcess()?.Kill();
}
catch (Exception ex)
{
}
}
}
注意:由于触发了主题更改事件,我们已经将来自 ThemeWatcher 类的相关样式资源与方法MergeThemeDictionaries()合并。 您也可以根据需要从这里更新它。
调用以下方法以在由于运行时更改资源后更新 UI。
private void InvalidedMainWindow()
{
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.InvokeAsync(() => InvalidedMainWindow());
return;
}
App.Current.MainWindow.UpdateLayout();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.