程序員經常要實現拖動控件的功能,一般實現這個功能,都要注冊事件,然后寫MouseMove的代碼,
Point point = Point.Empty; control.MouseDown += control_MouseDown; control.MouseMove += control_MouseMove; control.MouseLeave += control_MouseLeave;
如果程序的很多地方都有這個邏輯的話,那么代碼就會有一大部分的重復了。
在網上如果你搜索控件拖動的話,大部分代碼都是上面的代碼,重復的邏輯,重復的故事。
於是我想,能不能寫一個幫助類,當需要拖動的時候,只要調用EnableDrag方法就行了,如下:
private void Form1_Load(object sender, EventArgs e) { DraggerHelper.EnableDrag(button1); DraggerHelper.EnableDrag(label1); DraggerHelper.DisableDrag(button1); DraggerHelper.DisableDrag(label1); }
要實現這個效果,需要一些小技巧,當然,這些已經封裝進了DraggerHelper 類。
完整的代碼如下:


完整的代碼using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace ControlDragger { public static class DraggerHelper { private static DraggerHelperCore helperCore = new DraggerHelperCore(); public static void EnableDrag(this Control control) { helperCore.EnableDrag(control); } public static bool IsControlCanDrag(this Control control) { return helperCore.IsControlCanDrag(control); } public static void DisableDrag(this Control control) { helperCore.DisableDrag(control); } } internal sealed class DraggerHelperCore { /// <summary> /// 光標狀態 /// </summary> private enum EnumMousePointPosition { MouseSizeNone = 0, //'無 MouseSizeRight = 1, //'拉伸右邊框 MouseSizeLeft = 2, //'拉伸左邊框 MouseSizeBottom = 3, //'拉伸下邊框 MouseSizeTop = 4, //'拉伸上邊框 MouseSizeTopLeft = 5, //'拉伸左上角 MouseSizeTopRight = 6, //'拉伸右上角 MouseSizeBottomLeft = 7, //'拉伸左下角 MouseSizeBottomRight = 8, //'拉伸右下角 MouseDrag = 9 // '鼠標拖動 } private const int Band = 5; private const int MinWidth = 10; private const int MinHeight = 10; private EnumMousePointPosition m_MousePointPosition; internal class DragControlProperty { public Point PositionMovePoint { get; set; } public Point SizeChangeMovePoint { get; set; } } Dictionary<Control, DragControlProperty> controlPropertyDic = new Dictionary<Control, DragControlProperty>(); public bool IsControlCanDrag(Control control) { return controlPropertyDic.ContainsKey(control); } public void EnableDrag(Control control) { if (!controlPropertyDic.ContainsKey(control)) { controlPropertyDic.Add(control, new DragControlProperty() { }); control.MouseDown += control_MouseDown; control.MouseMove += control_MouseMove; control.MouseLeave += control_MouseLeave; } } public void DisableDrag(Control control) { if (controlPropertyDic.ContainsKey(control)) { controlPropertyDic.Remove(control); control.MouseDown -= control_MouseDown; control.MouseMove -= control_MouseMove; control.MouseLeave -= control_MouseLeave; } } void control_MouseLeave(object sender, EventArgs e) { m_MousePointPosition = EnumMousePointPosition.MouseSizeNone; Cursor.Current = Cursors.Arrow; } void control_MouseMove(object sender, MouseEventArgs e) { Control lCtrl = (sender as Control); DragControlProperty property = GetControlProperty(lCtrl); if (e.Button == MouseButtons.Left) { switch (m_MousePointPosition) { case EnumMousePointPosition.MouseDrag: lCtrl.Left = lCtrl.Left + e.X - property.PositionMovePoint.X; lCtrl.Top = lCtrl.Top + e.Y - property.PositionMovePoint.Y; break; case EnumMousePointPosition.MouseSizeBottom: lCtrl.Height = lCtrl.Height + e.Y - property.SizeChangeMovePoint.Y; property.SizeChangeMovePoint = e.Location; //'記錄光標拖動的當前點 break; case EnumMousePointPosition.MouseSizeBottomRight: lCtrl.Width = lCtrl.Width + e.X - property.SizeChangeMovePoint.X; lCtrl.Height = lCtrl.Height + e.Y - property.SizeChangeMovePoint.Y; property.SizeChangeMovePoint = e.Location; //'記錄光標拖動的當前點 break; case EnumMousePointPosition.MouseSizeRight: lCtrl.Width = lCtrl.Width + e.X - property.SizeChangeMovePoint.X; // lCtrl.Height = lCtrl.Height + e.Y - property.p1.Y; property.SizeChangeMovePoint = e.Location; //'記錄光標拖動的當前點 break; case EnumMousePointPosition.MouseSizeTop: lCtrl.Top = lCtrl.Top + (e.Y - property.PositionMovePoint.Y); lCtrl.Height = lCtrl.Height - (e.Y - property.PositionMovePoint.Y); break; case EnumMousePointPosition.MouseSizeLeft: lCtrl.Left = lCtrl.Left + e.X - property.PositionMovePoint.X; lCtrl.Width = lCtrl.Width - (e.X - property.PositionMovePoint.X); break; case EnumMousePointPosition.MouseSizeBottomLeft: lCtrl.Left = lCtrl.Left + e.X - property.PositionMovePoint.X; lCtrl.Width = lCtrl.Width - (e.X - property.PositionMovePoint.X); lCtrl.Height = lCtrl.Height + e.Y - property.SizeChangeMovePoint.Y; property.SizeChangeMovePoint = e.Location; //'記錄光標拖動的當前點 break; case EnumMousePointPosition.MouseSizeTopRight: lCtrl.Top = lCtrl.Top + (e.Y - property.PositionMovePoint.Y); lCtrl.Width = lCtrl.Width + (e.X - property.SizeChangeMovePoint.X); lCtrl.Height = lCtrl.Height - (e.Y - property.PositionMovePoint.Y); property.SizeChangeMovePoint = e.Location; //'記錄光標拖動的當前點 break; case EnumMousePointPosition.MouseSizeTopLeft: lCtrl.Left = lCtrl.Left + e.X - property.PositionMovePoint.X; lCtrl.Top = lCtrl.Top + (e.Y - property.PositionMovePoint.Y); lCtrl.Width = lCtrl.Width - (e.X - property.PositionMovePoint.X); lCtrl.Height = lCtrl.Height - (e.Y - property.PositionMovePoint.Y); break; default: break; } if (lCtrl.Width < MinWidth) lCtrl.Width = MinWidth; if (lCtrl.Height < MinHeight) lCtrl.Height = MinHeight; } else { m_MousePointPosition = MousePointPosition(lCtrl.Size, e); //'判斷光標的位置狀態 switch (m_MousePointPosition) //'改變光標 { case EnumMousePointPosition.MouseSizeNone: Cursor.Current = Cursors.Arrow; //'箭頭 break; case EnumMousePointPosition.MouseDrag: Cursor.Current = Cursors.SizeAll; //'四方向 break; case EnumMousePointPosition.MouseSizeBottom: Cursor.Current = Cursors.SizeNS; //'南北 break; case EnumMousePointPosition.MouseSizeTop: Cursor.Current = Cursors.SizeNS; //'南北 break; case EnumMousePointPosition.MouseSizeLeft: Cursor.Current = Cursors.SizeWE; //'東西 break; case EnumMousePointPosition.MouseSizeRight: Cursor.Current = Cursors.SizeWE; //'東西 break; case EnumMousePointPosition.MouseSizeBottomLeft: Cursor.Current = Cursors.SizeNESW; //'東北到南西 break; case EnumMousePointPosition.MouseSizeBottomRight: Cursor.Current = Cursors.SizeNWSE; //'東南到西北 break; case EnumMousePointPosition.MouseSizeTopLeft: Cursor.Current = Cursors.SizeNWSE; //'東南到西北 break; case EnumMousePointPosition.MouseSizeTopRight: Cursor.Current = Cursors.SizeNESW; //'東北到南西 break; default: break; } } } void control_MouseDown(object sender, MouseEventArgs e) { var property = GetControlProperty(sender as Control); property.PositionMovePoint = e.Location; property.SizeChangeMovePoint = e.Location; } private DragControlProperty GetControlProperty(Control control) { return controlPropertyDic[control]; } private EnumMousePointPosition MousePointPosition(Size size, System.Windows.Forms.MouseEventArgs e) { if ((e.X >= -1 * Band) | (e.X <= size.Width) | (e.Y >= -1 * Band) | (e.Y <= size.Height)) { if (e.X < Band) { if (e.Y < Band) { return EnumMousePointPosition.MouseSizeTopLeft; } else { if (e.Y > -1 * Band + size.Height) { return EnumMousePointPosition.MouseSizeBottomLeft; } else { return EnumMousePointPosition.MouseSizeLeft; } } } else { if (e.X > -1 * Band + size.Width) { if (e.Y < Band) { return EnumMousePointPosition.MouseSizeTopRight; } else { if (e.Y > -1 * Band + size.Height) { return EnumMousePointPosition.MouseSizeBottomRight; } else { return EnumMousePointPosition.MouseSizeRight; } } } else { if (e.Y < Band) { return EnumMousePointPosition.MouseSizeTop; } else { if (e.Y > -1 * Band + size.Height) { return EnumMousePointPosition.MouseSizeBottom; } else { return EnumMousePointPosition.MouseDrag; } } } } } else { return EnumMousePointPosition.MouseSizeNone; } } } }
這里是如何使用DragHelper的例子:
private void Form1_Load(object sender, EventArgs e) { DraggerHelper.EnableDrag(button1); DraggerHelper.EnableDrag(label1); DraggerHelper.DisableDrag(button1); DraggerHelper.DisableDrag(label1); } private void button1_Click(object sender, EventArgs e) { if (label1.IsControlCanDrag()) { label1.DisableDrag(); } else { label1.EnableDrag(); } }
完整的代碼:ControlDragger.rar
本文參考了:WCCC的傑出的文章:http://www.cnblogs.com/whc-blog/archive/2011/08/26/2154038.html
另外本文不討論設計,雖然我知道當前設計不一定是最好的,很多復雜的情況都沒有涵蓋到,不過基本的情況已經覆蓋了,歡迎大家擴展和填充。