Skip to content

Instantly share code, notes, and snippets.

@RichardD2
Last active August 29, 2015 14:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RichardD2/ef4ee339ce3dcc10264b to your computer and use it in GitHub Desktop.
Save RichardD2/ef4ee339ce3dcc10264b to your computer and use it in GitHub Desktop.
WPF Aero Glass Effect
internal static class SafeNativeMethods
{
[DllImport("dwmapi", SetLastError = true)]
private static extern int DwmIsCompositionEnabled([MarshalAs(UnmanagedType.Bool)] out bool isEnabled);
public static bool SafeDwmIsCompositionEnabled()
{
bool result = false;
if (Environment.OSVersion.Version.Major >= 6)
{
DwmIsCompositionEnabled(out result);
}
return result;
}
[StructLayout(LayoutKind.Sequential)]
private struct DwmMargins
{
private readonly int Left;
private readonly int Right;
private readonly int Top;
private readonly int Bottom;
public DwmMargins(Thickness value)
{
Left = (int)value.Left;
Right = (int)value.Right;
Top = (int)value.Top;
Bottom = (int)value.Bottom;
}
}
[DllImport("dwmapi", SetLastError = true)]
private static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref DwmMargins margins);
public static bool SafeDwmExtendFrameIntoClientArea(IntPtr hWnd, Thickness margins)
{
if (hWnd == IntPtr.Zero) throw new ArgumentException("Invalid window handle.", "hWnd");
bool result = false;
if (SafeDwmIsCompositionEnabled())
{
var dwmMargins = new DwmMargins(margins);
int hr = DwmExtendFrameIntoClientArea(hWnd, ref dwmMargins);
result = (hr == 0);
}
return result;
}
[Flags]
private enum DwmBlurBehindDwFlags : uint
{
DWM_BB_ENABLE = 0x00000001,
DWM_BB_BLURREGION = 0x00000002,
}
[StructLayout(LayoutKind.Sequential)]
private struct DWM_BLURBEHIND
{
public DwmBlurBehindDwFlags dwFlags;
public bool fEnable;
public IntPtr hRgnBlur;
private readonly bool fTransitionOnMaximized;
};
[DllImport("dwmapi", SetLastError = true)]
private static extern int DwmEnableBlurBehindWindow(IntPtr hWnd, ref DWM_BLURBEHIND bb);
public static void SafeResetBlur(IntPtr hWnd)
{
if (hWnd == IntPtr.Zero) throw new ArgumentException("Invalid window handle.", "hWnd");
if (SafeDwmIsCompositionEnabled())
{
var blurBehind = new DWM_BLURBEHIND
{
fEnable = false,
hRgnBlur = IntPtr.Zero,
dwFlags = DwmBlurBehindDwFlags.DWM_BB_ENABLE | DwmBlurBehindDwFlags.DWM_BB_BLURREGION
};
DwmEnableBlurBehindWindow(hWnd, ref blurBehind);
}
}
}
public static class DesktopWindowManager
{
private static readonly Thickness EmptyThickness = new Thickness(0);
private static readonly Thickness SheetOfGlass = new Thickness(-1);
public static bool IsDesktopCompositionEnabled
{
get { return SafeNativeMethods.SafeDwmIsCompositionEnabled(); }
}
private static readonly DependencyProperty OriginalBackgroundProperty = DependencyProperty.RegisterAttached(
"OriginalBackground", typeof(Brush), typeof(DesktopWindowManager),
new PropertyMetadata(null));
private static Brush GetOriginalBackground(DependencyObject element)
{
if (element == null) throw new ArgumentNullException("element");
return (Brush)element.GetValue(OriginalBackgroundProperty);
}
private static void SetOriginalBackground(DependencyObject element, Brush value)
{
if (element == null) throw new ArgumentNullException("element");
element.SetValue(OriginalBackgroundProperty, value);
}
internal static void ResetBlurCore(IntPtr hWnd)
{
if (hWnd != IntPtr.Zero && IsDesktopCompositionEnabled)
{
SafeNativeMethods.SafeResetBlur(hWnd);
}
}
public static void ResetBlur(Window window)
{
if (window == null) throw new ArgumentNullException("window");
ResetBlurCore(new WindowInteropHelper(window).Handle);
}
public static void ResetBlur(WindowInteropHelper window)
{
if (window == null) throw new ArgumentNullException("window");
ResetBlurCore(window.Handle);
}
public static void ResetBlur(IWin32Window window)
{
if (window == null) throw new ArgumentNullException("window");
ResetBlurCore(window.Handle);
}
internal static bool ResetFrameCore(IntPtr hWnd, Control window)
{
if (hWnd == IntPtr.Zero) return false;
bool result = false;
if (IsDesktopCompositionEnabled)
{
if (window != null)
{
Brush background = GetOriginalBackground(window);
if (background != null)
{
window.ClearValue(OriginalBackgroundProperty);
window.Background = background;
}
else
{
window.ClearValue(Control.BackgroundProperty);
}
}
result = SafeNativeMethods.SafeDwmExtendFrameIntoClientArea(hWnd, EmptyThickness);
}
return result;
}
public static bool ResetFrame(Window window)
{
if (window == null) throw new ArgumentNullException("window");
IntPtr hWnd = new WindowInteropHelper(window).Handle;
return ResetFrameCore(hWnd, window);
}
public static bool ResetFrame(WindowInteropHelper window)
{
if (window == null) throw new ArgumentNullException("window");
return ResetFrameCore(window.Handle, null);
}
public static bool ResetFrame(IWin32Window window)
{
if (window == null) throw new ArgumentNullException("window");
return ResetFrameCore(window.Handle, null);
}
internal static bool ExtendFrameIntoClientAreaCore(IntPtr hWnd, Control window, Thickness margins)
{
if (hWnd == IntPtr.Zero) return false;
bool result = false;
if (IsDesktopCompositionEnabled)
{
if (window != null && !Brushes.Transparent.Equals(window.Background))
{
SetOriginalBackground(window, window.Background);
window.Background = Brushes.Transparent;
}
var source = HwndSource.FromHwnd(hWnd);
if (source != null && source.CompositionTarget != null)
{
source.CompositionTarget.BackgroundColor = Colors.Transparent;
}
result = SafeNativeMethods.SafeDwmExtendFrameIntoClientArea(hWnd, margins);
}
return result;
}
public static bool ExtendFrameIntoClientArea(Window window, Thickness margins)
{
if (window == null) throw new ArgumentNullException("window");
IntPtr hWnd = new WindowInteropHelper(window).Handle;
return ExtendFrameIntoClientAreaCore(hWnd, window, margins);
}
public static bool ExtendFrameIntoClientArea(Window window)
{
return ExtendFrameIntoClientArea(window, SheetOfGlass);
}
public static bool ExtendFrameIntoClientArea(WindowInteropHelper window, Thickness margins)
{
if (window == null) throw new ArgumentNullException("window");
return ExtendFrameIntoClientAreaCore(window.Handle, null, margins);
}
public static bool ExtendFrameIntoClientArea(WindowInteropHelper window)
{
return ExtendFrameIntoClientArea(window, SheetOfGlass);
}
public static bool ExtendFrameIntoClientArea(IWin32Window window, Thickness margins)
{
if (window == null) throw new ArgumentNullException("window");
return ExtendFrameIntoClientAreaCore(window.Handle, null, margins);
}
public static bool ExtendFrameIntoClientArea(IWin32Window window)
{
return ExtendFrameIntoClientArea(window, SheetOfGlass);
}
}
public static class Glass
{
private static readonly Thickness DefaultThickness = new Thickness(-1, 0, 0, 0);
private static readonly DependencyPropertyKey IsAppliedPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
"IsApplied", typeof(bool), typeof(Glass),
new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty IsAppliedProperty = IsAppliedPropertyKey.DependencyProperty;
[AttachedPropertyBrowsableForType(typeof(Window))]
public static bool GetIsApplied(Window element)
{
if (element == null) throw new ArgumentNullException("element");
return (bool)element.GetValue(IsAppliedProperty);
}
private static void SetIsApplied(Window element, bool value)
{
if (element == null) throw new ArgumentNullException("element");
element.SetValue(IsAppliedPropertyKey, value);
}
public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached(
"IsEnabled", typeof(bool), typeof(Glass),
new FrameworkPropertyMetadata(false, OnGlassChanged));
[AttachedPropertyBrowsableForType(typeof(Window))]
public static bool GetIsEnabled(Window element)
{
if (element == null) throw new ArgumentNullException("element");
return (bool)element.GetValue(IsEnabledProperty);
}
public static void SetIsEnabled(Window element, bool value)
{
if (element == null) throw new ArgumentNullException("element");
element.SetValue(IsEnabledProperty, value);
}
public static readonly DependencyProperty FrameThicknessProperty = DependencyProperty.RegisterAttached(
"FrameThickness", typeof(Thickness), typeof(Glass),
new FrameworkPropertyMetadata(DefaultThickness, OnGlassChanged));
[AttachedPropertyBrowsableForType(typeof(Window))]
public static Thickness GetFrameThickness(Window element)
{
if (element == null) throw new ArgumentNullException("element");
return (Thickness)element.GetValue(FrameThicknessProperty);
}
public static void SetFrameThickness(Window element, Thickness value)
{
if (element == null) throw new ArgumentNullException("element");
element.SetValue(FrameThicknessProperty, value);
}
private static void OnGlassChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var window = d as Window;
if (window != null) Manager.UpdateGlassEffect(window);
}
private sealed class Manager
{
private readonly Window _window;
private IntPtr _windowHandle;
private Manager(Window window)
{
_window = window;
_window.SourceInitialized += WindowSourceInitialized;
WindowSourceInitialized(null, EventArgs.Empty);
}
private void WindowSourceInitialized(object sender, EventArgs e)
{
_windowHandle = new WindowInteropHelper(_window).Handle;
UpdateGlassEffectCore();
}
public static void UpdateGlassEffect(Window window)
{
var manager = (Manager)window.GetValue(ManagerProperty);
if (manager == null)
{
manager = new Manager(window);
window.SetValue(ManagerProperty, manager);
}
else
{
manager.UpdateGlassEffectCore();
}
}
private void UpdateGlassEffectCore()
{
bool result = false;
if (_windowHandle != IntPtr.Zero && DesktopWindowManager.IsDesktopCompositionEnabled)
{
DesktopWindowManager.ResetBlurCore(_windowHandle);
if (GetIsEnabled(_window))
{
result = DesktopWindowManager.ExtendFrameIntoClientAreaCore(_windowHandle, _window, GetFrameThickness(_window));
}
else if (GetIsApplied(_window))
{
DesktopWindowManager.ResetFrameCore(_windowHandle, _window);
}
}
SetIsApplied(_window, result);
}
}
private static readonly DependencyProperty ManagerProperty = DependencyProperty.RegisterAttached(
"Manager", typeof(Manager), typeof(Glass),
new PropertyMetadata(null));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment