无边框表格Dropshadow

时间:2018-03-20 22:14:18

标签: c# winforms

所以我有以下代码:

#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的检查,它会显示类似这样的阴影: enter image description here

2 个答案:

答案 0 :(得分:1)

这是一个Form类,它使用DWM渲染它的边框/阴影。

如上所述,您需要注册属性DWMWINDOWATTRIBUTE以及相关政策DWMNCRENDERINGPOLICY,将其值设置为已启用。
然后使用DwmSetWindowAttribute()设置属性,使用DwmExtendFrameIntoClientArea()DwmEnableBlurBehindWindow()设置所需的效果,等等。

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

这是Form类(名为" Borderless",在创造力的火花中) 我试图让它看起来像你已发布的内容,以尽量减少"影响"。

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

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);
        }
    }
}

答案 1 :(得分:0)

我将bottomHeight设置为3,发现边框高度已包含在表单大小中(表单的大小没有变化)。 因此,我为此表单设置了BackgroundImage,边框被图像隐藏了。