有没有办法让 WPF 应用程序尊重 Windows 10 中深色/浅色主题的系统选择?

2024-04-03

Windows 10最近添加了深色模式;有什么方法可以让我的 WPF 应用程序尊重此设置吗?最好是一个可以自动翻转它的开关,但如果没有,我想我可以在某处读取系统设置并切换到我的代码或其他东西中的备用主题......


没有直接的 API/事件来检测 wpf 的暗模式或高对比度模式。可以在 uwp 中找到。但是有一种方法可以通过 WMI 查询来检测主题更改事件,以观察相关注册表项的注册表更改。你会发现详情here https://engy.us/blog/2018/10/20/dark-theme-in-wpf/。 我有一个简化的类,您可以通过它检测注册表更改。

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;
        }
    }
}

创建相关的Enum进行逻辑实现:

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 类中的相关样式资源与该方法合并合并主题字典()由于主题更改事件被触发。您也可以根据您的需要从这里更新它。

由于运行时资源发生变化后,调用以下方法来更新 UI。

    private void InvalidedMainWindow()
    {
        if (!Application.Current.Dispatcher.CheckAccess())
        {
            Application.Current.Dispatcher.InvokeAsync(() => InvalidedMainWindow());
            return;
        }

        App.Current.MainWindow.UpdateLayout();
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有没有办法让 WPF 应用程序尊重 Windows 10 中深色/浅色主题的系统选择? 的相关文章

  • 什么定义了类型的大小?

    ISO C 标准规定 sizeof char lt sizeof short lt sizeof int lt sizeof long 我在 BIT Linux mint 19 1 上使用 GCC 8 大小为long int is 8 我正
  • 需要帮助处理 Application.xaml 文件中的 DataTemplate 事件

    我的应用程序中有一个包含几个按钮的数据模板 我希望这些按钮的偶数处理程序在当前页面 我在许多页面中使用此模板 而不是在 Application xaml vb cs 文件中触发 因为我希望在每个页面上执行不同的操作 我希望我说清楚了 您可以
  • 无法使用c#更改视频捕获分辨率

    我正在尝试使用 C 中的 DirectShowNet 更改默认网络摄像头分辨率 据我所知 我需要通过调用 windows win32 api dll 中内置的 VideoInfoHeader 类来更改它以进行 avi 捕获 我有来自 Dir
  • 采用 std::vector 或 std::array 的模板函数

    我有一个函数 当前接受 2 个向量 其中可以包含任何普通的旧数据 template
  • 在 WCF 上重用我的 PagedList 对象

    问题 我有一个自定义集合PagedList
  • 如何通过覆盖 MSBuild 目标来防止外语资源生成?

    我正在致力于减少大型 C ASP NET 解决方案的编译时间 我们的解决方案使用通常的 resx 文件方法翻译成大约十几种外语 这些资源文件的解析和编译极大地减慢了我们的编译时间 并且是日常的挫败感 我知道可以创建自定义资源提供程序并摆脱
  • 信号与信号2

    我的应用程序可能会受益于使用 boost 的信号库之一而不是本土解决方案 该应用程序是多线程的 但执行信号处理的部分是单线程的 如果多线程不是问题 是否有任何理由更喜欢 Boost Signals2 而不是 Boost Signal Boo
  • 头文件中实现的函数的静态与内联

    我想到的方式inline在 C 中用于链接 作用域 我把它放在同一个篮子里extern and static对于全局对象 通常 对于在头文件中实现的函数 我的首选解决方案是将其设为静态 In Foo h static void foo Do
  • C# 中类似图的实现

    所以我有一个对象 我们称之为 Head 它有一个对象列表 C C1 C2 C3 T T1 T2 和 M M1 M2 并且所有这些都是相互关联的 例如 Head gt C1 C2 C3 T1 T2 M1 M2 T1 gt C1 C2 T2 g
  • Winform DatagridView 数字列排序

    我只使用一个简单的 DataGridView 来保存一堆数据 有趣的是 我在特定列中有小数 但是当按小数列排序时 它的排序是错误的 例如 起始顺序可能是 0 56 3 45 500 89 20078 90 1 56 100 29 2 39
  • 如何从不同的线程访问控件?

    如何从创建控件的线程以外的线程访问控件 避免跨线程错误 这是我的示例代码 private void Form1 Load object sender EventArgs e Thread t new Thread foo t Start p
  • 从内存流播放视频文件

    只是好奇看看这是否可能 我有一个 Windows 应用程序 它从我的电脑上的 avi 文件读取所有字节 然后将其存储在 byte 中 现在我的内存中有 avi 文件 我想直接从内存将其加载到某种视频播放器控件中 我尝试过使用 wmplaye
  • 如何在 Visual Basic DLL 和 C++ DLL 之间创建隔离/免注册 COM?

    我必须在 C DLL 中使用 VB COM DLL 我弄清楚了如何从 C DLL 访问 VB COM DLL 并且它可以工作 现在我遇到了一个问题 我必须使用隔离的 COM 免注册 COM 因为我无法在必须使用它的每台 PC 上注册 DLL
  • FluentAssertions ShouldNotThrow 无法识别异步方法/Func

    我正在尝试检查异步方法是否抛出具体异常 为此 我使用 MSTEST 和 FluentAssertions 2 0 1 我已经检查过这个关于 Codeplex 的讨论 http fluentassertions codeplex com wo
  • 检测反射 DLL 注入

    在过去的几年中 恶意软件 以及一些渗透测试工具 如 Metasploit 的 meterpreter 负载 已经开始使用反射 DLL 注入 PDF http www harmonysecurity com files HS P005 Ref
  • ASP.NET MVC 动作过滤器

    有谁知道即使在 CATCH 块中 ActionFilterAttribute 类的 OnResultExecuted 方法是否也会执行 ie CookiesActions public ActionResult Login Usuarios
  • 节点*链表中的下一个

    我是数据结构和算法的新手 我遇到了以下代码 typedef struct node int data node next 谁能告诉我为什么我们要声明节点 next next 不能声明为 int next 吗 因为你希望能够做到n gt ne
  • C - 获取外部IP地址

    我需要通过 C C 调用获取我的公共 IP 地址 我知道作为替代方案 我可以从 http whatismyip akamai com 等外部链接获取 我写了一个示例来获取外部IP地址 但我的程序没有返回外部 IP 地址 我正在获取内部 IP
  • 在 C# 中使用自定义千位分隔符

    在显示字符串时 我尝试不使用 字符作为千位分隔符 而是使用空格 我想我需要定义一种自定义文化 但我似乎做得不对 有什么指点吗 例如 将 1000000 显示为 1 000 000 而不是 1 000 000 no String Replac
  • 创建进程默认浏览器

    我目前正在使用 ShellExecute 打开 在用户浏览器中打开 URL 但在 Win7 和 Vista 中遇到了一些麻烦 因为该程序作为服务运行提升 我想获取线程 id 因此 ShellExecute 无法获取线程 id 因此我开始使用

随机推荐

  • 过滤出现在两个标记之间的文本

    Part 1 创建仅输出由两个预定义标记包围的文本的文本过滤器的最简单方法是什么 我不介意使用任何标准工具 sed awk python 例如 我希望只显示由 标记开始 和 标记结束 包围的文本 input Text 1 Mark Begi
  • 如何使用标头和数据创建对服务器的 javascript POST 请求

    我使用 JS 自动化框架来测试 iOS 应用程序 在测试过程中 我需要向服务器创建 POST 请求 向用户发送一些钱 然后验证更改是否反映在 UI 中 请求如下 wwww testserver com userAddMoney user i
  • 将 Laravel 请求中的数组值转换为整数

    我想要array diff Laravel 中的两个数组 第一个数组如下所示 array 4 0 gt 7248 1 gt 7249 2 gt 7250 3 gt 7251 第二个 array 4 0 gt 7248 1 gt 7249 2
  • 在 R 中裁剪光栅

    我正在绘制美国东北部的地图 地图背景需要是海拔图或年平均温度图 我有来自 Worldclim org 的两个栅格 它们为我提供了这些变量 但我需要将它们裁剪到我感兴趣的状态范围 有关如何执行此操作的任何建议 这是我到目前为止所拥有的 loa
  • MySQL:索引可变长度的json数组?

    我想做一个tags类型列json e g id tags 1 tag1 tag2 tag3 2 tag1 tag3 tag5 tag7 3 tag2 tag5 我想为每个索引tag在数组中 不知道数组的长度 可变长度 那么如果我查询包含的行
  • 将大量数据从 NIST 更改为 RIFF wav 文件

    所以 我正在编写一个语音识别程序 为此 我从 TIMIT 下载了 400MB 的数据 当我打算读取 wav 文件时 我尝试了两个库 如下所示 import scipy io wavfile as wavfile import wave fs
  • 向客户展示应用程序的测试版

    我可以向客户发送可以在模拟器中运行的 iOS 应用程序的测试版吗 我可以在 Mac 上仅安装模拟器 不带 Xcode 吗 实际上 我需要一种有效的方法来向他发送应用程序的测试版 而不必在每次更新时与他见面 另外 3 有没有办法安装我在 iO
  • 当指定 -g 时,gcc 会定义什么吗?

    很快 我想知道 gcc 或 g 我需要它C 但也对 c 感到好奇 定义了任何特殊符号 如果 g已启用 可以 如果是的话 是什么符号 在搜索过程中我发现 DEBUG是手动定义的 手动我的意思是 D DEBUG 并且是 Visual C 程序员
  • 如何列出 docker 容器中包含的所有应用程序?

    我已经下载了一个 docker 容器 它使用几种不同类型的软件对输入文件执行多种不同的操作 即对齐 变体调用等 如何找出 docker 容器 图像的内容是什么 抱歉 如果这是微不足道的 我对 docker 完全陌生 有 至少 三种方式来解释
  • 错误:尝试在主机“localhost:27017”上运行命令“saslStart”时出现网络错误

    当我跑步时mongo我可以使用列出数据库show dbs命令 并执行写入和读取操作 但是当使用客户端 Robot 3T 时 我收到下一个错误 Error Network error while attempting to run comma
  • Python - 使用线程或队列迭代调用函数的 for 循环

    我对 python 相当陌生 正在制作一个脚本 允许将其他程序的点云数据引入 Autodesk Maya 我的脚本运行良好 但我想做的是让它更快 我有一个 for 循环 它遍历编号文件的列表 IE datafile001 txt dataf
  • 兑换代币代码 facebook-c#-sdk

    我正在使用 Facebook C Sdk v5 0 3 在 vb net 中创建一个非画布 Web 表单应用程序 但在将返回的 facebook 代码交换为 access token 时遇到问题 有人有我可以看的示例 C 或 vb net
  • 在 WooCommerce 管理新订单自定义字段中加载用户自定义数据

    灵感来自Woocommerce 可编辑自定义结帐字段和 get formatted shipping address https stackoverflow com questions 61522677 woocommerce editab
  • apache poi:如何创建带有条形图和折线图的图表?

    是否可以在 apache poi 中创建一个包含条形图和折线图的图表 你可以找个例子here https blogs office com en us 2012 06 21 combining chart types adding a se
  • 填充网络表单的最佳日历弹出窗口是什么?

    我希望能够在选择日期后进行 HTTP 调用来更新某些选择框 我希望能够控制更新文本框 以便我知道何时发生 真正的 更改 如果选择了相同的日期 理想情况下 我会调用一个函数来弹出日历 并能够在填充文本框之前评估日期 这样我就可以在进行服务器调
  • 将多个项目放在相对布局中居中而不将它们放入容器中?

    我有一个包含一对并排按钮的相对布局 我希望它们在布局中居中 我可以将按钮放在 LinearLayout 中并将其居中放在relativelayout 中 但我想保持 xml 尽可能干净 这是我尝试过的 这只是将 应用 按钮放在中间 将 撤消
  • 添加具有现有列名称的新列

    我正在处理一个数据框 如下所示 FID geometry Code w1 w2 0 12776 POLYGON 1 350000000000025 53 61540813717482 12776 0 1 1 13892 POLYGON 6
  • 在基本层面上,eval-parse 在 R 中做什么?

    我已经看到在循环或 apply 函数中使用 eval parse 的参考 但我仍然不清楚如何使用它 为了帮助像我这样的初学者理解它 有人可以解释为什么下面的第一部分 没有 eval parse 有效 而第二部分 有它 不起作用 这是 eva
  • Poetry能否根据对应C库的版本自动选择包版本

    我将使用 GDAL 作为具体示例 为了安装gdalPython 包 您必须先安装 GDAL C 库 您还必须安装 Python 版本gdal以匹配您安装的 C 库的版本 gdal config version 3 2 0 lt this i
  • 有没有办法让 WPF 应用程序尊重 Windows 10 中深色/浅色主题的系统选择?

    Windows 10最近添加了深色模式 有什么方法可以让我的 WPF 应用程序尊重此设置吗 最好是一个可以自动翻转它的开关 但如果没有 我想我可以在某处读取系统设置并切换到我的代码或其他东西中的备用主题 没有直接的 API 事件来检测 wp