【问题标题】:Borderless Form Dropshadow无边框形式阴影
【发布时间】:2018-08-29 21:42:13
【问题描述】:

所以我有以下代码:

#region Dropshadow
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
private static extern IntPtr CreateRoundRectRgn
(
    int nLeftRect,
    int nTopRect,
    int nRightRect,
    int nBottomRect,
    int nWidthEllipse,
    int nHeightEllipse
);
[DllImport("dwmapi.dll")]
public static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);
[DllImport("dwmapi.dll")]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
[DllImport("dwmapi.dll")]
public static extern int DwmIsCompositionEnabled(ref int pfEnabled);
private bool m_aeroEnabled;
public struct MARGINS
{
    public int leftWidth;
    public int rightWidth;
    public int topHeight;
    public int bottomHeight;
}
protected override CreateParams CreateParams {
    get {
        m_aeroEnabled = CheckAeroEnabled();
        CreateParams cp = base.CreateParams;
        if (!m_aeroEnabled) {
            cp.ClassStyle |= 0x00020000;
        }

        return cp;
    }
}
private bool CheckAeroEnabled()
{
    if (Environment.OSVersion.Version.Major >= 6) {
        int enabled = 0;
        DwmIsCompositionEnabled(ref enabled);
        return (enabled == 1) ? true : false;
    }
    return false;
}
protected override void WndProc(ref Message m)
{
    switch (m.Msg) {
        case 0x0085:
            if (m_aeroEnabled) {
                int v = 2;
                DwmSetWindowAttribute(Handle, 2, ref v, 4);
                MARGINS margins = new MARGINS() {
                    bottomHeight = 1,
                    leftWidth = 0,
                    rightWidth = 0,
                    topHeight = 0
                };
                DwmExtendFrameIntoClientArea(Handle, ref margins);
            }
            break;
        default:
            break;
    }
    base.WndProc(ref m);
}
#endregion

这会使用 GDI 制作 Dropshadow。 然而,唯一的问题是我必须让它在顶部保持一个 1 像素高度的边框(它可以是任何边缘,只是顶部在我的应用中最难注意到)。

这使我的应用程序顶部出现一条线,这实际上会降低观看体验。

有没有可能做到完全没有边框?

(bottomHeight = 1 代码就是它的全部。如果我将它设置为 0,topHeight 设置为 1,则该行将位于底部。将它们全部设置为 0,根本不会显示阴影.)

事实证明,这与我的填充有关,我需要在至少 1 个边缘上留 1 个像素线为空,以便 Dropshadow 工作。我选择使用 Padding 来制作 1 像素线,并将顶部填充设置为 1。这将线设置在顶部。 bottomHeight = 1 根本不重要。它就在那里,因为它要求其中至少有一个不为 0。

如果我删除 Padding 和 Top Line 等。并且在 CreateParams 覆盖中,如果我删除启用 aero 的检查,它会显示类似这样的阴影:

【问题讨论】:

  • 我真的不知道。但是您是否尝试过负边距(-1)?这应该会触发“玻璃板”效应。
  • @NigelWhatling 这会在此处产生一条透明线,您可以在其上看到聚焦和未聚焦的不透明度变化。 ://
  • 顺便说一句,我必须在顶部放置 1 的填充,这样它才能正常工作。如果我的 CEFSharp 浏览器 UI 覆盖了整个表单,则它不起作用。
  • 您需要注册您的窗口设置,在您的 Form.Load() 事件中使用 DWMNCRENDERINGPOLICY 值 = Enabled 调用 DwmSetWindowAttribute(),您还必须在第一个事件中调用 DwmExtendFrameIntoClientArea()时间,指定边距。然后,您应该处理WM_DWMCOMPOSITIONCHANGED,而不是 WM_PAINT。您只需将边距设置为 (0,1,0,1) => Right 和 Bottom 设置为 1 即可启用阴影。或全部为 -1 以启用特殊的玻璃板功能。
  • DWMNCRENDERINGPOLICY 是已设置的 int 2。我不认为它需要在 Form.Load() 中设置。它在 WndProc 中被调用。 DwmExtendFrameIntoClientArea() 我已经尝试将所有设置为-1。它不起作用,因为我的控件覆盖了整个表单,它需要 1 个边缘为空,因为它出于某种原因会产生阴影。

标签: c# winforms dwm


【解决方案1】:

我将bottomHeight 设置为3,我发现边框高度包含在表单大小中(表单大小没有改变)。 所以我给这个表单设置了一个BackgroundImage,边框被图片隐藏了。

