很多时候我们需要使用到自定义控件 而在C#中 我们主要以3中方式创建自定义控件,还有些需要注意的地方时常被忽略 比如Click事件,用户控件的Click并不像系统的Button单击
1.继承自.NET类库中已有的控件 如TextBox MenuStrip Pannel
2.继承自Control类
3.继承自UserControl类
下面是3个小示例
1.继承自类库中现有的控件
下面自定义一个ExtendTextBox 该控件扩展了一个属性,可以现在文本框只能输入数字,字母或者所有字符

2 {
3 private AllowType _allowType = AllowType.All;
4 public AllowType AllowType
5 {
6 get { return _allowType; }
7 set { _allowType = value; }
8 }
9
10 protected override void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)
11 {
12 // 设置此属性为true 基方法将不再处理此KeyPress事件
13 e.Handled = true ;
14
15 if (_allowType == A llowType.Number)
16 {
17 // 如果输入是0-9 交由基方法处理 允许输入
18 if (e.KeyChar >= ' 0 ' && e.KeyChar <= ' 9 ' )
19 e.Handled = false ;
20 }
21 else if (_allowType == A llowType.Letter)
22 {
23 // 如果输入是A-Z或a-z 交由基方法处理 允许输入
24 if (e.KeyChar >= ' A ' && e.KeyChar <= ' z ' )
25 e.Handled = false ;
26 }
27 else if (_allowType == A llowType.All)
28 {
29 e.Handled = false ;
30 }
31 base .OnKeyPress(e);
32 }
33 }
34 public enum AllowType
35 {
36 Number,
37 Letter,
38 All
39 }
2.继承自UserControl类 此方法主要用于编写组合控件 UserControl容器可以提供其组成控件的所有功能。可以编写代码指定新的用户控件可公开其子控件的哪些属性
UserControl支持直接将背景色设置为透明 而Control则不支持
{
}
3.继承自Control类 Control类提供基本控件功能,但不提供图形界面或任何特定功能 ,必须编写代码指定控件的属性 方法 事件,还必须重写OnPaint和OnPaintBackground方法以创建界面,通常需要使用到GDI+
Control 类实现向用户显示信息的类所需的最基本功能。它处理用户通过键盘和指针设备所进行的输入。它还处理消息路由和安全。虽然它并不实现绘制,但是它定义控件的边界(其位置和大小)。它提供窗口句柄 (hWnd)。
下面是一个椭圆按钮简单的例子 但是有几个地方是要引起注意的,关于自定义控件里由基类继承而来的Click事件,包括UserControl和Control Click事件是鼠标单击事件 鼠标左键单击和右键单击都将触发这个事件 如果没有定义双击事件 则双击控件将两次触发Click事件。这里的Click和.Net类库中的Button的Click事件是区别的 传统的Button按钮,鼠标左键单击才会响应 聚焦后按Enter键也会响应。而自定义控件里的Click事件不会响应键盘的Enter 并且鼠标左键或者右键的单击都会触发它 。所以要对其进行一些处理,例子中自定义了一个椭圆按钮 并且它不会对右键单击产生反应
字段和重写OnPaint和OnPaintBackground

