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: 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.