【讨论】:

    【解决方案2】:

    这是一个使用 DWM 呈现其边框/阴影的 Form 类。

    如上所述,您需要注册一个属性DWMWINDOWATTRIBUTE,并且相关的策略DWMNCRENDERINGPOLICY 将其值设置为启用。
    然后用DwmSetWindowAttribute()设置属性,用DwmExtendFrameIntoClientArea()、DwmEnableBlurBehindWindow()等设置想要的效果。

    所有需要的声明都在这里。

    这是 Form 类(命名为“Borderless”,激发了创造力)。
    我试图让它看起来像您已经发布的内容,以尽量减少“影响”。

    表单是标准的 WinForms 表单,带有FormBorderStyle = None。

    public partial class Borderless : Form
    {
        public Borderless() => InitializeComponent();
    
        protected override void OnHandleCreated(EventArgs e) {
            base.OnHandleCreated(e);
            WinApi.Dwm.DWMNCRENDERINGPOLICY Policy = WinApi.Dwm.DWMNCRENDERINGPOLICY.Enabled;
            WinApi.Dwm.WindowSetAttribute(this.Handle, WinApi.Dwm.DWMWINDOWATTRIBUTE.NCRenderingPolicy, (int)Policy);
            if (DWNCompositionEnabled()) { WinApi.Dwm.WindowBorderlessDropShadow(this.Handle, 2); }
            //if (DWNCompositionEnabled()) { WinApi.Dwm.WindowEnableBlurBehind(this.Handle); }
            //if (DWNCompositionEnabled()) { WinApi.Dwm.WindowSheetOfGlass(this.Handle); }
        }
    
        private bool DWNCompositionEnabled() => (Environment.OSVersion.Version.Major >= 6)
                                             ? WinApi.Dwm.IsCompositionEnabled()
                                             : false;
    
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case (int)WinApi.WinMessage.WM_DWMCOMPOSITIONCHANGED:
                    {
                        WinApi.Dwm.DWMNCRENDERINGPOLICY Policy = WinApi.Dwm.DWMNCRENDERINGPOLICY.Enabled;
                        WinApi.Dwm.WindowSetAttribute(this.Handle, WinApi.Dwm.DWMWINDOWATTRIBUTE.NCRenderingPolicy, (int)Policy);
                        WinApi.Dwm.WindowBorderlessDropShadow(this.Handle, 2);
                        m.Result = (IntPtr)0;
                    }
                    break;
                default:
                    break;
            }
            base.WndProc(ref m);
        }
    }
    


    这些是所需的所有声明,以及其他可能有用的声明。
    请注意,我仅使用 Win32 API 形式的 internal 属性,这些 API 使用帮助程序方法调用。

    这是一个部分类,因为Winapi 类是一个扩展类库。您可以将其更改为您习惯的任何内容。

    我建议保留[SuppressUnmanagedCodeSecurityAttribute] Win32 API 声明的属性。

    public partial class WinApi
    {
        public enum WinMessage : int
        {
            WM_DWMCOMPOSITIONCHANGED = 0x031E,          //The system will send a window the WM_DWMCOMPOSITIONCHANGED message to indicate that the availability of desktop composition has changed.
            WM_DWMNCRENDERINGCHANGED = 0x031F,          //WM_DWMNCRENDERINGCHANGED is called when the non-client area rendering status of a window has changed. Only windows that have set the flag DWM_BLURBEHIND.fTransitionOnMaximized to true will get this message.
            WM_DWMCOLORIZATIONCOLORCHANGED = 0x0320,    //Sent to all top-level windows when the colorization color has changed.
            WM_DWMWINDOWMAXIMIZEDCHANGE = 0x0321        //WM_DWMWINDOWMAXIMIZEDCHANGE will let you know when a DWM composed window is maximized. You also have to register for this message as well. You'd have other windowd go opaque when this message is sent.
        }
    
        public class Dwm
    
            public enum DWMWINDOWATTRIBUTE : uint
            {
                NCRenderingEnabled = 1,     //Get only atttribute
                NCRenderingPolicy,          //Enable or disable non-client rendering
                TransitionsForceDisabled,
                AllowNCPaint,
                CaptionButtonBounds,
                NonClientRtlLayout,
                ForceIconicRepresentation,
                Flip3DPolicy,
                ExtendedFrameBounds,
                HasIconicBitmap,
                DisallowPeek,
                ExcludedFromPeek,
                Cloak,
                Cloaked,
                FreezeRepresentation
            }
    
            public enum DWMNCRENDERINGPOLICY : uint
            {
                UseWindowStyle, // Enable/disable non-client rendering based on window style
                Disabled,       // Disabled non-client rendering; window style is ignored
                Enabled,        // Enabled non-client rendering; window style is ignored
            };
    
            // Values designating how Flip3D treats a given window.
            enum DWMFLIP3DWINDOWPOLICY : uint
            {
                Default,        // Hide or include the window in Flip3D based on window style and visibility.
                ExcludeBelow,   // Display the window under Flip3D and disabled.
                ExcludeAbove,   // Display the window above Flip3D and enabled.
            };
    
            public struct MARGINS
            {
                public int leftWidth;
                public int rightWidth;
                public int topHeight;
                public int bottomHeight;
    
                public MARGINS(int LeftWidth, int RightWidth, int TopHeight, int BottomHeight)
                {
                    leftWidth = LeftWidth;
                    rightWidth = RightWidth;
                    topHeight = TopHeight;
                    bottomHeight = BottomHeight;
                }
    
                public void NoMargins()
                {
                    leftWidth = 0;
                    rightWidth = 0;
                    topHeight = 0;
                    bottomHeight = 0;
                }
    
                public void SheetOfGlass()
                {
                    leftWidth = -1;
                    rightWidth = -1;
                    topHeight = -1;
                    bottomHeight = -1;
                }
            }
    
    
            [SuppressUnmanagedCodeSecurityAttribute]
            internal static class SafeNativeMethods
            {
                //https://msdn.microsoft.com/en-us/library/windows/desktop/aa969508(v=vs.85).aspx
                [DllImport("dwmapi.dll")]
                internal static extern int DwmEnableBlurBehindWindow(IntPtr hwnd, ref DWM_BLURBEHIND blurBehind);
    
                //https://msdn.microsoft.com/it-it/library/windows/desktop/aa969512(v=vs.85).aspx
                [DllImport("dwmapi.dll")]
                internal static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);
    
                //https://msdn.microsoft.com/en-us/library/windows/desktop/aa969515(v=vs.85).aspx
                [DllImport("dwmapi.dll")]
                internal static extern int DwmGetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attr, ref int attrValue, int attrSize);
    
                //https://msdn.microsoft.com/en-us/library/windows/desktop/aa969524(v=vs.85).aspx
                [DllImport("dwmapi.dll")]
                internal static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attr, ref int attrValue, int attrSize);
    
                [DllImport("dwmapi.dll")]
                internal static extern int DwmIsCompositionEnabled(ref int pfEnabled);
            }
    
            public static bool IsCompositionEnabled()
            {
                int pfEnabled = 0;
                int result = SafeNativeMethods.DwmIsCompositionEnabled(ref pfEnabled);
                return (pfEnabled == 1) ? true : false;
            }
    
            public static bool IsNonClientRenderingEnabled(IntPtr hWnd)
            {
                int gwaEnabled = 0;
                int result = SafeNativeMethods.DwmGetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.NCRenderingEnabled, ref gwaEnabled, sizeof(int));
                return (gwaEnabled == 1) ? true : false;
            }
    
            public static bool WindowSetAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE Attribute, int AttributeValue)
            {
                int result = SafeNativeMethods.DwmSetWindowAttribute(hWnd, Attribute, ref AttributeValue, sizeof(int));
                return (result == 0);
            }
    
    
            public static bool WindowEnableBlurBehind(IntPtr hWnd)
            {
                //Create and populate the Blur Behind structure
                DWM_BLURBEHIND Dwm_BB = new DWM_BLURBEHIND(true);
    
                int result = SafeNativeMethods.DwmEnableBlurBehindWindow(hWnd, ref Dwm_BB);
                return (result == 0);
            }
    
            public static bool WindowExtendIntoClientArea(IntPtr hWnd, WinApi.Dwm.MARGINS Margins)
            {
                // Extend frame on the bottom of client area
                int result = SafeNativeMethods.DwmExtendFrameIntoClientArea(hWnd, ref Margins);
                return (result == 0);
            }
    
            public static bool WindowBorderlessDropShadow(IntPtr hWnd, int ShadowSize)
            {
                MARGINS Margins = new MARGINS(0, ShadowSize, 0, ShadowSize);
                int result = SafeNativeMethods.DwmExtendFrameIntoClientArea(hWnd, ref Margins);
                return (result == 0);
            }
    
            public static bool WindowSheetOfGlass(IntPtr hWnd)
            {
                MARGINS Margins = new MARGINS();
                Margins.SheetOfGlass();
    
                //Margins set to All:-1 - Sheet Of Glass effect
                int result = SafeNativeMethods.DwmExtendFrameIntoClientArea(hWnd, ref Margins);
                return (result == 0);
            }
    
            public static bool WindowDisableRendering(IntPtr hWnd)
            {
                DWMNCRENDERINGPOLICY NCRP = DWMNCRENDERINGPOLICY.Disabled;
                int ncrp = (int)NCRP;
                // Disable non-client area rendering on the window.
                int result = SafeNativeMethods.DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.NCRenderingPolicy, ref ncrp, sizeof(int));
                return (result == 0);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-07-09
      • 1970-01-01
      • 2017-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多