在WPF中检测系统主题更改

| 对于WPF应用程序,我需要检测DWM何时打开/关闭或系统主题何时更改。 WinForms中有这样的事件,但是我在WPF中看不到任何事件。     
已邀请:
        我还没有听说过WinForms窗口从系统接收消息时将触发的WinForms事件,但是它具有自己的own0ѭ方法,您可以重写该方法。您可能会混淆窗体事件的窗口消息。嗯,这就是WinForms窗口中调用的“ 1”事件。我其余的答案仍然存在。 WPF与Windows API也不紧密相关,因为它是一种高级技术,它从内部进行了大量的抽象投资。例如,它自己在窗口中绘制所有内容,并且不要求系统为其绘制图像(编辑:这就是WPF缺少此类
StyleChanged
事件的原因)。也就是说,当切换DWM和更改主题时,Windows会将消息发送到所有窗口,并且您仍然可以从WPF层深入到低级别以访问这些消息并相应地操纵WPF控件。 作为窗口的window3ѭ事件的一部分,将窗口过程附加到WPF窗口的HWND(窗口句柄)。在您的窗口过程中,分别处理
WM_DWMCOMPOSITIONCHANGED
WM_THEMECHANGED
窗口消息。 这是一个简单的示例(根据我的问题改编了样板代码):
private IntPtr hwnd;
private HwndSource hsource;

private void Window_SourceInitialized(object sender, EventArgs e)
{
    if ((hwnd = new WindowInteropHelper(this).Handle) == IntPtr.Zero)
    {
        throw new InvalidOperationException(\"Could not get window handle.\");
    }

    hsource = HwndSource.FromHwnd(hwnd);
    hsource.AddHook(WndProc);
}

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    switch (msg)
    {
        case WM_DWMCOMPOSITIONCHANGED: // Define this as 0x31A
        case WM_THEMECHANGED:          // Define this as 0x31E

            // Respond to DWM being enabled/disabled or system theme being changed

            return IntPtr.Zero;

        default:
            return IntPtr.Zero;
    }
}
    
        事件SystemEvents.UserPreferenceChanged也可以解决问题。 UserPreferenceChanged(在Japaense中)     
        不幸的是,已接受的解决方案不适用于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
        }
    }
正如您在上面看到的,它远非直观。航空颜色更改会触发\'General \'偏好更改事件,即使还有很多更适合的选项,例如\'VisualStyle \'等。 如果要更彻底,则应将保存的DWM颜色与当前DWM颜色进行比较,以确保确实是触发此事件的Aero颜色主题(使用DwmGetColorizationParameters API调用),而不是其他事件。请参阅以下有关如何检索Aero颜色的答案: 获取Windows 8自动颜色主题的活动颜色     

要回复问题请先登录注册