I have a borderless, non-resizable WPF form (WindowStyle=None, AllowsTransparency=True, ResizeMode=NoResize) with a semi-transparent background. Here's a picture of how the form, a semi-transparent red rectangle, looks right now, running on top of Notepad:
However, I'd like the background to be blurred, like how Aero glass does it, except without all the fancy window borders and colored background with stripes - I'd like to handle that myself. Here's a mockup of how I want it to look like:
How can I achieve this in the most efficient way possible?
WinForms or WPF is fine by me. Hopefully it should use the same thing Aero glass uses (I'm fine with it working only with Aero enabled), instead of something crazy like capturing the screen region below as a bitmap and blurring that.
Here is a picture of what I DON'T want:
I know this is possible and I know how to do it, but I DON'T want the entire Aero glass window chrome, or the borders and title bar, or the window to have the user-set Aero glass color, JUST the effect of blurring whatever is below the window/form.
If you want to use the Aero blur then you can use the DwmEnableBlurBehindWindow api. Here's an example derived Window that utilizes this.
public class BlurWindow : Window
{
#region Constants
private const int WM_DWMCOMPOSITIONCHANGED = 0x031E;
private const int DWM_BB_ENABLE = 0x1;
#endregion //Constants
#region Structures
[StructLayout( LayoutKind.Sequential )]
private struct DWM_BLURBEHIND
{
public int dwFlags;
public bool fEnable;
public IntPtr hRgnBlur;
public bool fTransitionOnMaximized;
}
[StructLayout( LayoutKind.Sequential )]
private struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
#endregion //Structures
#region APIs
[DllImport( "dwmapi.dll", PreserveSig = false )]
private static extern void DwmEnableBlurBehindWindow(IntPtr hwnd, ref DWM_BLURBEHIND blurBehind);
[DllImport( "dwmapi.dll" )]
private static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMargins);
[DllImport( "dwmapi.dll", PreserveSig = false )]
private static extern bool DwmIsCompositionEnabled();
#endregion //APIs
#region Constructor
public BlurWindow()
{
this.WindowStyle = System.Windows.WindowStyle.None;
this.ResizeMode = System.Windows.ResizeMode.NoResize;
this.Background = Brushes.Transparent;
}
#endregion //Constructor
#region Base class overrides
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized( e );
if ( Environment.OSVersion.Version.Major >= 6 )
{
var hwnd = new WindowInteropHelper( this ).Handle;
var hs = HwndSource.FromHwnd( hwnd );
hs.CompositionTarget.BackgroundColor = Colors.Transparent;
hs.AddHook( new HwndSourceHook( this.WndProc ) );
this.InitializeGlass( hwnd );
}
}
#endregion //Base class overrides
#region Methods
#region InitializeGlass
private void InitializeGlass(IntPtr hwnd)
{
if ( !DwmIsCompositionEnabled() )
return;
// fill the background with glass
var margins = new MARGINS();
margins.cxLeftWidth = margins.cxRightWidth = margins.cyBottomHeight = margins.cyTopHeight = -1;
DwmExtendFrameIntoClientArea( hwnd, ref margins );
// initialize blur for the window
DWM_BLURBEHIND bbh = new DWM_BLURBEHIND();
bbh.fEnable = true;
bbh.dwFlags = DWM_BB_ENABLE;
DwmEnableBlurBehindWindow( hwnd, ref bbh );
}
#endregion //InitializeGlass
#region WndProc
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if ( msg == WM_DWMCOMPOSITIONCHANGED )
{
this.InitializeGlass( hwnd );
handled = false;
}
return IntPtr.Zero;
}
#endregion //WndProc
#endregion //Methods
}
And here's a snippet of using the BlurWindow.
var w = new BlurWindow();
w.Width = 100;
w.Height = 100;
w.MouseLeftButtonDown += (s1, e1) => {
((Window)s1).DragMove();
e1.Handled = true;
};
w.Background = new SolidColorBrush( Color.FromArgb( 75, 255, 0, 0 ) );
w.Show();