设计没有Style的Winform窗体,通过拖动操作区而非标题区让Form跟着鼠标移动。
我们平时设计常用的Form都是基于FormBorderStyle为Sizeable的,但是随着扁平化发展的迅速,Winform也偏向于扁平化的设计(虽然要做的更炫更好的话还是推荐WPF,但是毕竟Winfom还在用么)。
实际工作中碰到这样一个问题,我制作了一个窗体FormBorderStyle为None的窗体,如图:

如果此时我要移动这个窗体的话,由于没有标题栏,所以无法移动,当一个比较简单的解决办法是,对Form添加MouseDown事件和MouseMove事件,代码如下:
方案1:
Point downPoint; private void Form1_MouseDown(object sender, MouseEventArgs e) { downPoint = new Point(e.X, e.Y); } private void Form1_MouseMove(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { Location = new Point(Location.X + e.X - downPoint.X, Location.Y + e.Y - downPoint.Y); } }
MouseDown的时候将当前鼠标坐标存储,MouseMove的时候,实际上就是实时的将窗体最后一次的Location+偏移量-鼠标的位置。
这样做好处在于简单,不足在于:
(1)如果添加了如图所示的OpenFileDialog,那么当打开这个窗体的时候,主窗体会记录鼠标位置,同时当你选择文件的时候,默认认为你进行了偏移,关闭选择文件窗口的时候窗体就偏移了。
(2)对于窗体上的一些控件,必须添加两个事件使之也能同步,不太友好。
方案2:
这个方案是网上找到的,实际上利用消息的机制来进行设置,优点:不用声明api函数。缺点是:窗体上放着Panel等容器就会失效。
const int WM_NCHITTEST = 0x0084; const int HTLEFT = 10; const int HTCAPTION = 2; const int HTCLIENT = 1; protected override void WndProc(ref Message m) { base.WndProc(ref m); switch (m.Msg) { case WM_NCHITTEST: if (m.Result == (IntPtr)HTCLIENT) m.Result = (IntPtr)HTCAPTION; break; } }
方案3:
这个方案是我现在用的方案,虽然比较复杂,但是能恰到好处的处理掉拖动的问题,同时其他控件调用也比较方便
using System.Runtime.InteropServices; [DllImport("User32.DLL")] public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); [DllImport("User32.DLL")] public static extern bool ReleaseCapture(); public const uint WM_SYSCOMMAND = 0x0112; public const int SC_MOVE = 61456; public const int HTCAPTION = 2; private void Form1_MouseDown(object sender, MouseEventArgs e) { ReleaseCapture(); SendMessage(Handle, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0); }
实际上还是使用了消息机制,优点在于,例如Label等控件也只需要调用一下这个方法就可以进行整个窗体的移动了。
浙公网安备 33010602011771号