C# 自定义无边框窗体阴影效果
工作中我们会经常遇到自定义一些窗口的样式,设置无边框然后自定义关闭、最大化等其他菜单,但是这样就失去了Winform自带的边框阴影效果,下面这个方法能让无边框增加阴影效果。代码如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WinfromTest.ShadowDialog { public partial class ShadowForm : Form { [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; // variables for box shadow private const int CS_DROPSHADOW = 0x00020000; private const int WM_NCPAINT = 0x0085; private const int WM_ACTIVATEAPP = 0x001C; public struct MARGINS // struct for box shadow { public int leftWidth; public int rightWidth; public int topHeight; public int bottomHeight; } private const int WM_NCHITTEST = 0x84; // variables for dragging the form private const int HTCLIENT = 0x1; private const int HTCAPTION = 0x2; protected override CreateParams CreateParams { get { m_aeroEnabled = CheckAeroEnabled(); CreateParams cp = base.CreateParams; if (!m_aeroEnabled) cp.ClassStyle |= CS_DROPSHADOW; 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 WM_NCPAINT: // box shadow if (m_aeroEnabled) { var 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); if (m.Msg == WM_NCHITTEST && (int)m.Result == HTCLIENT) // drag the form m.Result = (IntPtr)HTCAPTION; } public ShadowForm() { m_aeroEnabled = false; FormBorderStyle = FormBorderStyle.None; InitializeComponent(); } private void btnClose_Click(object sender, EventArgs e) { Close(); } private void ShadowForm_Resize(object sender, EventArgs e) { pnlClient.Dock = DockStyle.Top; pnlClient.Height = this.Height - 1; } } }
1.上面代码中MARGINS部分源码里设置的都是1,这样阴影效果中会有一条1像素的白边,如果都设置成0后阴影效果就没了,无奈只能bottomHeight=1,这样只有底部有个小白线。
MARGINS margins = new MARGINS() { bottomHeight = 1, leftWidth = 0, rightWidth = 0, topHeight = 0 };
2.如果窗体上弄个pannel设置成Fill模式,阴影效果也会消失,费解。。。所以不能全部填充满,为此我想了个办法,设计界面还是弄一个pannel设置成FIll模式,这样不影响我们继续在页面布局,但是在ShadowForm_Resize中动态设置Dock为Top,高度为父容器Height -1就可以了。
这样一个自带阴影效果的Form就做好了。
private void ShadowForm_Resize(object sender, EventArgs e) { pnlClient.Dock = DockStyle.Top; pnlClient.Height = this.Height - 1; }
效果如下: