Get active color in Windows 8 auto color theme

In Windows 8, I set the color scheme to automatically configure and set my wallpaper to change after x minutes. The color scheme changes depending on the active wallpaper.

I am developing a WPF application and want my gradients to change when Windows changes the color scheme to match the current wallpaper.

Is there a way to get the current / actual color scheme and get notified of a change in C #?

+18
c # winapi windows-8 wpf
Dec 01 '12 at 15:44
source share
2 answers

Yes it is possible. However, be careful: this includes quite a lot of Win32 interop (this means that P / calls into its own DLLs from managed code) and only works with some undocumented APIs . Although the only undocumented functions are to get the color scheme of the window (or, as DWM calls it, the color of the window's coloring), which is discussed in this other question:

Vista / 7: How to get glass color?

In my own project, I use the call to 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; } 

I tested it and it works great with Windows 8 and its auto window coloring feature. As suggested in the link above, you can look in the registry for color values ​​as an alternative to P / Invoke, but I have not tested this method, and as indicated, they are undocumented and are not guaranteed to be stable.

As soon as you get the color for drawing your gradient brushes, the brushes will not be updated when the color scheme of the window changes, whether manually or automatically by Windows. Fortunately, Windows broadcasts a WM_DWMCOLORIZATIONCOLORCHANGED window message whenever this happens, so you just need to listen to this message and update your colors whenever it is sent, you do this by connecting to the window procedure ( WndProc() ).

The value of WM_DWMCOLORIZATIONCOLORCHANGED is 0x320 ; you want to define this as a constant somewhere so you can use it in your code.

In addition, unlike WinForms, WPF windows do not have a virtual WndProc() method to override, so you need to create and connect it as a delegate to its associated windows (HWND).

Taking some sample code from my answers:

  • How to make a WPF window movable by dragging and dropping an extended window frame?
  • Detect system theme change in WPF

We have:

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

When Windows switches to a color change, WM_DWMCOLORIZATIONCOLORCHANGED sent on each keyframe of the transition, so when you change color, you get numerous messages with a short burst. This is normal; just refresh your gradient brushes as usual, and you will notice that when Windows moves to the window color scheme, your gradients will move smoothly along with the rest of the window frames.

Remember that you may need to consider situations where DWM is not available, for example, when working in Windows XP or when working in Windows Vista or later with the desktop turned off. You will also want that you do not abuse it, or you may encounter significant success and slow down your application.

+15
Dec 02
source share

This can be done in .NET 4.5 and later without P / Invokes. The SystemParameters class now has a static WindowGlassBrush and WindowGlassColor along with the StaticPropertyChanged event.

From XAML, you can bind to the WindowGlassBrush property, for example:

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

However, for this purpose, the background color will not automatically update when Windows changes its colors. Unfortunately, SystemParameters does not provide the WindowGlassBrushKey or WindowGlassColorKey properties for use as ResourceKeys with DynamicResource, so you need code to handle the StaticPropertyChanged event to receive change notifications.

 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(); } } } 
+11
Jan 20 '14 at 2:39
source share



All Articles