前言:
很多時候我們需要在運行時,動態地改變控件的位置以及大小,以獲得更好的布局。比如說實際項目中的可自定義的報表、可自定義的單據等諸如此類。它們有個特點就是允許客戶或者二次開發人員設計它們需要的界面設置功能。
本人以前也做過可自定義系統,包括界面和功能,主要為了減少開發人員的工作量以及程序的靈活性和健壯性。
本篇主要討論下,在運行時如何實現拖拉控件,達到改變控件位置與大小。功能將模擬VS設計界面時的拖拉功能。
(本篇暫不涉及多控件同時操作)
一、技術概述
其實實現運行時控件的拖拉並不難,主要是改變控件的Location與Size即可。動態調整時再捕獲MouseDown、MouseMove及MouseUp事件來實時修改上述兩個屬性就可以實現。
二、功能規划
在此之前,我們先來看下.net設計界面,一旦選中某個控件時,將會出現如下圖的邊框:
之后就可以通過拖拉出現的邊框改變其大小。而改變控件的位置,實際上是當鼠標點擊在控件內部拖動時實現的。
所有本例也將功能分為兩個部分實現,分別為控件內部拖動改變位置與控件邊框拖拉改變大小。
三、具體實現
1.拖動控件改變位置
首先,新建一個項目,然后添加一個類,取名叫MoveControl,該類用來給控件掛載事件實現拖動。
接着在該類中添加字段currentControl,用來保存需要操作的控件,即通過構造函數傳遞的控件。
接着創建一方法--AddEvents,用來給當前的控件掛載事件。
代碼如下:

