2012-12-01 13 views
18

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

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

C'è un modo per ottenere lo schema di colori attuale/attuale e ricevere una notifica della modifica in C#?

+0

Questo include un po 'di interoperabilità ed è possibile solo con alcune * API non documentate *. In effetti, l'ho fatto con il mio progetto per Windows Vista/7, e l'ho testato con successo su Windows 8. Posso provare a mettere insieme una risposta basata su questo, ma mi servirà un po 'di tempo. Vedi anche: [Vista/7: Come ottenere il colore del vetro?] (Http://stackoverflow.com/questions/3560890/vista-7-how-to-get-glass-color) – BoltClock

+0

Grazie mille per l'informazione . Ho usato il trucco del registro e funziona benissimo. – user1868880

risposta

15

Sì, è possibile. Tuttavia sii avvisato: questo include un po 'di interoperabilità di Win32 (questo significa P/Invoca in DLL native dal codice gestito) ed è eseguibile solo con alcune API prive di documenti. Anche se, le uniche caratteristiche non documentate coinvolti sono per ottenere lo schema di colore della finestra (o come il DWM lo chiama, il colore della finestra colorazione), che è coperto in quest'altra domanda:

Vista/7: How to get glass color?

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

ho provato e funziona benissimo con Windows 8 e la sua funzione automatica finestra colorazione. Come suggerito nel link qui sopra, puoi cercare nel registro i valori dei colori 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 colori della finestra cambia, manualmente o automaticamente da Windows. Fortunatamente, Windows trasmette lo WM_DWMCOLORIZATIONCOLORCHANGED window message ogni volta che ciò accade, quindi è sufficiente ascoltare quel messaggio e aggiornare i colori 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 finestre WPF non hanno un metodo virtuale WndProc() da sovrascrivere, quindi è necessario crearne uno e collegarlo come delegato agli handle di finestra associati (HWND).

Prendendo qualche esempio di codice da queste risposte miei:

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 transizione il cambiamento di colore, WM_DWMCOLORIZATIONCOLORCHANGED è spedito ad ogni keyframe durante la transizione, quindi riceverai numerosi messaggi con una breve interruzione durante il cambio di colore. E 'normale; semplicemente aggiorna i pennelli sfumati come al solito e noterai che quando Windows passa dallo schema dei colori della finestra, i tuoi gradienti passeranno uniformemente insieme al resto dei fotogrammi delle finestre.

Ricordare che potrebbe essere necessario tenere conto di situazioni in cui il DWM non è disponibile, ad esempio quando si esegue su Windows XP o quando si esegue su 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.

+2

E questa è la mia prima risposta a Windows 8 postata da ... Windows 8. Non troppo squallido ... – BoltClock

+0

Whoa, 202k punti: D –

+0

Oh ragazzo, ho appena trovato il mio commento di 3 anni fa. : O –

11

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

Da XAML, è possibile associare alla proprietà WindowGlassBrush come:

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

Tuttavia, con questo incarico il colore di sfondo non viene aggiornata automaticamente all'avvio di Windows cambia i suoi colori. Purtroppo, SystemParameters fa non forniscono WindowGlassBrushKey o WindowGlassColorKey oggetti da utilizzare come ResourceKeys con DynamicResource, in modo da ottenere le notifiche di modifica richiede codice dietro 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(); 
     } 
    } 
} 
+0

La proprietà SystemParameters.WindowGlassColor nel Il framework .NET 4.5 avvolge semplicemente DwmGetColorizationColor –

+0

Sto utilizzando questa proprietà all'interno di un modello, esiste un modo per aggiornare il modello per sostituire il vecchio colore con uno nuovo? –

+0

Purtroppo, SystemParameters.WindowGlassBrush non restituirà il colore dell'accento corretto, almeno è diverso sulla mia macchina. Io uso questo codice: https://gist.github.com/paulcbetts/3c6aedc9f0cd39a77c37 –

Problemi correlati