2 protected override void OnPaint(PaintEventArgs e)
3 {
4 // 将文本绘制到正中央
5 SizeF stringSize = e.Graphics.MeasureString(Text, Font);
6 float startx = (Width - stringSize.Width) / 2 ;
7 float starty = (Height - stringSize.Height) / 2 ;
8 e.Graphics.DrawString(Text, Font, new SolidBrush(ForeColor), startx, starty);
9 base .OnPaint(e);
10 }
11 protected override void OnPaintBackground(PaintEventArgs pevent)
12 {
13 // 绘制过程为 控件整体背景色->控件有效区背景色->控件状态表示区域->控件外框
14
15 // **********
16 // 控件整体背景色
17 // **********
18 if ( this .Parent != null )
19 pevent.Graphics.FillRectangle( new SolidBrush(Parent.BackColor), 0 , 0 , this .Width, this .Height);
20 // 使用高质量平滑模式消除椭圆边缘锯齿
21 pevent.Graphics.SmoothingMode = SmoothingMode.HighQuality;
22
23 // ***********
24 // 控件有效区背景色
25 // ************** Control.MouseButtons静态成员
26 if (_mouseEntered && (MouseButtons & MouseButtons.Left) == MouseButtons.Left)
27 {
28 Color mouseDownColor = Color.FromArgb( 128 , BackColor);
29 pevent.Graphics.FillEllipse( new SolidBrush(mouseDownColor), 0 , 0 , Width - 1 , Height - 1 );
30 }
31 else
32 pevent.Graphics.FillEllipse( new SolidBrush(BackColor), 0 , 0 , Width - 1 , Height - 1 );
33
34 // ***********
35 // 控件状态表示区域
36 // ************
37 // 左键未按下时绘制状态表示区域
38 if ((MouseButtons & MouseButtons.Left) != MouseButtons.Left)
39 {
40 // 鼠标进入 绘制橙色边框
41 if (_mouseEntered)
42 {
43 Pen mouseEnterPen = new Pen(Color.Orange, 2 );
44 pevent.Graphics.DrawEllipse(mouseEnterPen, 1 , 1 , Width - 3 , Height - 3 );
45 mouseEnterPen.Dispose();
46 }
47 // 控件获得焦点 但鼠标未进入 绘制蓝色边框
48 else if (Focused)
49 {
50 Pen focusedPen = new Pen(Color.PowderBlue, 2 );
51 pevent.Graphics.DrawEllipse(focusedPen, 1 , 1 , Width - 3 , Height - 3 );
52 focusedPen.Dispose();
53 }
54 }
55 // 如果有焦点,绘制焦点框
56 if (Focused)
57 {
58 Pen focusedDotPen = new Pen(Color.Black);
59 focusedDotPen.DashStyle = DashStyle.Dot;
60 pevent.Graphics.DrawEllipse(focusedDotPen, 3 , 3 , Width - 7 , Height - 7 );
61 focusedDotPen.Dispose();
62 }
63
64 // *********
65 // 控件外框
66 // **********
67 pevent.Graphics.DrawEllipse(Pens.Black, 0 , 0 , Width - 1 , Height - 1 );
68
69 // base.OnPaintBackground(pevent);
70 }
非关键代码

2 {
3 _mouseEntered = true ;
4 this .Refresh();
5 base .OnMouseEnter(e);
6 }
7 protected override void OnMouseLeave(EventArgs e)
8 {
9 _mouseEntered = false ;
10 this .Refresh();
11 base .OnMouseLeave(e);
12 }
13 protected override void OnGotFocus(EventArgs e)
14 {
15 this .Refresh();
16 base .OnGotFocus(e);
17 }
18 protected override void OnLostFocus(EventArgs e)
19 {
20 this .Refresh();
21 base .OnLostFocus(e);
22 }
需要注意的地方

2 protected override void OnMouseDown(MouseEventArgs e)
3 {
4 if (e.Button == MouseButtons.Left)
5 {
6 this .Focus();
7 this .Refresh();
8 }
9 base .OnMouseDown(e);
10 }
11 protected override void OnMouseUp(MouseEventArgs e)
12 {
13 if (e.Button == MouseButtons.Left)
14 this .Refresh();
15 base .OnMouseUp(e);
16 }
17 // 这里将消息对象强制转换为鼠标消息 判断是哪个键单击 只有当左键单击的时候才
18 // 执行,Click事件的委托是由OnClick来调用的 所以通过判断消息决定是否触发Click
19 protected override void OnClick(EventArgs e)
20 {
21 MouseEventArgs m = (MouseEventArgs)e;
22 if (m.Button == MouseButtons.Left)
23 base .OnClick(e);
24 }