对于我的WPF应用程序,我需要检测DWM何时打开/关闭或系统主题何时更改
WinForms中有这样一个事件,但我在WPF中看不到。
WndProc()
方法,您可以覆盖它。您可能混淆了窗体事件的窗口消息StyleChanged
事件。不过,我的其余回答仍然有效。
WPF也与Windows API没有紧密联系,因为它是一种高级技术,在内部投入了大量抽象。首先,它自己在窗口中绘制所有,并且不要求系统为其绘制(EDIT:这就是WPF缺少StyleChanged
事件的原因)。也就是说,当DWM切换和主题更改时,Windows会向所有窗口发送消息,并且您仍然可以从WPF层深入到低级别以访问这些消息并相应地操作您的WPF控件。
将窗口过程附加到WPF窗口的HWND(窗口句柄),作为窗口的SourceInitialized
事件的一部分。在窗口过程中,分别处理WM_DWMCOMPOSITIONCHANGED
和WM_THEMECHANGED
窗口消息。
这里有一个快速的例子(根据我的这个问题改编的样板代码):
private IntPtr hwnd;
private HwndSource hsource;
private const int WM_DWMCOMPOSITIONCHANGED= 0x31E;
private const int WM_THEMECHANGED = 0x31A;
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:
case WM_THEMECHANGED:
// Respond to DWM being enabled/disabled or system theme being changed
return IntPtr.Zero;
default:
return IntPtr.Zero;
}
}
不幸的是,接受的解决方案不适用于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
}
}
正如您在上面所看到的,这远远不是直观的。Aero颜色变化会触发"常规"偏好变化事件,尽管有许多更适合的事件,如"VisualStyle"等。
如果您想更彻底,您应该将保存的DWM颜色与当前DWM颜色进行比较,以确保触发此事件的确实是Aero颜色主题(使用DwmGetColorizationParameters API调用),而不是其他内容。请参阅以下关于如何检索Aero颜色的答案:获取Windows 8自动颜色主题的活动颜色
事件SystemEvents.UserPreferenceChanged也起到了作用。UserPreferenceChanged(日语)