1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Windows.Forms; 5 using System.Drawing; 6 7 namespace DragControl 8 { 9 public class MoveControl 10 { 11 #region Constructors 12 public MoveControl(Control ctrl) 13 { 14 currentControl = ctrl; 15 AddEvents(); 16 } 17 #endregion 18 19 #region Fields 20 private Control currentControl; //傳入的控件 21 #endregion 22 23 #region Properties 24 25 #endregion 26 27 #region Methods 28 /// <summary> 29 /// 掛載事件 30 /// </summary> 31 private void AddEvents() 32 { 33 currentControl.MouseClick += new MouseEventHandler(MouseClick); 34 currentControl.MouseDown += new MouseEventHandler(MouseDown); 35 currentControl.MouseMove += new MouseEventHandler(MouseMove); 36 currentControl.MouseUp += new MouseEventHandler(MouseUp); 37 } 38 #endregion 39 40 #region Events 41 /// <summary> 42 /// 鼠標單擊事件:用來顯示邊框 43 /// </summary> 44 /// <param name="sender"></param> 45 /// <param name="e"></param> 46 void MouseClick(object sender, MouseEventArgs e) 47 { 48 } 49 50 /// <summary> 51 /// 鼠標按下事件:記錄當前鼠標相對窗體的坐標 52 /// </summary> 53 void MouseDown(object sender, MouseEventArgs e) 54 { 55 56 } 57 58 /// <summary> 59 /// 鼠標移動事件:讓控件跟着鼠標移動 60 /// </summary> 61 void MouseMove(object sender, MouseEventArgs e) 62 { 63 } 64 65 /// <summary> 66 /// 鼠標彈起事件:讓自定義的邊框出現 67 /// </summary> 68 void MouseUp(object sender, MouseEventArgs e) 69 { 70 } 71 #endregion 72 } 73 }
接着我們需要實現MouseDown、MouseMove、MouseUp三個事件。
不過在此之前,我們必須要弄清楚,移動即表示坐標的改變,所以必定要有個起始坐標和終點坐標。
所以我們在MoveControl類中加入兩個字段。
private Point pPoint; //上個鼠標坐標 private Point cPoint; //當前鼠標坐標
而且在開始拖動之前,我們肯定需要先單擊一次控件。在MouseDown時獲取當前光標的位置,保存到pPoint中。
(此處用Cursor獲得坐標的好處,就是忽略掉容器的麻煩問題)
1 /// <summary> 2 /// 鼠標單擊事件:用來顯示邊框 3 /// </summary> 4 void MouseClick(object sender, MouseEventArgs e) 5 { 6 pPoint = Cursor.Position; 7 }
接着便實現MouseMove的事件,當鼠標左鍵按下時,接着移動鼠標后,繼續鼠標移動后的坐標,然后與MouseDown時記下的坐標相減,就得到鼠標的位移值,接着控件的Location加上該位移值即可,然后更新pPoint。
1 /// <summary> 2 /// 鼠標移動事件:讓控件跟着鼠標移動 3 /// </summary> 4 void MouseMove(object sender, MouseEventArgs e) 5 { 6 Cursor.Current = Cursors.SizeAll; //當鼠標處於控件內部時,顯示光標樣式為SizeAll 7 //當鼠標左鍵按下時才觸發 8 if (e.Button == MouseButtons.Left) 9 { 10 cPoint = Cursor.Position; //獲得當前鼠標位置 11 int x = cPoint.X - pPoint.X; 12 int y = cPoint.Y - pPoint.Y; 13 currentControl.Location = new Point(currentControl.Location.X + x, currentControl.Location.Y + y); 14 pPoint = cPoint; 15 } 16 }
由於此時還沒涉及到邊框,所以MouseUp暫時不用處理。至此拖動的基本功能已經實現!
目前MoveControl的完整代碼如下:

1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Windows.Forms; 5 using System.Drawing; 6 7 namespace DragControl 8 { 9 public class MoveControl 10 { 11 #region Constructors 12 public MoveControl(Control ctrl) 13 { 14 currentControl = ctrl; 15 AddEvents(); 16 } 17 #endregion 18 19 #region Fields 20 private Control currentControl; //傳入的控件 21 private Point pPoint; //上個鼠標坐標 22 private Point cPoint; //當前鼠標坐標 23 #endregion 24 25 #region Properties 26 27 #endregion 28 29 #region Methods 30 /// <summary> 31 /// 掛載事件 32 /// </summary> 33 private void AddEvents() 34 { 35 currentControl.MouseDown += new MouseEventHandler(MouseDown); 36 currentControl.MouseMove += new MouseEventHandler(MouseMove); 37 currentControl.MouseUp += new MouseEventHandler(MouseUp); 38 } 39 40 /// <summary> 41 /// 繪制拖拉時的黑色邊框 42 /// </summary> 43 public static void DrawDragBound(Control ctrl) 44 { 45 ctrl.Refresh(); 46 Graphics g = ctrl.CreateGraphics(); 47 int width = ctrl.Width; 48 int height = ctrl.Height; 49 Point[] ps = new Point[5]{new Point(0,0),new Point(width -1,0), 50 new Point(width -1,height -1),new Point(0,height-1),new Point(0,0)}; 51 g.DrawLines(new Pen(Color.Black), ps); 52 } 53 #endregion 54 55 #region Events 56 /// <summary> 57 /// 鼠標按下事件:記錄當前鼠標相對窗體的坐標 58 /// </summary> 59 void MouseDown(object sender, MouseEventArgs e) 60 { 61 pPoint = Cursor.Position; 62 } 63 64 /// <summary> 65 /// 鼠標移動事件:讓控件跟着鼠標移動 66 /// </summary> 67 void MouseMove(object sender, MouseEventArgs e) 68 { 69 Cursor.Current = Cursors.SizeAll; //當鼠標處於控件內部時,顯示光標樣式為SizeAll 70 //當鼠標左鍵按下時才觸發 71 if (e.Button == MouseButtons.Left) 72 { 73 MoveControl.DrawDragBound(this.currentControl); 74 cPoint = Cursor.Position; //獲得當前鼠標位置 75 int x = cPoint.X - pPoint.X; 76 int y = cPoint.Y - pPoint.Y; 77 currentControl.Location = new Point(currentControl.Location.X + x, currentControl.Location.Y + y); 78 pPoint = cPoint; 79 } 80 } 81 82 /// <summary> 83 /// 鼠標彈起事件:讓自定義的邊框出現 84 /// </summary> 85 void MouseUp(object sender, MouseEventArgs e) 86 { 87 this.currentControl.Refresh(); 88 } 89 #endregion 90 } 91 }
下面我們來測試下拖動的功能。
創建一個Form窗體,可以再界面上添加你要測試的控件類型,此處我只用TextBox左下測試。在Load的中添加以下代碼,將Form中的所有控件掛載上拖拉功能。
1 private void Form1_Load(object sender, EventArgs e) 2 { 3 foreach (Control ctrl in this.Controls) 4 { 5 new MoveControl(ctrl); 6 } 7 }
此時,有心人可能會發現VS中拖動控件時,將會出現黑色邊框,而處於沒有。
這也很簡單,我們在MouseMove時加上如下代碼即可。
1 /// <summary> 2 /// 繪制拖拉時的黑色邊框 3 /// </summary> 4 public static void DrawDragBound(Control ctrl) 5 { 6 ctrl.Refresh(); 7 Graphics g = ctrl.CreateGraphics(); 8 int width = ctrl.Width; 9 int height = ctrl.Height; 10 Point[] ps = new Point[5]{new Point(0,0),new Point(width -1,0), 11 new Point(width -1,height -1),new Point(0,height-1),new Point(0,0)}; 12 g.DrawLines(new Pen(Color.Black), ps); 13 } 14 15 16 /// <summary> 17 /// 鼠標移動事件:讓控件跟着鼠標移動 18 /// </summary> 19 void MouseMove(object sender, MouseEventArgs e) 20 { 21 Cursor.Current = Cursors.SizeAll; //當鼠標處於控件內部時,顯示光標樣式為SizeAll 22 //當鼠標左鍵按下時才觸發 23 if (e.Button == MouseButtons.Left) 24 { 25 MoveControl.DrawDragBound(this.currentControl); 26 cPoint = Cursor.Position; //獲得當前鼠標位置 27 int x = cPoint.X - pPoint.X; 28 int y = cPoint.Y - pPoint.Y; 29 currentControl.Location = new Point(currentControl.Location.X + x, currentControl.Location.Y + y); 30 pPoint = cPoint; 31 } 32 }
同時要在MoveUp的時候,刷新一下自己,讓黑色邊框消失掉!
1 /// <summary> 2 /// 鼠標彈起事件:讓自定義的邊框出現 3 /// </summary> 4 void MouseUp(object sender, MouseEventArgs e) 5 { 6 this.currentControl.Refresh(); 7 }
接着用沒有邊框的控件測試下就會很明顯。如下圖所示:
2.通過邊框拖拉控件改變大小
此處的主要思路為:點擊控件的時候,創建一個自定義的用戶控件,該用戶控件響應區域就是傳入控件的邊框區域,同時給它畫上虛線與8個小圓圈。
第一、創建用戶控件--FrameControl(邊框控件),然后增加一個字段用來保存傳入的控件,還有加載事件,此處類同前面的MoveControl。

1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Drawing; 5 using System.Data; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 10 namespace DragControl 11 { 12 public partial class FrameControl : UserControl 13 { 14 #region Constructors 15 public FrameControl(Control ctrl) 16 { 17 baseControl = ctrl; 18 AddEvents(); 19 } 20 #endregion 21 22 #region Fields 23 Control baseControl; //基礎控件,即被包圍的控件 24 #endregion 25 26 #region Methods 27 /// <summary> 28 /// 加載事件 29 /// </summary> 30 private void AddEvents() 31 { 32 this.Name = "FrameControl" + baseControl.Name; 33 this.MouseDown += new MouseEventHandler(FrameControl_MouseDown); 34 this.MouseMove += new MouseEventHandler(FrameControl_MouseMove); 35 this.MouseUp += new MouseEventHandler(FrameControl_MouseUp); 36 } 37 38 #endregion 39 40 #region Events 41 /// <summary> 42 /// 鼠標按下事件:記錄當前鼠標相對窗體的坐標 43 /// </summary> 44 void FrameControl_MouseDown(object sender, MouseEventArgs e) 45 { 46 47 } 48 49 /// <summary> 50 /// 鼠標移動事件:讓控件跟着鼠標移動 51 /// </summary> 52 void FrameControl_MouseMove(object sender, MouseEventArgs e) 53 { 54 55 } 56 57 /// <summary> 58 /// 鼠標彈起事件:讓自定義的邊框出現 59 /// </summary> 60 void FrameControl_MouseUp(object sender, MouseEventArgs e) 61 { 62 63 } 64 #endregion 65 } 66 }
做完這些准備工作后,將到了主要的部分,就是給控件畫邊框。
整個邊框分為三個部分:四邊框(用來設置可視區域與區域)+四條虛線(只用來顯示)+八個小圓圈(用來斜角拖拉)。
所以要建立三個字段,用來分別保存這個數據。
Rectangle[] smallRects = new Rectangle[8];//邊框中的八個小圓圈 Rectangle[] sideRects = new Rectangle[4];//四條邊框,用來做響應區域 Point[] linePoints = new Point[5];//四條邊,用於畫虛線
接着就是創建用戶控件的可視區域,和上面的三個變量數值。
(以下計算位置的代碼,有興趣的人可以研究下,沒有的就直接Copy)

1 #region 創建邊框 2 /// <summary> 3 /// 建立控件可視區域 4 /// </summary> 5 private void CreateBounds() 6 { 7 //創建邊界 8 int X = baseControl.Bounds.X - square.Width - 1; 9 int Y = baseControl.Bounds.Y - square.Height - 1; 10 int Height = baseControl.Bounds.Height + (square.Height * 2) + 2; 11 int Width = baseControl.Bounds.Width + (square.Width * 2) + 2; 12 this.Bounds = new Rectangle(X, Y, Width, Height); 13 this.BringToFront(); 14 SetRectangles(); 15 //設置可視區域 16 this.Region = new Region(BuildFrame()); 17 g = this.CreateGraphics(); 18 } 19 20 /// <summary> 21 /// 設置定義8個小矩形的范圍 22 /// </summary> 23 void SetRectangles() 24 { 25 //左上 26 smallRects[0] = new Rectangle(new Point(0, 0), square); 27 //右上 28 smallRects[1] = new Rectangle(new Point(this.Width - square.Width - 1, 0), square); 29 //左下 30 smallRects[2] = new Rectangle(new Point(0, this.Height - square.Height - 1), square); 31 //右下 32 smallRects[3] = new Rectangle(new Point(this.Width - square.Width - 1, this.Height - square.Height - 1), square); 33 //上中 34 smallRects[4] = new Rectangle(new Point(this.Width / 2 - 1, 0), square); 35 //下中 36 smallRects[5] = new Rectangle(new Point(this.Width / 2 - 1, this.Height - square.Height - 1), square); 37 //左中 38 smallRects[6] = new Rectangle(new Point(0, this.Height / 2 - 1), square); 39 //右中 40 smallRects[7] = new Rectangle(new Point(square.Width + baseControl.Width + 1, this.Height / 2 - 1), square); 41 42 //四條邊線 43 //左上 44 linePoints[0] = new Point(square.Width / 2, square.Height / 2); 45 //右上 46 linePoints[1] = new Point(this.Width - square.Width / 2 - 1, square.Height / 2); 47 //右下 48 linePoints[2] = new Point(this.Width - square.Width / 2 - 1, this.Height - square.Height / 2); 49 //左下 50 linePoints[3] = new Point(square.Width / 2, this.Height - square.Height / 2 - 1); 51 //左上 52 linePoints[4] = new Point(square.Width / 2, square.Height / 2); 53 54 //整個包括周圍邊框的范圍 55 ControlRect = new Rectangle(new Point(0, 0), this.Bounds.Size); 56 } 57 58 /// <summary> 59 /// 設置邊框控件可視區域 60 /// </summary> 61 /// <returns></returns> 62 private GraphicsPath BuildFrame() 63 { 64 GraphicsPath path = new GraphicsPath(); 65 //上邊框 66 sideRects[0] = new Rectangle(0, 0, this.Width - square.Width - 1, square.Height + 1); 67 //左邊框 68 sideRects[1] = new Rectangle(0, square.Height + 1, square.Width + 1, this.Height - square.Height - 1); 69 //下邊框 70 sideRects[2] = new Rectangle(square.Width + 1, this.Height - square.Height - 1, this.Width - square.Width - 1, square.Height + 1); 71 //右邊框 72 sideRects[3] = new Rectangle(this.Width - square.Width - 1, 0, square.Width + 1, this.Height - square.Height - 1); 73 74 path.AddRectangle(sideRects[0]); 75 path.AddRectangle(sideRects[1]); 76 path.AddRectangle(sideRects[2]); 77 path.AddRectangle(sideRects[3]); 78 return path; 79 } 80 #endregion
設置完位置后,接着就是繪制的工作。增加一個Draw的方法用來畫,同時設置為Public。此處不用控件的Paint,而是讓用戶調用,只因為這樣方便在不同控件之間切換,也就是一個容器中,只有當前控件有邊框。
1 /// <summary> 2 /// 繪圖 3 /// </summary> 4 public void Draw() 5 { 6 this.BringToFront(); 7 Pen pen = new Pen(Color.Black); 8 pen.DashStyle = DashStyle.Dot;//設置為虛線,用虛線畫四邊,模擬微軟效果 9 g.DrawLines(pen, linePoints);//繪制四條邊線 10 g.FillRectangles(Brushes.White, smallRects); //填充8個小矩形的內部 11 foreach (Rectangle smallRect in smallRects) 12 { 13 g.DrawEllipse(Pens.Black, smallRect); //繪制8個小橢圓 14 } 15 //g.DrawRectangles(Pens.Black, smallRects); //繪制8個小矩形的黑色邊線 16 }
做到這里,我們可以去前台看一下效果,不過再此之前,我們需要調用該用戶控件。
調用的地方就是在控件上點擊的時候,所以在MoveControl中加入MouseClick的事件。
1 /// <summary> 2 /// 鼠標單擊事件:用來顯示邊框 3 /// </summary> 4 /// <param name="sender"></param> 5 /// <param name="e"></param> 6 protected void MouseClick(object sender, MouseEventArgs e) 7 { 8 this.currentControl.Parent.Refresh();//刷新父容器,清除掉其他控件的邊框 9 this.currentControl.BringToFront(); 10 fc = new FrameControl(this.currentControl); 11 this.currentControl.Parent.Controls.Add(fc); 12 fc.Visible = true; 13 fc.Draw(); 14 }
這時有了邊框之后會有一個小問題,就是拖動控件的時候,控件移動了,但是邊框還留在原地。
所以,這里需要注意的,就是移動的時候,將邊框控件隱藏掉,當MouseUp的時候再顯示。
此時的完整代碼如下:

1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Windows.Forms; 5 using System.Drawing; 6 7 namespace DragControl 8 { 9 public class MoveControl 10 { 11 #region Constructors 12 public MoveControl(Control ctrl) 13 { 14 currentControl = ctrl; 15 AddEvents(); 16 } 17 #endregion 18 19 #region Fields 20 private Control currentControl; //傳入的控件 21 private Point pPoint; //上個鼠標坐標 22 private Point cPoint; //當前鼠標坐標 23 FrameControl fc;//邊框控件 24 #endregion 25 26 #region Properties 27 28 #endregion 29 30 #region Methods 31 /// <summary> 32 /// 掛載事件 33 /// </summary> 34 private void AddEvents() 35 { 36 currentControl.MouseClick += new MouseEventHandler(MouseClick); 37 currentControl.MouseDown += new MouseEventHandler(MouseDown); 38 currentControl.MouseMove += new MouseEventHandler(MouseMove); 39 currentControl.MouseUp += new MouseEventHandler(MouseUp); 40 } 41 42 /// <summary> 43 /// 繪制拖拉時的黑色邊框 44 /// </summary> 45 public static void DrawDragBound(Control ctrl) 46 { 47 ctrl.Refresh(); 48 Graphics g = ctrl.CreateGraphics(); 49 int width = ctrl.Width; 50 int height = ctrl.Height; 51 Point[] ps = new Point[5]{new Point(0,0),new Point(width -1,0), 52 new Point(width -1,height -1),new Point(0,height-1),new Point(0,0)}; 53 g.DrawLines(new Pen(Color.Black), ps); 54 } 55 #endregion 56 57 #region Events 58 /// <summary> 59 /// 鼠標單擊事件:用來顯示邊框 60 /// </summary> 61 /// <param name="sender"></param> 62 /// <param name="e"></param> 63 protected void MouseClick(object sender, MouseEventArgs e) 64 { 65 this.currentControl.Parent.Refresh();//刷新父容器,清除掉其他控件的邊框 66 this.currentControl.BringToFront(); 67 fc = new FrameControl(this.currentControl); 68 this.currentControl.Parent.Controls.Add(fc); 69 fc.Visible = true; 70 fc.Draw(); 71 } 72 73 /// <summary> 74 /// 鼠標按下事件:記錄當前鼠標相對窗體的坐標 75 /// </summary> 76 void MouseDown(object sender, MouseEventArgs e) 77 { 78 pPoint = Cursor.Position; 79 } 80 81 /// <summary> 82 /// 鼠標移動事件:讓控件跟着鼠標移動 83 /// </summary> 84 void MouseMove(object sender, MouseEventArgs e) 85 { 86 Cursor.Current = Cursors.SizeAll; //當鼠標處於控件內部時,顯示光標樣式為SizeAll 87 //當鼠標左鍵按下時才觸發 88 if (e.Button == MouseButtons.Left) 89 { 90 MoveControl.DrawDragBound(this.currentControl); 91 if (fc != null) fc.Visible = false; //先隱藏 92 cPoint = Cursor.Position; //獲得當前鼠標位置 93 int x = cPoint.X - pPoint.X; 94 int y = cPoint.Y - pPoint.Y; 95 currentControl.Location = new Point(currentControl.Location.X + x, currentControl.Location.Y + y); 96 pPoint = cPoint; 97 } 98 } 99 100 /// <summary> 101 /// 鼠標彈起事件:讓自定義的邊框出現 102 /// </summary> 103 void MouseUp(object sender, MouseEventArgs e) 104 { 105 this.currentControl.Refresh(); 106 if (fc != null) 107 { 108 fc.Visible = true; 109 fc.Draw(); 110 } 111 } 112 #endregion 113 } 114 }

1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Drawing; 5 using System.Data; 6 using System.Text; 7 using System.Windows.Forms; 8 using System.Drawing.Drawing2D; 9 10 namespace DragControl 11 { 12 public partial class FrameControl : UserControl 13 { 14 #region Constructors 15 public FrameControl(Control ctrl) 16 { 17 baseControl = ctrl; 18 AddEvents(); 19 CreateBounds(); 20 } 21 #endregion 22 23 #region Fields 24 const int Band = 6; //調整大小的響應邊框 25 Size square = new Size(Band, Band);//小矩形大小 26 Control baseControl; //基礎控件,即被包圍的控件 27 Rectangle[] smallRects = new Rectangle[8];//邊框中的八個小圓圈 28 Rectangle[] sideRects = new Rectangle[4];//四條邊框,用來做響應區域 29 Point[] linePoints = new Point[5];//四條邊,用於畫虛線 30 Graphics g; //畫圖板 31 Rectangle ControlRect; //控件包含邊框的區域 32 #endregion 33 34 #region Methods 35 /// <summary> 36 /// 加載事件 37 /// </summary> 38 private void AddEvents() 39 { 40 this.Name = "FrameControl" + baseControl.Name; 41 this.MouseDown += new MouseEventHandler(FrameControl_MouseDown); 42 this.MouseMove += new MouseEventHandler(FrameControl_MouseMove); 43 this.MouseUp += new MouseEventHandler(FrameControl_MouseUp); 44 } 45 46 #region 創建邊框 47 /// <summary> 48 /// 建立控件可視區域 49 /// </summary> 50 private void CreateBounds() 51 { 52 //創建邊界 53 int X = baseControl.Bounds.X - square.Width - 1; 54 int Y = baseControl.Bounds.Y - square.Height - 1; 55 int Height = baseControl.Bounds.Height + (square.Height * 2) + 2; 56 int Width = baseControl.Bounds.Width + (square.Width * 2) + 2; 57 this.Bounds = new Rectangle(X, Y, Width, Height); 58 this.BringToFront(); 59 SetRectangles(); 60 //設置可視區域 61 this.Region = new Region(BuildFrame()); 62 g = this.CreateGraphics(); 63 } 64 65 /// <summary> 66 /// 設置定義8個小矩形的范圍 67 /// </summary> 68 void SetRectangles() 69 { 70 //左上 71 smallRects[0] = new Rectangle(new Point(0, 0), square); 72 //右上 73 smallRects[1] = new Rectangle(new Point(this.Width - square.Width - 1, 0), square); 74 //左下 75 smallRects[2] = new Rectangle(new Point(0, this.Height - square.Height - 1), square); 76 //右下 77 smallRects[3] = new Rectangle(new Point(this.Width - square.Width - 1, this.Height - square.Height - 1), square); 78 //上中 79 smallRects[4] = new Rectangle(new Point(this.Width / 2 - 1, 0), square); 80 //下中 81 smallRects[5] = new Rectangle(new Point(this.Width / 2 - 1, this.Height - square.Height - 1), square); 82 //左中 83 smallRects[6] = new Rectangle(new Point(0, this.Height / 2 - 1), square); 84 //右中 85 smallRects[7] = new Rectangle(new Point(square.Width + baseControl.Width + 1, this.Height / 2 - 1), square); 86 87 //四條邊線 88 //左上 89 linePoints[0] = new Point(square.Width / 2, square.Height / 2); 90 //右上 91 linePoints[1] = new Point(this.Width - square.Width / 2 - 1, square.Height / 2); 92 //右下 93 linePoints[2] = new Point(this.Width - square.Width / 2 - 1, this.Height - square.Height / 2); 94 //左下 95 linePoints[3] = new Point(square.Width / 2, this.Height - square.Height / 2 - 1); 96 //左上 97 linePoints[4] = new Point(square.Width / 2, square.Height / 2); 98 99 //整個包括周圍邊框的范圍 100 ControlRect = new Rectangle(new Point(0, 0), this.Bounds.Size); 101 } 102 103 /// <summary> 104 /// 設置邊框控件可視區域 105 /// </summary> 106 /// <returns></returns> 107 private GraphicsPath BuildFrame() 108 { 109 GraphicsPath path = new GraphicsPath(); 110 //上邊框 111 sideRects[0] = new Rectangle(0, 0, this.Width - square.Width - 1, square.Height + 1); 112 //左邊框 113 sideRects[1] = new Rectangle(0, square.Height + 1, square.Width + 1, this.Height - square.Height - 1); 114 //下邊框 115 sideRects[2] = new Rectangle(square.Width + 1, this.Height - square.Height - 1, this.Width - square.Width - 1, square.Height + 1); 116 //右邊框 117 sideRects[3] = new Rectangle(this.Width - square.Width - 1, 0, square.Width + 1, this.Height - square.Height - 1); 118 119 path.AddRectangle(sideRects[0]); 120 path.AddRectangle(sideRects[1]); 121 path.AddRectangle(sideRects[2]); 122 path.AddRectangle(sideRects[3]); 123 return path; 124 } 125 #endregion 126 127 /// <summary> 128 /// 繪圖 129 /// </summary> 130 public void Draw() 131 { 132 this.BringToFront(); 133 Pen pen = new Pen(Color.Black); 134 pen.DashStyle = DashStyle.Dot;//設置為虛線,用虛線畫四邊,模擬微軟效果 135 g.DrawLines(pen, linePoints);//繪制四條邊線 136 g.FillRectangles(Brushes.White, smallRects); //填充8個小矩形的內部 137 foreach (Rectangle smallRect in smallRects) 138 { 139 g.DrawEllipse(Pens.Black, smallRect); //繪制8個小橢圓 140 } 141 //g.DrawRectangles(Pens.Black, smallRects); //繪制8個小矩形的黑色邊線 142 } 143 144 #endregion 145 146 #region Events 147 /// <summary> 148 /// 鼠標按下事件:記錄當前鼠標相對窗體的坐標 149 /// </summary> 150 void FrameControl_MouseDown(object sender, MouseEventArgs e) 151 { 152 153 } 154 155 /// <summary> 156 /// 鼠標移動事件:讓控件跟着鼠標移動 157 /// </summary> 158 void FrameControl_MouseMove(object sender, MouseEventArgs e) 159 { 160 161 } 162 163 /// <summary> 164 /// 鼠標彈起事件:讓自定義的邊框出現 165 /// </summary> 166 void FrameControl_MouseUp(object sender, MouseEventArgs e) 167 { 168 169 } 170 #endregion 171 } 172 }
測試界面:
到目前為止,還只是有邊框,下面將實現拖拉功能。
首先來實現,當鼠標放在響應區域的時候,根據不同的位置顯示不同的箭頭樣子。
為此先創建一個枚舉,用來記錄當前鼠標的位置,等拖拉的時候根據該枚舉值做不同的計算。
1 /// <summary> 2 /// 鼠標在控件中位置 3 /// </summary> 4 enum MousePosOnCtrl 5 { 6 NONE = 0, 7 TOP = 1, 8 RIGHT = 2, 9 BOTTOM = 3, 10 LEFT = 4, 11 TOPLEFT = 5, 12 TOPRIGHT = 6, 13 BOTTOMLEFT = 7, 14 BOTTOMRIGHT = 8, 15 }
創建一個方法,用來改變光標的樣子以及枚舉值
1 /// <summary> 2 /// 設置光標狀態 3 /// </summary> 4 public bool SetCursorShape(int x, int y) 5 { 6 Point point = new Point(x, y); 7 if (!ControlRect.Contains(point)) 8 { 9 Cursor.Current = Cursors.Arrow; 10 return false; 11 } 12 else if (smallRects[0].Contains(point)) 13 { 14 Cursor.Current = Cursors.SizeNWSE; 15 mpoc = MousePosOnCtrl.TOPLEFT; 16 } 17 else if (smallRects[1].Contains(point)) 18 { 19 Cursor.Current = Cursors.SizeNESW; 20 mpoc = MousePosOnCtrl.TOPRIGHT; 21 } 22 else if (smallRects[2].Contains(point)) 23 { 24 Cursor.Current = Cursors.SizeNESW; 25 mpoc = MousePosOnCtrl.BOTTOMLEFT; 26 } 27 else if (smallRects[3].Contains(point)) 28 { 29 Cursor.Current = Cursors.SizeNWSE; 30 mpoc = MousePosOnCtrl.BOTTOMRIGHT; 31 } 32 else if (sideRects[0].Contains(point)) 33 { 34 Cursor.Current = Cursors.SizeNS; 35 mpoc = MousePosOnCtrl.TOP; 36 } 37 else if (sideRects[1].Contains(point)) 38 { 39 Cursor.Current = Cursors.SizeWE; 40 mpoc = MousePosOnCtrl.LEFT; 41 } 42 else if (sideRects[2].Contains(point)) 43 { 44 Cursor.Current = Cursors.SizeNS; 45 mpoc = MousePosOnCtrl.BOTTOM; 46 } 47 else if (sideRects[3].Contains(point)) 48 { 49 Cursor.Current = Cursors.SizeWE; 50 mpoc = MousePosOnCtrl.RIGHT; 51 } 52 else 53 { 54 Cursor.Current = Cursors.Arrow; 55 } 56 return true; 57 }
接着就是處理相關的三大事件MouseDown、MouseMove、MouseUp來實現拖拉。如同MoveControl都要增加以下兩個字段。
private Point pPoint; //上個鼠標坐標 private Point cPoint; //當前鼠標坐標
1 /// <summary> 2 /// 鼠標按下事件:記錄當前鼠標相對窗體的坐標 3 /// </summary> 4 void FrameControl_MouseDown(object sender, MouseEventArgs e) 5 { 6 pPoint = Cursor.Position; 7 } 8 9 /// <summary> 10 /// 鼠標移動事件:讓控件跟着鼠標移動 11 /// </summary> 12 void FrameControl_MouseMove(object sender, MouseEventArgs e) 13 { 14 if (e.Button == MouseButtons.Left) 15 { 16 this.Visible = false; 17 MoveControl.DrawDragBound(baseControl); 18 ControlMove(); 19 } 20 else 21 { 22 this.Visible = true; 23 SetCursorShape(e.X, e.Y); //更新鼠標指針樣式 24 } 25 } 26 27 /// <summary> 28 /// 鼠標彈起事件:讓自定義的邊框出現 29 /// </summary> 30 void FrameControl_MouseUp(object sender, MouseEventArgs e) 31 { 32 this.baseControl.Refresh(); //刷掉黑色邊框 33 this.Visible = true; 34 CreateBounds(); 35 Draw(); 36 }
在上面的MouseMove中多了一個方法--ControlMove,這個就是根據不同的枚舉值,計算控件的移動方式和大小的方法。該方法中同時對控件的最小寬度和高度做了處理。添加如下兩個字段。
private int MinWidth = 20; //最小寬度 private int MinHeight = 20;//最小高度
1 /// <summary> 2 /// 控件移動 3 /// </summary> 4 private void ControlMove() 5 { 6 cPoint = Cursor.Position; 7 int x = cPoint.X - pPoint.X; 8 int y = cPoint.Y - pPoint.Y; 9 switch (this.mpoc) 10 { 11 case MousePosOnCtrl.TOP: 12 if (baseControl.Height - y > MinHeight) 13 { 14 baseControl.Top += y; 15 baseControl.Height -= y; 16 } 17 else 18 { 19 baseControl.Top -= MinHeight - baseControl.Height; 20 baseControl.Height = MinHeight; 21 } 22 break; 23 case MousePosOnCtrl.BOTTOM: 24 if (baseControl.Height + y > MinHeight) 25 { 26 baseControl.Height += y; 27 } 28 else 29 { 30 baseControl.Height = MinHeight; 31 } 32 break; 33 case MousePosOnCtrl.LEFT: 34 if (baseControl.Width - x > MinWidth) 35 { 36 baseControl.Left += x; 37 baseControl.Width -= x; 38 } 39 else 40 { 41 baseControl.Left -= MinWidth - baseControl.Width; 42 baseControl.Width = MinWidth; 43 } 44 45 break; 46 case MousePosOnCtrl.RIGHT: 47 if (baseControl.Width + x > MinWidth) 48 { 49 baseControl.Width += x; 50 } 51 else 52 { 53 baseControl.Width = MinWidth; 54 } 55 break; 56 case MousePosOnCtrl.TOPLEFT: 57 if (baseControl.Height - y > MinHeight) 58 { 59 baseControl.Top += y; 60 baseControl.Height -= y; 61 } 62 else 63 { 64 baseControl.Top -= MinHeight - baseControl.Height; 65 baseControl.Height = MinHeight; 66 } 67 if (baseControl.Width - x > MinWidth) 68 { 69 baseControl.Left += x; 70 baseControl.Width -= x; 71 } 72 else 73 { 74 baseControl.Left -= MinWidth - baseControl.Width; 75 baseControl.Width = MinWidth; 76 } 77 break; 78 case MousePosOnCtrl.TOPRIGHT: 79 if (baseControl.Height - y > MinHeight) 80 { 81 baseControl.Top += y; 82 baseControl.Height -= y; 83 } 84 else 85 { 86 baseControl.Top -= MinHeight - baseControl.Height; 87 baseControl.Height = MinHeight; 88 } 89 if (baseControl.Width + x > MinWidth) 90 { 91 baseControl.Width += x; 92 } 93 else 94 { 95 baseControl.Width = MinWidth; 96 } 97 break; 98 case MousePosOnCtrl.BOTTOMLEFT: 99 if (baseControl.Height + y > MinHeight) 100 { 101 baseControl.Height += y; 102 } 103 else 104 { 105 baseControl.Height = MinHeight; 106 } 107 if (baseControl.Width - x > MinWidth) 108 { 109 baseControl.Left += x; 110 baseControl.Width -= x; 111 } 112 else 113 { 114 baseControl.Left -= MinWidth - baseControl.Width; 115 baseControl.Width = MinWidth; 116 } 117 break; 118 case MousePosOnCtrl.BOTTOMRIGHT: 119 if (baseControl.Height + y > MinHeight) 120 { 121 baseControl.Height += y; 122 } 123 else 124 { 125 baseControl.Height = MinHeight; 126 } 127 if (baseControl.Width + x > MinWidth) 128 { 129 baseControl.Width += x; 130 } 131 else 132 { 133 baseControl.Width = MinWidth; 134 } 135 break; 136 137 } 138 pPoint = Cursor.Position; 139 }
到此為止,功能已經基本上實現。
完成代碼如下:

1 /****************************************************************** 2 * 創 建 人: SamWang 3 * 創建時間: 2012-5-10 16:06 4 * 描 述: 5 * 移動控件但不改變大小 6 * 原 理: 7 * 版 本: V1.0 8 * 環 境: VS2010 9 ******************************************************************/ 10 using System; 11 using System.Collections.Generic; 12 using System.Linq; 13 using System.Text; 14 using System.Windows.Forms; 15 using System.Drawing; 16 17 namespace DragControl 18 { 19 public class MoveControl 20 { 21 #region Constructors 22 public MoveControl(Control ctrl) 23 { 24 currentControl = ctrl; 25 AddEvents(); 26 } 27 #endregion 28 29 #region Fields 30 private Control currentControl; //傳入的控件 31 private Point pPoint; //上個鼠標坐標 32 private Point cPoint; //當前鼠標坐標 33 FrameControl fc;//邊框控件 34 #endregion 35 36 #region Properties 37 38 #endregion 39 40 #region Methods 41 /// <summary> 42 /// 掛載事件 43 /// </summary> 44 private void AddEvents() 45 { 46 currentControl.MouseClick += new MouseEventHandler(MouseClick); 47 currentControl.MouseDown += new MouseEventHandler(MouseDown); 48 currentControl.MouseMove += new MouseEventHandler(MouseMove); 49 currentControl.MouseUp += new MouseEventHandler(MouseUp); 50 } 51 52 /// <summary> 53 /// 繪制拖拉時的黑色邊框 54 /// </summary> 55 public static void DrawDragBound(Control ctrl) 56 { 57 ctrl.Refresh(); 58 Graphics g = ctrl.CreateGraphics(); 59 int width = ctrl.Width; 60 int height = ctrl.Height; 61 Point[] ps = new Point[5]{new Point(0,0),new Point(width -1,0), 62 new Point(width -1,height -1),new Point(0,height-1),new Point(0,0)}; 63 g.DrawLines(new Pen(Color.Black), ps); 64 } 65 66 #endregion 67 68 #region Events 69 /// <summary> 70 /// 鼠標單擊事件:用來顯示邊框 71 /// </summary> 72 /// <param name="sender"></param> 73 /// <param name="e"></param> 74 protected void MouseClick(object sender, MouseEventArgs e) 75 { 76 this.currentControl.Parent.Refresh();//刷新父容器,清除掉其他控件的邊框 77 this.currentControl.BringToFront(); 78 fc = new FrameControl(this.currentControl); 79 this.currentControl.Parent.Controls.Add(fc); 80 fc.Visible = true; 81 fc.Draw(); 82 } 83 84 /// <summary> 85 /// 鼠標按下事件:記錄當前鼠標相對窗體的坐標 86 /// </summary> 87 void MouseDown(object sender, MouseEventArgs e) 88 { 89 pPoint = Cursor.Position; 90 } 91 92 /// <summary> 93 /// 鼠標移動事件:讓控件跟着鼠標移動 94 /// </summary> 95 void MouseMove(object sender, MouseEventArgs e) 96 { 97 Cursor.Current = Cursors.SizeAll; //當鼠標處於控件內部時,顯示光標樣式為SizeAll 98 //當鼠標左鍵按下時才觸發 99 if (e.Button == MouseButtons.Left) 100 { 101 MoveControl.DrawDragBound(this.currentControl); 102 if(fc != null ) fc.Visible = false; //先隱藏 103 cPoint = Cursor.Position;//獲得當前鼠標位置 104 int x = cPoint.X - pPoint.X; 105 int y = cPoint.Y - pPoint.Y; 106 currentControl.Location = new Point(currentControl.Location.X + x, currentControl.Location.Y + y); 107 pPoint = cPoint; 108 } 109 } 110 111 /// <summary> 112 /// 鼠標彈起事件:讓自定義的邊框出現 113 /// </summary> 114 void MouseUp(object sender, MouseEventArgs e) 115 { 116 this.currentControl.Refresh(); 117 if (fc != null) 118 { 119 fc.Visible = true; 120 fc.Draw(); 121 } 122 } 123 #endregion 124 } 125 }

1 /****************************************************************** 2 * 創 建 人: SamWang 3 * 創建時間: 2012-5-10 17:00 4 * 描 述: 5 * 在控件外部加上邊框,用於拖拉,以改變內部控件的大小 6 * 原 理: 7 * 版 本: V1.0 8 * 環 境: VS2010 9 ******************************************************************/ 10 using System; 11 using System.Collections.Generic; 12 using System.Text; 13 using System.Windows.Forms; 14 using System.Drawing; 15 using System.Drawing.Drawing2D; 16 17 namespace DragControl 18 { 19 public class FrameControl : UserControl 20 { 21 #region Constructors 22 /// <summary> 23 /// 構造函數 24 /// </summary> 25 public FrameControl(Control ctrl) 26 { 27 baseControl = ctrl; 28 AddEvents(); 29 CreateBounds(); 30 } 31 #endregion 32 33 #region Fields 34 const int Band = 6; //調整大小的響應邊框 35 private int MinWidth = 20; //最小寬度 36 private int MinHeight = 20;//最小高度 37 Size square = new Size(Band, Band);//小矩形大小 38 Control baseControl; //基礎控件,即被包圍的控件 39 Rectangle[] smallRects = new Rectangle[8];//邊框中的八個小圓圈 40 Rectangle[] sideRects = new Rectangle[4];//四條邊框,用來做響應區域 41 Point[] linePoints = new Point[5];//四條邊,用於畫虛線 42 Graphics g; //畫圖板 43 Rectangle ControlRect; //控件包含邊框的區域 44 private Point pPoint; //上個鼠標坐標 45 private Point cPoint; //當前鼠標坐標 46 private MousePosOnCtrl mpoc; 47 #endregion 48 49 #region Properties 50 /// <summary> 51 /// 鼠標在控件中位置 52 /// </summary> 53 enum MousePosOnCtrl 54 { 55 NONE = 0, 56 TOP = 1, 57 RIGHT = 2, 58 BOTTOM = 3, 59 LEFT = 4, 60 TOPLEFT = 5, 61 TOPRIGHT = 6, 62 BOTTOMLEFT = 7, 63 BOTTOMRIGHT = 8, 64 } 65 #endregion 66 67 #region Methods 68 /// <summary> 69 /// 加載事件 70 /// </summary> 71 private void AddEvents() 72 { 73 this.Name = "FrameControl" + baseControl.Name; 74 this.MouseDown += new MouseEventHandler(FrameControl_MouseDown); 75 this.MouseMove += new MouseEventHandler(FrameControl_MouseMove); 76 this.MouseUp += new MouseEventHandler(FrameControl_MouseUp); 77 } 78 79 #region 創建邊框 80 /// <summary> 81 /// 建立控件可視區域 82 /// </summary> 83 private void CreateBounds() 84 { 85 //創建邊界 86 int X = baseControl.Bounds.X - square.Width - 1; 87 int Y = baseControl.Bounds.Y - square.Height - 1; 88 int Height = baseControl.Bounds.Height + (square.Height * 2) + 2; 89 int Width = baseControl.Bounds.Width + (square.Width * 2) + 2; 90 this.Bounds = new Rectangle(X, Y, Width, Height); 91 this.BringToFront(); 92 SetRectangles(); 93 //設置可視區域 94 this.Region = new Region(BuildFrame()); 95 g = this.CreateGraphics(); 96 } 97 98 /// <summary> 99 /// 設置定義8個小矩形的范圍 100 /// </summary> 101 void SetRectangles() 102 { 103 //左上 104 smallRects[0] = new Rectangle(new Point(0, 0), square); 105 //右上 106 smallRects[1] = new Rectangle(new Point(this.Width - square.Width - 1, 0), square); 107 //左下 108 smallRects[2] = new Rectangle(new Point(0, this.Height - square.Height - 1), square); 109 //右下 110 smallRects[3] = new Rectangle(new Point(this.Width - square.Width - 1, this.Height - square.Height - 1), square); 111 //上中 112 smallRects[4] = new Rectangle(new Point(this.Width / 2 - 1, 0), square); 113 //下中 114 smallRects[5] = new Rectangle(new Point(this.Width / 2 - 1, this.Height - square.Height - 1), square); 115 //左中 116 smallRects[6] = new Rectangle(new Point(0, this.Height / 2 - 1), square); 117 //右中 118 smallRects[7] = new Rectangle(new Point(square.Width + baseControl.Width + 1, this.Height / 2 - 1), square); 119 120 //四條邊線 121 //左上 122 linePoints[0] = new Point(square.Width / 2, square.Height / 2); 123 //右上 124 linePoints[1] = new Point(this.Width - square.Width / 2 - 1, square.Height / 2); 125 //右下 126 linePoints[2] = new Point(this.Width - square.Width / 2 - 1, this.Height - square.Height / 2); 127 //左下 128 linePoints[3] = new Point(square.Width / 2, this.Height - square.Height / 2 - 1); 129 //左上 130 linePoints[4] = new Point(square.Width / 2, square.Height / 2); 131 132 //整個包括周圍邊框的范圍 133 ControlRect = new Rectangle(new Point(0, 0), this.Bounds.Size); 134 } 135 136 /// <summary> 137 /// 設置邊框控件可視區域 138 /// </summary> 139 /// <returns></returns> 140 private GraphicsPath BuildFrame() 141 { 142 GraphicsPath path = new GraphicsPath(); 143 //上邊框 144 sideRects[0] = new Rectangle(0, 0, this.Width - square.Width - 1, square.Height + 1); 145 //左邊框 146 sideRects[1] = new Rectangle(0, square.Height + 1, square.Width + 1, this.Height - square.Height - 1); 147 //下邊框 148 sideRects[2] = new Rectangle(square.Width + 1, this.Height - square.Height - 1, this.Width - square.Width - 1, square.Height + 1); 149 //右邊框 150 sideRects[3] = new Rectangle(this.Width - square.Width - 1, 0, square.Width + 1, this.Height - square.Height - 1); 151 152 path.AddRectangle(sideRects[0]); 153 path.AddRectangle(sideRects[1]); 154 path.AddRectangle(sideRects[2]); 155 path.AddRectangle(sideRects[3]); 156 return path; 157 } 158 #endregion 159 160 /// <summary> 161 /// 繪圖 162 /// </summary> 163 public void Draw() 164 { 165 this.BringToFront(); 166 //g.FillRectangles(Brushes.LightGray, sideRects); //填充四條邊框的內部 167 Pen pen = new Pen(Color.Black); 168 pen.DashStyle = DashStyle.Dot;//設置為虛線,用虛線畫四邊,模擬微軟效果 169 g.DrawLines(pen, linePoints);//繪制四條邊線 170 g.FillRectangles(Brushes.White, smallRects); //填充8個小矩形的內部 171 foreach (Rectangle smallRect in smallRects) 172 { 173 g.DrawEllipse(Pens.Black, smallRect); //繪制8個小橢圓 174 } 175 //g.DrawRectangles(Pens.Black, smallRects); //繪制8個小矩形的黑色邊線 176 } 177 178 /// <summary> 179 /// 設置光標狀態 180 /// </summary> 181 public bool SetCursorShape(int x, int y) 182 { 183 Point point = new Point(x, y); 184 if (!ControlRect.Contains(point)) 185 { 186 Cursor.Current = Cursors.Arrow; 187 return false; 188 } 189 else if (smallRects[0].Contains(point)) 190 { 191 Cursor.Current = Cursors.SizeNWSE; 192 mpoc = MousePosOnCtrl.TOPLEFT; 193 } 194 else if (smallRects[1].Contains(point)) 195 { 196 Cursor.Current = Cursors.SizeNESW; 197 mpoc = MousePosOnCtrl.TOPRIGHT; 198 } 199 else if (smallRects[2].Contains(point)) 200 { 201 Cursor.Current = Cursors.SizeNESW; 202 mpoc = MousePosOnCtrl.BOTTOMLEFT; 203 } 204 else if (smallRects[3].Contains(point)) 205 { 206 Cursor.Current = Cursors.SizeNWSE; 207 mpoc = MousePosOnCtrl.BOTTOMRIGHT; 208 } 209 else if (sideRects[0].Contains(point)) 210 { 211 Cursor.Current = Cursors.SizeNS; 212 mpoc = MousePosOnCtrl.TOP; 213 } 214 else if (sideRects[1].Contains(point)) 215 { 216 Cursor.Current = Cursors.SizeWE; 217 mpoc = MousePosOnCtrl.LEFT; 218 } 219 else if (sideRects[2].Contains(point)) 220 { 221 Cursor.Current = Cursors.SizeNS; 222 mpoc = MousePosOnCtrl.BOTTOM; 223 } 224 else if (sideRects[3].Contains(point)) 225 { 226 Cursor.Current = Cursors.SizeWE; 227 mpoc = MousePosOnCtrl.RIGHT; 228 } 229 else 230 { 231 Cursor.Current = Cursors.Arrow; 232 } 233 return true; 234 } 235 236 /// <summary> 237 /// 控件移動 238 /// </summary> 239 private void ControlMove() 240 { 241 cPoint = Cursor.Position; 242 int x = cPoint.X - pPoint.X; 243 int y = cPoint.Y - pPoint.Y; 244 switch (this.mpoc) 245 { 246 case MousePosOnCtrl.TOP: 247 if (baseControl.Height - y > MinHeight) 248 { 249 baseControl.Top += y; 250 baseControl.Height -= y; 251 } 252 else 253 { 254 baseControl.Top -= MinHeight - baseControl.Height; 255 baseControl.Height = MinHeight; 256 } 257 break; 258 case MousePosOnCtrl.BOTTOM: 259 if (baseControl.Height + y > MinHeight) 260 { 261 baseControl.Height += y; 262 } 263 else 264 { 265 baseControl.Height = MinHeight; 266 } 267 break; 268 case MousePosOnCtrl.LEFT: 269 if (baseControl.Width - x > MinWidth) 270 { 271 baseControl.Left += x; 272 baseControl.Width -= x; 273 } 274 else 275 { 276 baseControl.Left -= MinWidth - baseControl.Width; 277 baseControl.Width = MinWidth; 278 } 279 280 break; 281 case MousePosOnCtrl.RIGHT: 282 if (baseControl.Width + x > MinWidth) 283 { 284 baseControl.Width += x; 285 } 286 else 287 { 288 baseControl.Width = MinWidth; 289 } 290 break; 291 case MousePosOnCtrl.TOPLEFT: 292 if (baseControl.Height - y > MinHeight) 293 { 294 baseControl.Top += y; 295 baseControl.Height -= y; 296 } 297 else 298 { 299 baseControl.Top -= MinHeight - baseControl.Height; 300 baseControl.Height = MinHeight; 301 } 302 if (baseControl.Width - x > MinWidth) 303 { 304 baseControl.Left += x; 305 baseControl.Width -= x; 306 } 307 else 308 { 309 baseControl.Left -= MinWidth - baseControl.Width; 310 baseControl.Width = MinWidth; 311 } 312 break; 313 case MousePosOnCtrl.TOPRIGHT: 314 if (baseControl.Height - y > MinHeight) 315 { 316 baseControl.Top += y; 317 baseControl.Height -= y; 318 } 319 else 320 { 321 baseControl.Top -= MinHeight - baseControl.Height; 322 baseControl.Height = MinHeight; 323 } 324 if (baseControl.Width + x > MinWidth) 325 { 326 baseControl.Width += x; 327 } 328 else 329 { 330 baseControl.Width = MinWidth; 331 } 332 break; 333 case MousePosOnCtrl.BOTTOMLEFT: 334 if (baseControl.Height + y > MinHeight) 335 { 336 baseControl.Height += y; 337 } 338 else 339 { 340 baseControl.Height = MinHeight; 341 } 342 if (baseControl.Width - x > MinWidth) 343 { 344 baseControl.Left += x; 345 baseControl.Width -= x; 346 } 347 else 348 { 349 baseControl.Left -= MinWidth - baseControl.Width; 350 baseControl.Width = MinWidth; 351 } 352 break; 353 case MousePosOnCtrl.BOTTOMRIGHT: 354 if (baseControl.Height + y > MinHeight) 355 { 356 baseControl.Height += y; 357 } 358 else 359 { 360 baseControl.Height = MinHeight; 361 } 362 if (baseControl.Width + x > MinWidth) 363 { 364 baseControl.Width += x; 365 } 366 else 367 { 368 baseControl.Width = MinWidth; 369 } 370 break; 371 372 } 373 pPoint = Cursor.Position; 374 } 375 376 #endregion 377 378 #region Events 379 /// <summary> 380 /// 鼠標按下事件:記錄當前鼠標相對窗體的坐標 381 /// </summary> 382 void FrameControl_MouseDown(object sender, MouseEventArgs e) 383 { 384 pPoint = Cursor.Position; 385 } 386 387 /// <summary> 388 /// 鼠標移動事件:讓控件跟着鼠標移動 389 /// </summary> 390 void FrameControl_MouseMove(object sender, MouseEventArgs e) 391 { 392 if (e.Button == MouseButtons.Left) 393 { 394 this.Visible = false; 395 MoveControl.DrawDragBound(baseControl); 396 ControlMove(); 397 } 398 else 399 { 400 this.Visible = true; 401 SetCursorShape(e.X, e.Y); //更新鼠標指針樣式 402 } 403 } 404 405 /// <summary> 406 /// 鼠標彈起事件:讓自定義的邊框出現 407 /// </summary> 408 void FrameControl_MouseUp(object sender, MouseEventArgs e) 409 { 410 this.baseControl.Refresh(); //刷掉黑色邊框 411 this.Visible = true; 412 CreateBounds(); 413 Draw(); 414 } 415 #endregion 416 } 417 }
四、遺留問題
1.ListBox存在拖拉高度時,存在莫名奇妙的BUG。
2.目前該版本只支持單控件的拖拉,多控件同時拖拉等下次有空再弄。
五、附源代碼下載
http://files.cnblogs.com/wangshenhe/DragControl.zip
SamWang
2012-05-14
作者:SamWang
出處:http://wangshenhe.cnblogs.com/
本文版權歸作者和博客園共有,歡迎圍觀轉載。轉載時請您務必在文章明顯位置給出原文鏈接,謝謝您的合作。