2012-12-01 35 views
18

Trong Windows 8, tôi đã đặt bảng màu thành tự động và định cấu hình hình nền của tôi thay đổi sau x phút. Màu sắc thay đổi theo hình nền hoạt động.Lấy màu chủ động của chủ đề màu tự động của Windows 8

Tôi đang phát triển ứng dụng WPF và muốn thay đổi độ dốc khi Windows thay đổi bảng màu phù hợp với hình nền hiện tại.

Có cách nào lấy bảng màu hiện tại/thực tế và được thông báo về thay đổi trong C# không?

+0

Điều này bao gồm khá nhiều interop và chỉ có thể thực hiện được với một số API * không được cấp phép *. Trong thực tế, tôi đã thực hiện điều này với dự án của riêng mình cho Windows Vista/7 và thử nghiệm thành công trên Windows 8. Tôi có thể thử đặt câu trả lời cùng nhau dựa trên đó, nhưng tôi sẽ cần một lúc. Xem thêm: [Vista/7: Cách lấy màu kính?] (Http://stackoverflow.com/questions/3560890/vista-7-how-to-get-glass-color) – BoltClock

+0

Cảm ơn bạn rất nhiều về thông tin . Tôi đã sử dụng thủ thuật đăng ký và nó hoạt động rất tốt. – user1868880

Trả lời

15

Có, có thể. Tuy nhiên được cảnh báo: điều này bao gồm một chút tương tác Win32 (điều này có nghĩa là P/Invokes thành DLL gốc từ mã được quản lý) và là chỉ có thể thực hiện được với một số API không được cấp phép. Mặc dù, các tính năng không có giấy tờ chỉ tham gia là để đạt được chương trình cửa sổ màu (hoặc là DWM gọi đó là, màu sắc cửa sổ colorization), được đề cập trong câu hỏi này khác:

Vista/7: How to get glass color?

Trong dự án của riêng tôi, Tôi sử dụng cuộc gọi tới 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; 
} 

Tôi đã thử nghiệm và nó hoạt động tuyệt vời với Windows 8 và tính năng tự động hóa cửa sổ tự động của nó. Như đã đề xuất trong liên kết ở trên, bạn có thể tìm trong sổ đăng ký các giá trị màu thay cho P/Invoke, nhưng tôi chưa thử nghiệm phương thức đó, và như đã nêu là không có giấy tờ và không được bảo đảm ổn định.

Khi bạn có được màu để vẽ bàn chải gradient, bàn chải sẽ không cập nhật khi thay đổi sơ đồ màu cửa sổ, cho dù bằng tay hoặc tự động bởi Windows. Rất may, Windows phát sóng các WM_DWMCOLORIZATIONCOLORCHANGED window message bất cứ khi nào điều đó xảy ra, vì vậy bạn chỉ cần lắng nghe thông điệp đó và cập nhật màu sắc của bạn bất cứ khi nào nó được gửi đi. Bạn làm điều này bằng cách móc vào thủ tục cửa sổ (WndProc()).

Giá trị của WM_DWMCOLORIZATIONCOLORCHANGED0x320; bạn sẽ muốn xác định đó là một hằng số ở đâu đó để bạn có thể sử dụng nó trong mã.

Ngoài ra, không giống như WinForms, cửa sổ WPF không có phương thức WndProc() ảo để ghi đè, vì vậy bạn phải tạo và móc một trong làm đại biểu cho tay cầm cửa sổ liên quan (HWND).

Lấy một số mã ví dụ từ những câu trả lời của tôi:

Chúng tôi có:

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

Khi Windows chuyển tiếp sự thay đổi màu sắc, WM_DWMCOLORIZATIONCOLORCHANGED là được gửi ở mọi khung chính trong quá trình chuyển đổi, vì vậy, bạn sẽ nhận được nhiều tin nhắn tại một thời điểm ngắn trong khi thay đổi màu sắc. Điều này là bình thường; chỉ cần cập nhật bàn chải gradient của bạn như bình thường và bạn sẽ nhận thấy rằng khi Windows chuyển đổi lược đồ màu cửa sổ, gradient của bạn sẽ chuyển đổi trơn tru cùng với phần còn lại của khung cửa sổ là tốt.

Hãy nhớ rằng bạn có thể cần tính đến các trường hợp DWM không khả dụng, chẳng hạn như khi chạy trên Windows XP hoặc khi chạy trên Windows Vista trở lên bị tắt thành phần trên màn hình. Bạn cũng sẽ muốn đảm bảo bạn không lạm dụng điều này hoặc bạn có thể phải chịu một lần truy cập hiệu suất đáng kể và làm chậm ứng dụng của mình.

+2

Và đây là câu trả lời đầu tiên của Windows 8 được đăng từ ... Windows 8. Không quá tồi tàn ... – BoltClock

+0

Whoa, 202k points: D –

+0

Oh boy, tôi vừa tìm thấy bình luận của tôi từ 3 năm trước. : O –

11

Điều này có thể được thực hiện trong .NET 4.5 trở lên mà không có P/Invokes. Lớp SystemParameters hiện có các thuộc tính tĩnh WindowGlassBrushWindowGlassColor cùng với sự kiện StaticPropertyChanged.

Từ XAML, bạn có thể liên kết với các tài sản WindowGlassBrush như:

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

Tuy nhiên, với nhiệm vụ này các màu nền sẽ không được cập nhật tự động khi Windows thay đổi màu sắc của nó. Thật không may, SystemParameters không không cung cấp WindowGlassBrushKey hoặc WindowGlassColorKey thuộc tính để sử dụng làm ResourceKeys với DynamicResource, vì vậy việc nhận thông báo thay đổi yêu cầu mã phía sau để xử lý sự kiện 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

Thuộc tính SystemParameters.WindowGlassColor trong Khuôn khổ .NET 4.5 chỉ kết thúc tốt đẹp DwmGetColorizationColor –

+0

Tôi đang sử dụng thuộc tính này bên trong một mẫu, có cách nào để cập nhật mẫu để thay thế màu cũ bằng một mẫu mới không? –

+0

Đáng buồn thay, SystemParameters.WindowGlassBrush sẽ không trả về màu nhấn chính xác, ít nhất nó khác trên máy của tôi. Tôi sử dụng mã này: https://gist.github.com/paulcbetts/3c6aedc9f0cd39a77c37 –

Các vấn đề liên quan