Windows Vista udziwnił troszeczkę konstrukcję okna wprowadzając półprzezroczystą część nazywaną Glass (szkło). Jest to ewidentnie wodotrysk i trochę dziwi mnie, dlaczego wprowadzono do API funkcje, które mogą okazać się tylko chwilową modą, która zniknie wraz z nastepną wersją systemu.
No dobrze, w Windows 7 dalej będzie ten wodotrysk, więc skoro już jest, to warto może spróbować go użyć (byle nie nadużyć). Nie oszukujmy się – ludzie lubią wodotryski.
WPF nie daje bezpośredniej możliwości operowania na szkle – potrzebujemy wywołać funkcję API DwmExtendFrameIntoClientArea przyjmującą jako argument uchwyt okna i strukturę MARGINS. A może by tak postarać się trochę i utworzyć DependencyProperty – animowalną, bindowalną i elegancką (na tyle, na ile DependencyProperty można nazywać elegancką) właściwość pozwalającą regulować szklany obszar okna?
Proponuję zrobić to tak:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
using System; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; using System.Windows.Media; namespace WpfExperiments { public class GlassWindow : Window { struct MARGINS { public MARGINS(Thickness t) { Left = (int)t.Left; Right = (int)t.Right; Top = (int)t.Top; Bottom = (int)t.Bottom; } public int Left; public int Right; public int Top; public int Bottom; } [DllImport("dwmapi.dll", PreserveSig = false)] static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins); [DllImport("dwmapi.dll", PreserveSig = false)] static extern bool DwmIsCompositionEnabled(); public Thickness GlassFrame { get { return (Thickness)GetValue(GlassFrameProperty); } set { SetValue(GlassFrameProperty, value); } } public static readonly DependencyProperty GlassFrameProperty = DependencyProperty.Register("GlassFrame", typeof(Thickness), typeof(GlassWindow), new UIPropertyMetadata(new Thickness(0, 0, 0, 0), new PropertyChangedCallback(GlassFrameChangedProperty))); private static void GlassFrameChangedProperty(DependencyObject d, DependencyPropertyChangedEventArgs e) { UpdateGlassFrame((Window)d, (Thickness)e.NewValue); } private static void UpdateGlassFrame(Window win, Thickness t) { if (!DwmIsCompositionEnabled()) { return; } IntPtr hwnd = new WindowInteropHelper(win).Handle; if (hwnd == IntPtr.Zero) { return; } win.Background = Brushes.Transparent; HwndSource.FromHwnd(hwnd).CompositionTarget.BackgroundColor = Colors.Transparent; MARGINS margins = new MARGINS(t); DwmExtendFrameIntoClientArea(hwnd, ref margins); } protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); UpdateGlassFrame(this, GlassFrame); } } } |
Teraz – zamiast tworzyć okna na bazie klasy Window, możemy użyć klasy GlassWindow posiadającej właściwość GlassFrame typu Thickness, którą możemy się posługiwać jak każdą inną DependencyProperty.
Ustawiając dodatnie wartości dla GlassFrame, możemy regulować grubość szklaj ramki. Jeśli ustawimy wartości ujemne – całe okno zrobi się szklane.
Jak możesz – bo wydaję mi się że to gdzieś widziałem już, w sensie kodu – umieszczaj skompilowany programik aby szybko sprawdzić jak to wygląda 😉
Powyższa klasa będzie użyta w następnym programiku, który opublikuję. I będzie od razu w wersji skompilowanej.