12

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:

the form as it currently appears 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:

the form as I want it to be - blur anything that's below it

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 don't want the entire Aero glass window chrome

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.

nathanchere
  • 8,008
  • 15
  • 65
  • 86
Zdeněk Gromnica
  • 854
  • 2
  • 14
  • 31
  • 1
    Have you seen http://stackoverflow.com/questions/421968/blurred-opacity? – Chris Shain Jul 08 '12 at 20:31
  • Yes, and that's blurring INSIDE the form. I want the form itself to blur other windows below it. – Zdeněk Gromnica Jul 08 '12 at 20:32
  • Have you tried this: http://stackoverflow.com/questions/7815278/blur-the-background-of-the-wpf-container – sloth Jul 08 '12 at 20:34
  • Again, that's blurring INSIDE the form. I want the form itself to blur other windows below it. – Zdeněk Gromnica Jul 08 '12 at 20:36
  • @FutureMillennium Do you want to blur any application in the background or only windows of your application? If the format, you may have to screen capture w/o your window, copy that image to your window and blur it. – kenny Jul 09 '12 at 00:53
  • @kenny I want to blur anything that's below the application's window, be it other windows, the desktop or anything else. And yes, blurring a screen capture is exactly what want to avoid, that's not how Aero does it. – Zdeněk Gromnica Jul 09 '12 at 01:24
  • @FutureMillennium id you know how Aero does it, can you use that method? – kenny Jul 09 '12 at 01:27

2 Answers2

10

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();
AndrewS
  • 6,054
  • 24
  • 31
  • 1
    That's probably because aero glass is disabled in Windows 8. I think [there are hacks](http://www.howtogeek.com/128630/how-to-enable-aero-glass-style-transparency-in-windows-8/) to re-enable it but it's not something MS is really supporting. – AndrewS Oct 31 '13 at 16:20
1

I did something similar once but I didn't need the following:

  1. I didn't need to move my form much.
  2. No movement took place under my form.

What I did:

  1. I used to minimize my form window for a moment (programmatically).
  2. Form used to capture the image snip of it's size and at the same coordinates.
  3. Set that image as it's background after applying the BlurBitmapEffect.

Not a great answer I presume, but I'm just writing what I did!

If you're interested in this approach this article will help you: http://www.codeproject.com/Articles/91487/Screen-Capture-in-WPF-WinForms-Application

naqvitalha
  • 793
  • 5
  • 9
  • 1
    Thanks, but that's what I'm trying to avoid. Aero is a compositing window manager and you shouldn't have to manually screencap a part of the screen and then blur that as a bitmap. Not only is it costly, but it's not hardware accelerated, unlike how Aero does it. – Zdeněk Gromnica Jul 09 '12 at 15:35