Ottieni il colore attivo del tema colore automatico di Windows 8

In Windows 8, ho impostato lo schema dei colors su automatico e configurato il mio sfondo per cambiare dopo x minuti. Lo schema dei colors cambia in base allo sfondo attivo.

Sto sviluppando un’applicazione WPF e vorrei che i miei gradienti cambiassero quando Windows cambia lo schema dei colors in modo che corrisponda allo sfondo corrente.

C’è un modo per ottenere la combinazione di colors attuale / attuale ed essere avvisati della modifica in C #?

Si è ansible. Comunque siate avvertiti: questo include un po ‘di interoperabilità di Win32 (questo significa P / Invoca in DLL native dal codice gestito) ed è fattibile solo con alcune API non documentate . Sebbene, le uniche funzionalità non documentate coinvolte siano per ottenere lo schema di colors della finestra (o come il DWM lo chiama, il colore della colorazione della finestra), che è coperto in questa altra domanda:

Vista / 7: come ottenere il colore del vetro?

Nel mio progetto, faccio uso di una chiamata a 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; } 

L’ho provato e funziona perfettamente con Windows 8 e la sua funzione di colorazione automatica delle windows. Come suggerito nel link qui sopra, puoi cercare nel registro i valori dei colors come alternativa a un P / Invoke, ma non ho provato quel metodo, e come dichiarato questi non sono documentati e non sono garantiti come stabili.

Una volta ottenuto il colore per disegnare i pennelli sfumati, i pennelli non si aggiorneranno quando la combinazione di colors della finestra cambia, manualmente o automaticamente da Windows. Fortunatamente, Windows trasmette il messaggio della finestra WM_DWMCOLORIZATIONCOLORCHANGED ogni volta che ciò accade, quindi è sufficiente ascoltare quel messaggio e aggiornare i colors ogni volta che viene inviato. Lo fai agganciando la procedura della finestra ( WndProc() ).

Il valore di WM_DWMCOLORIZATIONCOLORCHANGED è 0x320 ; vorrai definirlo come una costante da qualche parte in modo da poterlo usare nel codice.

Inoltre, a differenza di WinForms, le windows WPF non hanno un metodo WndProc() virtuale per sovrascrivere, quindi è necessario crearne uno e collegarlo come delegato agli handle di finestra associati (HWND).

Prendendo un esempio di codice da queste mie risposte:

  • Come faccio a rendere mobile una finestra WPF trascinando la cornice della finestra estesa?
  • Rileva il cambiamento del tema del sistema in WPF

Abbiamo:

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

Quando Windows trasferisce la modifica del colore, WM_DWMCOLORIZATIONCOLORCHANGED viene inviato ad ogni fotogramma chiave nella transizione, quindi riceverai numerosi messaggi con una breve interruzione durante il cambio colore. E ‘normale; semplicemente aggiorna i pennelli sfumati come al solito e noterai che quando Windows passa dallo schema dei colors della finestra, i tuoi gradienti passeranno uniformsmente insieme al resto dei fotogrammi delle windows.

Ricordare che potrebbe essere necessario tenere conto di situazioni in cui DWM non è disponibile, ad esempio quando si esegue Windows XP o quando si esegue Windows Vista o versioni successive con composizione desktop disabilitata. Inoltre, devi assicurarti di non utilizzarlo eccessivamente, altrimenti potresti incorrere in un notevole calo delle prestazioni e rallentare la tua app.

Questo può essere fatto in .NET 4.5 e versioni successive senza P / Invokes. La class SystemParameters ora ha proprietà statiche WindowGlassBrush e WindowGlassColor insieme a un evento StaticPropertyChanged .

Da XAML, puoi associare alla proprietà WindowGlassBrush come:

  

Tuttavia, con questo compito il colore di sfondo non verrà aggiornato automaticamente quando Windows cambia colore. Sfortunatamente, SystemParameters non fornisce le proprietà WindowGlassBrushKey o WindowGlassColorKey da utilizzare come ResourceKeys con DynamicResource, quindi ottenere le notifiche di modifica richiede il codice behind per gestire l’evento 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(); } } }