作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
Windows 10 最近添加了深色模式;有没有办法让我的 WPF 应用程序尊重这个设置?最好是一个可以自动翻转它的开关,但如果没有,我想我可以在某处读取系统设置并切换到我的代码或其他东西中的备用主题......
最佳答案
没有直接的 API/事件可以从 wpf 检测暗模式或高对比度模式。这在 uwp 中可用。但是有一种方法可以通过 WMI 查询来检测主题更改事件,以查看相关注册表项的注册表更改。您会找到详细信息 here .
我有一个简化的类,您可以通过它检测注册表更改。
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() 由于主题改变事件被触发。您也可以根据需要从这里更新它。
private void InvalidedMainWindow()
{
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.InvokeAsync(() => InvalidedMainWindow());
return;
}
App.Current.MainWindow.UpdateLayout();
}
关于c# - 有没有办法让 WPF 应用程序尊重 Windows 10 中暗/亮主题的系统选择?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59366391/
我是一名优秀的程序员,十分优秀!