【原创】C# 实现拖拉控件改变位置与大小(SamWang)(附源代码下载)

 

 前言:

  很多时候我们需要在运行时,动态地改变控件的位置以及大小,以获得更好的布局。比如说实际项目中的可自定义的报表、可自定义的单据等诸如此类。它们有个特点就是允许客户或者二次开发人员设计它们需要的界面设置功能。

  本人以前也做过可自定义系统,包括界面和功能,主要为了减少开发人员的工作量以及程序的灵活性和健壮性。

  本篇主要讨论下,在运行时如何实现拖拉控件,达到改变控件位置与大小。功能将模拟VS设计界面时的拖拉功能。

  (本篇暂不涉及多控件同时操作)

 

 

一、技术概述

  其实实现运行时控件的拖拉并不难,主要是改变控件的Location与Size即可。动态调整时再捕获MouseDown、MouseMove及MouseUp事件来实时修改上述两个属性就可以实现。

 

二、功能规划

  在此之前,我们先来看下.net设计界面,一旦选中某个控件时,将会出现如下图的边框:

  

  之后就可以通过拖拉出现的边框改变其大小。而改变控件的位置,实际上是当鼠标点击在控件内部拖动时实现的。

  所有本例也将功能分为两个部分实现,分别为控件内部拖动改变位置与控件边框拖拉改变大小。

 

三、具体实现

1.拖动控件改变位置

  首先,新建一个项目,然后添加一个类,取名叫MoveControl,该类用来给控件挂载事件实现拖动。

  接着在该类中添加字段currentControl,用来保存需要操作的控件,即通过构造函数传递的控件。

  接着创建一方法--AddEvents,用来给当前的控件挂载事件。

  代码如下:   

DragControl
 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的完整代码如下:  

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。

FrameControl
 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的时候再显示。

 

  此时的完整代码如下:

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         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 }
FrameControl
  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         }        

  到此为止,功能已经基本上实现。

  完成代码如下:

MoveControl
  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 }
FrameControl
  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.目前该版本只支持单控件的拖拉,多控件同时拖拉等下次有空再弄。

 

五、附源代码下载

https://files.cnblogs.com/wangshenhe/DragControl.zip

 

                                    SamWang  

                                            2012-05-14 

 


作者:SamWang
出处:http://wangshenhe.cnblogs.com/
本文版权归作者和博客园共有,欢迎围观转载。转载时请您务必在文章明显位置给出原文链接,谢谢您的合作。

 

 

                                            
posted on 2012-05-14 14:54  SamWang  阅读(8584)  评论(24编辑  收藏  举报