检测WPF中的系统主题更改

时间:2011-06-15 15:56:55

标签: c# .net wpf winapi dwm

对于我的WPF应用程序,我需要检测DWM何时打开/关闭或系统主题何时更改。
在WinForms中有这样的事件,但我在WPF中看不到任何事件。

3 个答案:

答案 0 :(得分:7)

我还没有听说过WinForms窗口从系统接收消息时会触发的 WinForms事件,但是它有自己的WndProc()方法可以覆盖。你可能会混淆表单事件的窗口消息。啊,所以它是在WinForms窗口中调用的StyleChanged事件。我的其余部分仍然有效。

WPF与Windows API没有密切联系,因为它是一种高级技术,可以从内部投入大量抽象。首先,它在窗口中单独绘制所有,并且不要求系统为它绘制图形(编辑:>这就是为什么WPF缺少这样的{ {1}}事件)。也就是说,当切换DWM并且主题发生变化时,Windows会向所有窗口发送消息,您仍然可以从WPF层向下钻取到低级别以访问这些消息并相应地操作WPF控件。

将窗口过程作为窗口StyleChanged事件的一部分附加到WPF窗口的HWND(窗口句柄)。在窗口过程中,分别处理WM_DWMCOMPOSITIONCHANGEDWM_THEMECHANGED窗口消息。

这是一个简单的例子(样板代码改编自this question of mine):

SourceInitialized

答案 1 :(得分:2)

事件SystemEvents.UserPreferenceChanged也可以解决问题。 UserPreferenceChanged(in Japaense)

答案 2 :(得分:1)

不幸的是,已接受的解决方案不适用于Aero颜色主题更改,并且WM消息十六进制数字混淆了 - 但我同意如果您想在WPF中捕获WM消息,它非常有用。我一直试图找到这个问题的解决方案,我想我已经解决了所有可能的情况(对于航空和经典主题)。

Aero颜色更改会触发WM_DWMCOLORIZATIONCOLORCHANGED消息。

要检测颜色主题何时更改,您必须使用多种方法。 Form.StyleChanged事件将检测所有主题更改,除了Aero颜色更改。这是StyleChanged的替代解决方案。 (好吧,我知道这是WinForms,但你已经有了这个想法。无论如何,WPF等价物都在接受的答案中。)

    private const int WM_DWMCOLORIZATIONCOLORCHANGED = 0x320;
    private const int WM_DWMCOMPOSITIONCHANGED = 0x31E;
    private const int WM_THEMECHANGED = 0x031A;

    protected override void WndProc(ref Message m)
    {
        switch(m.Msg)
        {
            case WM_DWMCOLORIZATIONCOLORCHANGED:
            case WM_DWMCOMPOSITIONCHANGED:
            case WM_THEMECHANGED:
                // you code here
                break;
            default:
                break;
        }
        base.WndProc(ref m);
    }

对于Aero颜色主题,SystemEvents.UserPreferenceChanged事件也可以工作(谢谢看!):

    Microsoft.Win32.SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;

    private void SystemEvents_UserPreferenceChanged(object sender, Microsoft.Win32.UserPreferenceChangedEventArgs e)
    {
        if (e.Category == Microsoft.Win32.UserPreferenceCategory.General)
        {
            // your code here, compare saved theme color with current one
        }
    }

正如您在上面所看到的,它远非直观。航空颜色变化会触发“通用”。偏好更改事件,即使有更多适合的事件,例如' VisualStyle'等...

如果你想彻底,你应该将保存的DWM颜色与当前的DWM颜色进行比较,以确保它确实是一个触发此事件的Aero颜色主题(使用DwmGetColorizationParameters API调用),而不是其他东西。有关如何检索Aero颜色,请参阅以下答案: Get the active color of Windows 8 automatic color theme