获取Windows 8自动颜色主题的活动颜色

在Windows 8中,我已将颜色scheme设置为自动,并在x分钟后将我的壁纸configuration为更改。 配色scheme根据活动壁纸而改变。

我正在开发一个WPF应用程序,并希望当Windows更改颜色scheme以匹配当前壁纸时我的渐变。

有没有办法获得当前/实际的配色scheme,并通知在C#中的变化?

是的,这是可能的。 不过要注意的是:这包含了很多Win32的互操作(这意味着P /从托pipe代码中调用本地DLL),并且只能用于某些未公开的API 。 虽然,涉及的唯一未logging的function是获取窗口颜色scheme(或DWM称之为窗口着色颜色),这是另一个问题中所涉及的:

Vista / 7:如何获得玻璃颜色?

在我自己的项目中,我使用了对DwmGetColorizationParameters()的调用:

 internal static class NativeMethods { [DllImport("dwmapi.dll", EntryPoint="#127")] internal static extern void DwmGetColorizationParameters(ref DWMCOLORIZATIONPARAMS params); } public struct DWMCOLORIZATIONPARAMS { public uint ColorizationColor, ColorizationAfterglow, ColorizationColorBalance, ColorizationAfterglowBalance, ColorizationBlurBalance, ColorizationGlassReflectionIntensity, ColorizationOpaqueBlend; } 

我已经testing过了,它可以在Windows 8及其自动窗口着色function下使用。 正如在上面的链接中所build议的,你可以在registry中查找颜色值作为P / Invoke的替代方法,但是我没有testing过这个方法,并且如上所述,这些方法没有logging,也不能保证稳定。

一旦获得用于绘制渐变画笔的颜色,当窗口颜色scheme更改时,画笔将不会更新,无论手动还是自动通过Windows。 值得庆幸的是,无论什么时候,Windows都会广播WM_DWMCOLORIZATIONCOLORCHANGED窗口消息 ,所以只需要听取消息并在发送时更新颜色。 通过挂钩到窗口过程( WndProc() )来做到这一点。

WM_DWMCOLORIZATIONCOLORCHANGED的值是0x320 ; 你会想把它定义为一个常量,所以你可以在代码中使用它。

此外,与WinForms不同,WPF窗口没有虚拟的WndProc()方法来覆盖,因此您必须创build一个代理并将其挂接到相关的窗口句柄(HWND)。

以我的这些答案为例:

  • 如何通过拖动扩展窗口框架来移动WPF窗口?
  • 检测WPF中的系统主题更改

我们有:

 const int WM_DWMCOLORIZATIONCOLORCHANGED = 0x320; 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 static Color GetWindowColorizationColor(bool opaque) { var params = NativeMethods.DwmGetColorizationParameters(); return Color.FromArgb( (byte)(opaque ? 255 : params.ColorizationColor >> 24), (byte)(params.ColorizationColor >> 16), (byte)(params.ColorizationColor >> 8), (byte) params.ColorizationColor ); } private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case WM_DWMCOLORIZATIONCOLORCHANGED: /* * Update gradient brushes with new color information from * NativeMethods.DwmGetColorizationParams() or the registry. */ return IntPtr.Zero; default: return IntPtr.Zero; } } 

当Windows转换颜色更改时, WM_DWMCOLORIZATIONCOLORCHANGED将在转换中的每个关键帧WM_DWMCOLORIZATIONCOLORCHANGED派,因此在颜色更改期间您将在短时间内收到大量消息。 这个是正常的; 只是像往常一样更新你的渐变画笔,你会注意到,当Windows转换窗口颜色scheme时,您的渐变将与其他窗口框架顺利过渡。

请记住,您可能需要考虑DWM不可用的情况,例如在Windows XP上运行时,或者在Windows Vista或更高版本上运行时禁用桌面合成。 您还需要确保不会过度使用此function,否则可能会导致重大的性能下降,从而使您的应用程序变慢。

这可以在.NET 4.5及更高版本中完成,无需P / Invokes。 SystemParameters类现在具有静态WindowGlassBrush和WindowGlassColor属性以及一个StaticPropertyChanged事件。

从XAML,您可以绑定到WindowGlassBrush属性,如:

 <Grid Background="{x:Static SystemParameters.WindowGlassBrush}"> 

但是,使用此分配时,Windows更改其颜色时,背景颜色不会自动更新。 不幸的是,SystemParameters不提供WindowGlassBrushKeyWindowGlassColorKey属性作为ResourceKeys与DynamicResource一起使用,因此获取更改通知需要隐藏代码来处理StaticPropertyChanged事件。

 public partial class MainWindow : Window { public MainWindow() { this.InitializeComponent(); SystemParameters.StaticPropertyChanged += this.SystemParameters_StaticPropertyChanged; // Call this if you haven't set Background in XAML. this.SetBackgroundColor(); } protected override void OnClosed(EventArgs e) { SystemParameters.StaticPropertyChanged -= this.SystemParameters_StaticPropertyChanged; base.OnClosed(e); } private void SetBackgroundColor() { this.Background = SystemParameters.WindowGlassBrush; } private void SystemParameters_StaticPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (e.PropertyName == "WindowGlassBrush") { this.SetBackgroundColor(); } } }