2012-12-01 12 views
18

Windows 8では、カラースキームを自動的に設定し、x分後に変更するように壁紙を設定しました。アクティブな壁紙に応じて配色が変わります。Windows 8の自動カラーテーマのアクティブカラーを取得

私はWPFアプリケーションを開発しています。Windowsが現在の壁紙に合わせて配色を変更したときにグラデーションを変更したいと考えています。

現在の/実際の配色を取得し、C#の変更を通知する方法はありますか?

+0

これはかなりのinteropを含み、特定の*文書化されていないAPI *でのみ実行可能です。実際には、Windows Vista/7用の独自のプロジェクトでこれを行い、Windows 8で正常にテストしました。これに基づいて回答をまとめようとしていますが、しばらくはかかるでしょう。参照:[Vista/7:ガラスの色を取得する方法](http://stackoverflow.com/questions/3560890/vista-7-how-to-get-glass-color) – BoltClock

+0

ありがとうございます。私はレジストリのトリックを使用し、それは素晴らしい動作します。 – user1868880

答えて

15

はい、可能です。ただし、これはかなりのWin32 interop(これはP /管理されたコードからのネイティブDLLへの呼び出しを意味します)を含み、は特定の文書化されていないAPIでしか実行できませんです。が、関与する唯一の文書化されていない機能は、ウィンドウのカラースキーム(またはDWMはそれを呼び出すように、窓のカラー化色)この他の質問に覆われて、取得するために、次のとおりです。私自身のプロジェクトで

Vista/7: How to get glass color?

を、

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

私はそれをテストしてみたし、それは、Windows 8とその自動窓のカラー化機能と素晴らしい作品:私はDwmGetColorizationParameters()への呼び出しを使用しています。上記のリンクで提案されているように、P/Invokeの代わりにレジストリで色の値を調べることはできますが、その方法はテストされていません。これらは文書化されていないため、安定しているとは限りません。

グラデーションブラシを描画するための色を取得すると、Windowsによって手動または自動で、ウィンドウのカラースキームが変更されたときにブラシが更新されません。ありがたいことにWindowsはWM_DWMCOLORIZATIONCOLORCHANGED window messageをブロードキャストします。そのメッセージが届くとそのメッセージを聞いて色を更新するだけです。これは、ウィンドウプロシージャ(WndProc())にフックすることで行います。

WM_DWMCOLORIZATIONCOLORCHANGEDの値は0x320です。それをコードの中で使うことができるように、どこかで定数として定義したいと思うでしょう。

また、WinFormsとは異なり、WPFウィンドウには仮想のWndProc()メソッドがありません。そのため、関連付けられたウィンドウハンドル(HWND)へのデリゲートとして作成およびフックする必要があります。我々が持っている

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がある鉱山のこれらの答えからいくつかのサンプルコードを撮影

あらゆるキーフレームで派遣されるトランジションでは、色の変更中に短いバーストで多数のメッセージを受信します。これは正常です;通常のようにグラデーションブラシを更新するだけで、Windowsがウィンドウのカラースキームを移行すると、グラデーションはウィンドウフレームの残りの部分とともにスムーズに移行します。

Windows XPで実行しているときや、デスクトップのコンポジションを無効にしてWindows Vista以降で実行しているときなど、DWMが利用できない状況を考慮する必要があることに注意してください。また、これを過度に使用しないようにするか、パフォーマンスが大幅に低下してアプリが遅くなる可能性があります。

+2

これは私の最初のWindows 8の回答です... Windows 8.あまりにもひどい... – BoltClock

+0

Whoa、202k点:D –

+0

ああ、私は3年前からコメントを見つけました。 :O –

11

これは、P/Invokesなしで.NET 4.5以降で実行できます。 SystemParametersクラスには、WindowGlassBrushおよびWindowGlassColorのプロパティがあり、StaticPropertyChangedイベントがあります。この割り当てと背景色は、Windowsがその色を変更したときに自動的に更新されません、しかし

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

:XAMLから

、あなたは次のようWindowGlassBrushプロパティにバインドすることができます。残念ながら、SystemParametersはないはそう変更通知を取得し、DynamicResourceとResourceKeysとして使用するWindowGlassBrushKeyまたはWindowGlassColorKey特性を提供し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

SystemParameters.WindowGlassColorプロパティは.NET 4.5フレームワークだけでDwmGetColorizationColorをラップする –

+0

私はテンプレート内でこのプロパティを使用していますが、テンプレートを更新して古い色を新しいものに置き換える方法はありますか? –

+0

悲しいことに、SystemParameters.WindowGlassBrushは正しいアクセントの色を返しません。少なくとも、それは私のマシン上では違っています。私はこのコードを使用します:https://gist.github.com/paulcbetts/3c6aedc9f0cd39a77c37 –

関連する問題