using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; using System.Windows.Media; namespace Developpez.Dotnet.Windows.Util { /// /// Fournit des propriétés attachées pour utiliser les effets du DWM (Desktop Window Manager) /// public static class DwmUtil { #region Attached properties #region IsHandlerAttached (private) private static bool GetIsHandlerAttached(DependencyObject obj) { return (bool)obj.GetValue(IsHandlerAttachedProperty); } private static void SetIsHandlerAttached(DependencyObject obj, bool value) { obj.SetValue(IsHandlerAttachedProperty, value); } // Using a DependencyProperty as the backing store for IsHandlerAttached. This enables animation, styling, binding, etc... private static readonly DependencyProperty IsHandlerAttachedProperty = DependencyProperty.RegisterAttached("IsHandlerAttached", typeof(bool), typeof(DwmUtil), new UIPropertyMetadata(false)); private static void AttachHandler(Window w) { if (!GetIsHandlerAttached(w)) { w.Loaded += w_Loaded; w.Unloaded += w_Unloaded; SetIsHandlerAttached(w, true); } } private static void DetachHandler(Window w) { if (GetIsHandlerAttached(w)) { w.Loaded -= w_Loaded; w.Unloaded -= w_Unloaded; SetIsHandlerAttached(w, false); } } static void w_Unloaded(object sender, RoutedEventArgs e) { Window w = sender as Window; if (w != null) { DetachHandler(w); } } static void w_Loaded(object sender, RoutedEventArgs e) { Window w = sender as Window; if (w != null) { ApplyGlassFrameMargins(w, GetGlassFrameMargins(w)); EnableBlur(w, GetEnableBlur(w)); } } #endregion #region GlassFrameMargins /// /// Obtient les marges de la bordure "Glass" /// /// La fenêtre cible /// Les marges de la bordure "Glass" [AttachedPropertyBrowsableForType(typeof(Window))] public static Thickness GetGlassFrameMargins(Window window) { return (Thickness)window.GetValue(GlassFrameMarginsProperty); } /// /// Définit les marges de la bordure "Glass" /// /// La fenêtre cible /// Les marges à appliquer /// Une bordure uniforme de -1 applique l'effet "Glass" à toute la fenêtre public static void SetGlassFrameMargins(Window window, Thickness value) { window.SetValue(GlassFrameMarginsProperty, value); } /// /// Identifiant de la propriété GlassFrameMargins /// public static readonly DependencyProperty GlassFrameMarginsProperty = DependencyProperty.RegisterAttached( "GlassFrameMargins", typeof(Thickness), typeof(DwmUtil), new UIPropertyMetadata( new Thickness(), (o, e) => { Window w = o as Window; Thickness newValue = (Thickness)e.NewValue; if (w != null) { if (w.IsLoaded) { ApplyGlassFrameMargins(w, newValue); } else { AttachHandler(w); } } })); private static readonly Thickness fullClientArea = new Thickness(-1); private static void ApplyGlassFrameMargins(Window window, Thickness margins) { try { bool compositionEnabled = false; Interop.Functions.DwmIsCompositionEnabled(ref compositionEnabled); if (compositionEnabled) { // Obtain the window handle for WPF application IntPtr hwnd = new WindowInteropHelper(window).Handle; HwndSource mainWindowSrc = HwndSource.FromHwnd(hwnd); mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0); //Color bgColor = Color.FromArgb(0, 0, 0, 0); //if (window.Background is SolidColorBrush) // bgColor = (window.Background as SolidColorBrush).Color; //mainWindowSrc.CompositionTarget.BackgroundColor = bgColor; // Set Margins if (!margins.Equals(fullClientArea)) { System.Drawing.Graphics desktop = System.Drawing.Graphics.FromHwnd(hwnd); float DesktopDpiX = desktop.DpiX; float DesktopDpiY = desktop.DpiY; margins.Left *= DesktopDpiX / 96; margins.Right *= DesktopDpiX / 96; margins.Top *= DesktopDpiY / 96; margins.Bottom *= DesktopDpiY / 96; } Interop.Types.MARGINS mrg = new Interop.Types.MARGINS { Left = (int)margins.Left, Top = (int)margins.Top, Right = (int)margins.Right, Bottom = (int)margins.Bottom }; int hr = Interop.Functions.DwmExtendFrameIntoClientArea(mainWindowSrc.Handle, ref mrg); if (hr < 0) { Exception ex = Marshal.GetExceptionForHR(hr); throw ex; } } } // If not Vista, paint background white. catch (DllNotFoundException) { window.Background = Brushes.White; } } #endregion #region EnableBlur /// /// Indique si l'effet "Blur" est appliqué à la fenêtre /// /// La fenêtre cible /// true si l'effet "Blur" est appliqué à la fenêtre, false sinon. [AttachedPropertyBrowsableForType(typeof(Window))] public static bool? GetEnableBlur(Window window) { return (bool?)window.GetValue(EnableBlurProperty); } /// /// Définit si l'effet "Blur" est appliqué à la fenêtre /// /// La fenêtre cible /// true si l'effet "Blur" doit être appliqué à la fenêtre, false sinon. public static void SetEnableBlur(Window window, bool? value) { window.SetValue(EnableBlurProperty, value); } /// /// Identifiant de la propriété EnableBlur /// public static readonly DependencyProperty EnableBlurProperty = DependencyProperty.RegisterAttached( "EnableBlur", typeof(bool?), typeof(DwmUtil), new UIPropertyMetadata( null, (o, e) => { bool? newValue = (bool?)e.NewValue; Window w = o as Window; if (w != null) { if (w.IsLoaded && newValue.HasValue) { EnableBlur(w, newValue); } else { AttachHandler(w); } } })); private static void EnableBlur(Window window, bool? enable) { if (enable.HasValue) { try { bool compositionEnabled = false; Interop.Functions.DwmIsCompositionEnabled(ref compositionEnabled); if (compositionEnabled) { IntPtr hwnd = new WindowInteropHelper(window).Handle; HwndSource mainWindowSrc = System.Windows.Interop.HwndSource.FromHwnd(hwnd); mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0); Interop.Types.DWM_BLURBEHIND bb = new Interop.Types.DWM_BLURBEHIND(); bb.Enable = enable.Value; bb.BlurRegion = IntPtr.Zero; int hr = Interop.Functions.DwmEnableBlurBehindWindow(hwnd, ref bb); if (hr < 0) { Exception ex = Marshal.GetExceptionForHR(hr); throw ex; } } } // If not Vista, paint background white. catch (DllNotFoundException) { window.Background = Brushes.White; } } } #endregion #endregion #region Interop declarations private static class Interop { public static class Types { [StructLayout(LayoutKind.Sequential)] public struct MARGINS { public MARGINS(int thickness) { Left = thickness; Right = thickness; Top = thickness; Bottom = thickness; } public int Left; // width of left border that retains its size public int Right; // width of right border that retains its size public int Top; // height of top border that retains its size public int Bottom; // height of bottom border that retains its size }; [StructLayout(LayoutKind.Sequential)] public struct DWM_BLURBEHIND { private uint _flags; public uint Flags { get { return _flags; } set { _flags = value; } } [MarshalAs(UnmanagedType.Bool)] private bool _enable; public bool Enable { get { return _enable; } set { _enable = value; _flags |= Constants.DWM_BB_ENABLE; } } private IntPtr _blurRegion; public IntPtr BlurRegion { get { return _blurRegion; } set { _blurRegion = value; _flags |= Constants.DWM_BB_BLURREGION; } } [MarshalAs(UnmanagedType.Bool)] private bool _transitionOnMaximized; public bool TransitionOnMaximized { get { return _transitionOnMaximized; } set { _transitionOnMaximized = value; _flags |= Constants.DWM_BB_TRANSITIONONMAXIMIZED; } } }; } public static class Functions { [DllImport("DwmApi.dll")] public static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref Types.MARGINS pMarInset); [DllImport("DwmApi.dll")] public static extern int DwmEnableBlurBehindWindow(IntPtr hwnd, ref Types.DWM_BLURBEHIND pBlurBehind); [DllImport("DwmApi.dll")] public static extern int DwmIsCompositionEnabled(ref bool enabled); } public static class Constants { public const uint DWM_BB_ENABLE = 0x00000001; public const uint DWM_BB_BLURREGION = 0x00000002; public const uint DWM_BB_TRANSITIONONMAXIMIZED = 0x00000004; } } #endregion } }