半透明窗体(如Aero玻璃)的背景模糊化

12

我有一个无边框、不可调整大小的WPF表单(WindowStyle=None,AllowsTransparency=True,ResizeMode=NoResize),带有半透明背景。这是一个现在运行在记事本上的半透明红色矩形窗体的图片:

the form as it currently appears on top of Notepad

然而,我希望背景模糊,就像Aero Glass一样,但不需要所有花哨的窗口边框和彩色背景条纹 - 我想自己处理。这是我想要的外观草图:

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

我该如何以最高效的方式实现这一目标?

WinForms或WPF都可以。希望它使用与Aero玻璃相同的东西(仅支持启用Aero),而不是像捕获下面屏幕区域作为位图并模糊处理那样的疯狂方法。

这里是一个我不想要的图片:

I don't want the entire Aero glass window chrome

我知道这是可能的,也知道如何做到,但我不想让整个Aero玻璃窗口外观,包括边框和标题栏,或让窗口使用用户设置的Aero玻璃颜色,只想要模糊窗口/表单下方的效果。

1
你看过 https://dev59.com/IXRC5IYBdhLWcg3wD83r 吗? - Chris Shain
是的,这是在窗体内部模糊。我希望窗体本身可以使其下面的其他窗口变模糊。 - Zdeněk Gromnica
@FutureMillennium,您想要模糊后台的任何应用程序还是只有您的应用程序窗口?如果是后者,您可能需要在不包括您的窗口的情况下进行屏幕截图,将该图像复制到您的窗口并对其进行模糊处理。 - kenny
@kenny 我想要模糊应用程序窗口下方的任何内容,无论是其他窗口、桌面还是其他东西。是的,我想要避免模糊屏幕截图,这不是 Aero 的做法。 - Zdeněk Gromnica
@FutureMillennium,你知道Aero是怎么做的吗?你能用那种方法吗? - kenny
显示剩余2条评论
2个回答

10

如果您想使用Aero模糊效果,则可以使用 DwmEnableBlurBehindWindow API。这是一个使用此功能的窗口示例。

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
}

这里是使用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();

1
这可能是因为Windows 8中禁用了Aero Glass。我认为有一些黑客技巧可以重新启用它,但这不是微软真正支持的东西。 - AndrewS

1

我曾经做过类似的事情,但我不需要以下内容:

  1. 我不需要移动我的表单。
  2. 在我的表单下没有发生任何移动。

我所做的:

  1. 我曾经将我的表单窗口最小化了一会儿(以编程方式)。
  2. 表单用于捕获其大小和相同坐标的图像剪辑。
  3. 在应用BlurBitmapEffect之后,将该图像设置为其背景。

我想这不是一个很好的答案,但我只是写出了我所做的!

如果您对此方法感兴趣,这篇文章会对您有所帮助:http://www.codeproject.com/Articles/91487/Screen-Capture-in-WPF-WinForms-Application


1
谢谢,但这正是我想避免的。Aero 是一个合成窗口管理器,你不应该手动截取屏幕的一部分,然后将其作为位图模糊处理。这不仅代价高昂,而且不像 Aero 那样具有硬件加速功能。 - Zdeněk Gromnica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接