在图形化用户界面编程中,用户控件是一个很重要的概念。本质上我们的图形化用户界面是由各种控件构成,这些控件有些是IDE开发商提供的,有些是第三方提供的,若这些控件都不能完成功能则需要自己编写控件了。在C#中编写一个控件很简单,以下代码就能实现一个用户控件。
public class UserControl1: System.Windows.Forms.UserControl { protected override void OnMouseMove(MouseEventArgs e) { // 处理鼠标移动代码 } protected override void OnPaint(PaintEventArgs e) { // 绘制用户界面的代码 } // 用户控件的其他代码 }
在此小弟提出“虚控件”的概念,所谓虚控件就是在控件和操作控件的代码之间放置一个代理层,所有的代码通过这个代理来操作控件,而控件的事件也通过这个代理层来调用相关的控制代码,控件和代码不直接发生关系。以下代码实现了一个简单的“虚控件”中的代理层
public class VirtualControlBase
{ protected System.Windows.Forms.Control myControl = null; public System.Windows.Forms.PaintEventHandler _Paint = null; public System.Windows.Forms.MouseEventHandler _MouseMove = null; public VirtualControlBase() { _Paint = new System.Windows.Forms.PaintEventHandler(myControl_Paint); _MouseMove = new System.Windows.Forms.MouseEventHandler(myControl_MouseMove); } // 绑定的控件 public System.Windows.Forms.Control BindControl
{ get
{ return myControl; } set
{ if (value != myControl) { if (myControl != null) { myControl.Paint -= _Paint; myControl.MouseMove -= _MouseMove; } myControl = value; if (myControl != null) { myControl.Paint += _Paint; myControl.MouseMove += _MouseMove; } } } } //public System.Windows.Forms.Control BindControl private void myControl_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { HandlePaint(e.Graphics, e.ClipRectangle); } private void myControl_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) { HandleMouseMove(e.X, e.Y, e.Button); } protected virtual void HandlePaint(System.Drawing.Graphics Graphics, System.Drawing.Rectangle ClipRectangle){} protected virtual void HandleMouseMove(int x, int y, System.Windows.Forms.MouseButtons Button){} public System.Drawing.Size ClientSize
{ get
{ return System.Drawing.Size.Empty; } } public System.Drawing.Rectangle Bounds
{ get
{ return myControl.Bounds; } } public System.Drawing.Graphics CreateGraphics() { return myControl.CreateGraphics(); } public System.Windows.Forms.Cursor Cursor
{ get
{ return myControl.Cursor; } set
{ myControl.Cursor = value; } } public System.Drawing.Font Font
{ get
{ return myControl.Font; } set
{ myControl.Font = value; } } public void Refresh() { myControl.Refresh(); } public void Invalidate(System.Drawing.Rectangle Rect) { myControl.Invalidate(Rect, true); } public void Update() { myControl.Update(); } } //public class VirtualControlBase
public class UserControl2: VirtualControlBase { protected override void HandleMouseMove(int x, int y, MouseButtons Button) { // 处理鼠标移动的代码 } protected override void HandlePaint(Graphics Graphics, Rectangle ClipRectangle) { // 绘制用户界面的代码 } // 用户控件的其他代码 }
这种模式我称为“虚控件”模式,而传统的控件称为“实控件”模式。
设计良好的虚控件的代理层能使得代码的编写和实控件的代码的编写没有多大的区别。
虚控件是不能直接使用的,它得依附在其他控件使用,首先在窗体中放置一个标准控件,比如Panel等等。然后实例化一个虚控件,调用VirtualControlBase.BindControl 属性来进行控件绑定,如此才可使用。
为何开发一个用户控件需要如此多此一举。其实这样做有不少好处,可列举的有
其实虚控件的概念还能用VB来实现,以下代码就是一个简单的例子
' 类 myControl.cls 的内容 Private WithEvents myControl As VB.PictureBox Public Sub SetBindControl(ByVal p As VB.PictureBox) Set myControl = p End Sub Private Sub myControl_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single) ' 处理鼠标移动事件 End Sub Private Sub myControl_Paint() ' 绘图图形的操作 End Sub
以下是C#编写的一个虚控件代理层的完整代码。
/// <summary> /// 绑定控件的模块 /// </summary> public class VirtualControlBase { /// <summary> /// 对象绑定的控件 /// </summary> protected System.Windows.Forms.Control myControl = null; /// <summary> /// 处理控件重绘事件的委托对象 /// </summary> public System.Windows.Forms.PaintEventHandler _Paint = null; /// <summary> /// 处理鼠标按键按下事件的委托对象 /// </summary> public System.Windows.Forms.MouseEventHandler _MouseDown = null; /// <summary> /// 处理鼠标移动事件的委托对象 /// </summary> public System.Windows.Forms.MouseEventHandler _MouseMove = null; /// <summary> /// 处理鼠标按键松开事件的委托对象 /// </summary> public System.Windows.Forms.MouseEventHandler _MouseUp = null; /// <summary> /// 处理鼠标光标进入控件事件的委托对象 /// </summary> public System.EventHandler _MouseEnter = null; /// <summary> /// 处理鼠标光标离开控件事件的委托对象 /// </summary> public System.EventHandler _MouseLeave = null; /// <summary> /// 处理鼠标滚轮事件的委托对象 /// </summary> public System.Windows.Forms.MouseEventHandler _MouseWheel = null; /// <summary> /// 处理键盘按键按下事件的委托对象 /// </summary> public System.Windows.Forms.KeyEventHandler _KeyDown = null; /// <summary> /// 处理键盘输入字符事件的委托对象 /// </summary> public System.Windows.Forms.KeyPressEventHandler _KeyPress = null; /// <summary> /// 处理键盘按键松开事件的委托对象 /// </summary> public System.Windows.Forms.KeyEventHandler _KeyUp = null; /// <summary> /// 处理控件获得焦点事件的委托对象 /// </summary> public System.EventHandler _GotFocus = null; /// <summary> /// 处理控件失去焦点事件的委托对象 /// </summary> public System.EventHandler _LostFocus = null; /// <summary> /// 处理鼠标单击事件的委托对象 /// </summary> public System.EventHandler _Click = null; /// <summary> /// 处理鼠标双击事件的委托对象 /// </summary> public System.EventHandler _DoubleClick = null; /// <summary> /// 处理控件大小改变事件的委托对象 /// </summary> public System.EventHandler _Resize = null; /// <summary> /// 初始化对象 /// </summary> public VirtualControlBase() { _Paint = new System.Windows.Forms.PaintEventHandler(myControl_Paint); _MouseDown = new System.Windows.Forms.MouseEventHandler(myControl_MouseDown); _MouseMove = new System.Windows.Forms.MouseEventHandler(myControl_MouseMove); _MouseUp = new System.Windows.Forms.MouseEventHandler(myControl_MouseUp); _MouseEnter = new System.EventHandler(myControl_MouseEnter); _MouseLeave = new System.EventHandler(myControl_MouseLeave); _MouseWheel = new System.Windows.Forms.MouseEventHandler(myControl_MouseWheel); _KeyDown = new System.Windows.Forms.KeyEventHandler(myControl_KeyDown); _KeyPress = new System.Windows.Forms.KeyPressEventHandler(myControl_KeyPress); _KeyUp = new System.Windows.Forms.KeyEventHandler(myControl_KeyUp); _GotFocus = new System.EventHandler(myControl_GotFocus); _LostFocus = new System.EventHandler(myControl_LostFocus); _Click = new System.EventHandler(myControl_Click); _DoubleClick = new System.EventHandler(myControl_DoubleClick); _Resize = new System.EventHandler(myControl_Resize); } /// <summary> /// 重新绑定控件 /// </summary> public virtual void ReBind() { this.BindControl = this.myControl; } /// <summary> /// 绑定的控件 /// </summary> public virtual System.Windows.Forms.Control BindControl { get { return myControl; } set { if (myControl != null) { myControl.Paint -= _Paint; myControl.MouseDown -= _MouseDown; myControl.MouseMove -= _MouseMove; myControl.MouseUp -= _MouseUp; myControl.MouseEnter -= _MouseEnter; myControl.MouseLeave -= _MouseLeave; myControl.MouseWheel -= _MouseWheel; myControl.KeyDown -= _KeyDown; myControl.KeyPress -= _KeyPress; myControl.KeyUp -= _KeyUp; myControl.GotFocus -= _GotFocus; myControl.LostFocus -= _LostFocus; myControl.Click -= _Click; myControl.DoubleClick -= _DoubleClick; myControl.Resize -= _Resize; } myControl = value; if (myControl != null) { myControl.Paint += _Paint; myControl.MouseDown += _MouseDown; myControl.MouseMove += _MouseMove; myControl.MouseUp += _MouseUp; myControl.MouseEnter += _MouseEnter; myControl.MouseLeave += _MouseLeave; myControl.MouseWheel += _MouseWheel; myControl.KeyDown += _KeyDown; myControl.KeyPress += _KeyPress; myControl.KeyUp += _KeyUp; myControl.GotFocus += _GotFocus; myControl.LostFocus += _LostFocus; myControl.Click += _Click; myControl.DoubleClick += _DoubleClick; myControl.Resize += _Resize; } OnAfterBindControl(); } } //public System.Windows.Forms.Control BindControl /// <summary> /// 绑定控件后的处理 /// </summary> protected virtual void OnAfterBindControl(){} private void myControl_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) { HandleKeyDown(e.KeyCode, e.Alt, e.Shift, e.Control); } private void myControl_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) { HandleKeyPress(e.KeyChar); } private void myControl_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e) { HandleKeyUp(e.KeyCode, e.Alt, e.Shift, e.Control); } private void myControl_MouseLeave(object sender, System.EventArgs e) { HandleMouseLeave(); } private void myControl_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e) { HandleMouseWheel(e.X, e.Y, e.Button, e.Delta); } private void myControl_GotFocus(object sender, System.EventArgs e) { HandleGotFocus(); } private void myControl_LostFocus(object sender, System.EventArgs e) { HandleLostFocus(); } private void myControl_MouseEnter(object sender, System.EventArgs e) { HandleMouseEnter(); } private void myControl_Click(object sender, System.EventArgs e) { System.Drawing.Point p = System.Windows.Forms.Control.MousePosition; p = myControl.PointToClient(p); HandleClick(p.X, p.Y, System.Windows.Forms.Control.MouseButtons); } private void myControl_DoubleClick(object sender, System.EventArgs e) { System.Drawing.Point p = System.Windows.Forms.Control.MousePosition; p = myControl.PointToClient(p); HandleDoubleClick(p.X, p.Y, System.Windows.Forms.Control.MouseButtons); } private void myControl_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { HandlePaint(e.Graphics, e.ClipRectangle); } private void myControl_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) { HandleMouseDown(e.X, e.Y, e.Button); } private void myControl_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) { HandleMouseMove(e.X, e.Y, e.Button); } private void myControl_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) { HandleMouseUp(e.X, e.Y, e.Button); } private void myControl_Resize(object sender, System.EventArgs e) { HandleResize(); } #region 控件事件处理过程群 /// <summary> /// 处理键盘按键按下事件 /// </summary> /// <param name="KeyCode">按键编码</param> /// <param name="Alt">Alt键是否按下</param> /// <param name="Shift">Shift键是否按下</param> /// <param name="Control">Control键是否按下</param> protected virtual void HandleKeyDown(System.Windows.Forms.Keys KeyCode, bool Alt, bool Shift, bool Control){} /// <summary> /// 处理键盘字符事件 /// </summary> /// <param name="KeyChar">字符数据</param> protected virtual void HandleKeyPress(char KeyChar){} /// <summary> /// 处理键盘按键松开事件 /// </summary> /// <param name="KeyCode">按键编码</param> /// <param name="Alt">Alt键是否按下</param> /// <param name="Shift">Shift键是否按下</param> /// <param name="Control">Control键是否按下</param> protected virtual void HandleKeyUp(System.Windows.Forms.Keys KeyCode, bool Alt, bool Shift, bool Control){} /// <summary> /// 处理鼠标光标离开控件工作区事件 /// </summary> protected virtual void HandleMouseLeave(){} /// <summary> /// 处理鼠标滚轮事件 /// </summary> /// <param name="x">鼠标光标X坐标</param> /// <param name="y">鼠标光标Y坐标</param> /// <param name="Button">鼠标按键值</param> /// <param name="Delta">滚轮值</param> protected virtual void HandleMouseWheel(int x, int y, System.Windows.Forms.MouseButtons Button, int Delta){} /// <summary> /// 处理控件获得焦点事件 /// </summary> protected virtual void HandleGotFocus(){} /// <summary> /// 处理控件失去焦点事件 /// </summary> protected virtual void HandleLostFocus(){} /// <summary> /// 处理鼠标光标进入控件工作区事件 /// </summary> protected virtual void HandleMouseEnter(){} /// <summary> /// 处理鼠标单击事件 /// </summary> /// <param name="x">鼠标光标X坐标</param> /// <param name="y">鼠标光标Y坐标</param> /// <param name="Button">鼠标按键值</param> protected virtual void HandleClick(int x, int y, System.Windows.Forms.MouseButtons Button){} /// <summary> /// 处理鼠标双击事件 /// </summary> /// <param name="x">鼠标光标X坐标</param> /// <param name="y">鼠标光标Y坐标</param> /// <param name="Button">鼠标按键值</param> protected virtual void HandleDoubleClick(int x, int y, System.Windows.Forms.MouseButtons Button){} /// <summary> /// 处理鼠标按键按下事件 /// </summary> /// <param name="x">鼠标光标X坐标</param> /// <param name="y">鼠标光标Y坐标</param> /// <param name="Button">鼠标按键值</param> protected virtual void HandleMouseDown(int x, int y, System.Windows.Forms.MouseButtons Button){} /// <summary> /// 处理鼠标移动事件 /// </summary> /// <param name="x">鼠标光标X坐标</param> /// <param name="y">鼠标光标Y坐标</param> /// <param name="Button">鼠标按键值</param> protected virtual void HandleMouseMove(int x, int y, System.Windows.Forms.MouseButtons Button){} /// <summary> /// 处理鼠标按键松开事件 /// </summary> /// <param name="x">鼠标光标X坐标</param> /// <param name="y">鼠标光标Y坐标</param> /// <param name="Button">鼠标按键值</param> protected virtual void HandleMouseUp(int x, int y, System.Windows.Forms.MouseButtons Button){} /// <summary> /// 处理重绘用户界面事件 /// </summary> /// <param name="Graphics">图形绘制对象</param> /// <param name="ClipRectangle">剪切矩形区域</param> protected virtual void HandlePaint(System.Drawing.Graphics Graphics, System.Drawing.Rectangle ClipRectangle){} /// <summary> /// 处理控件改变大小事件 /// </summary> protected virtual void HandleResize(){} #endregion /// <summary> /// 创建显示内容的位图对象 /// </summary> /// <param name="bounds">要显示的区域</param> /// <returns>创建的BMP位图对象</returns> public System.Drawing.Bitmap CreateBitmap(System.Drawing.Rectangle bounds) { System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(bounds.Width, bounds.Height); using(System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp)) { g.TranslateTransform(bounds.Left, bounds.Top); this.HandlePaint(g, bounds); } return bmp; } /// <summary> /// 对象是否绑定了一个控件 /// </summary> public bool HasBindControl { get { return myControl != null; } } /// <summary> /// 创建绘图对象 /// </summary> /// <returns></returns> public System.Drawing.Graphics CreateGraphics() { if (myControl == null) return null; else return myControl.CreateGraphics(); } /// <summary> /// 设置输入焦点 /// </summary> public void Focus() { if (myControl != null) myControl.Focus(); } /// <summary> /// 鼠标光标 /// </summary> public System.Windows.Forms.Cursor Cursor { get { if (myControl == null) return System.Windows.Forms.Cursors.Default; else return myControl.Cursor; } set { if (myControl != null) myControl.Cursor = value; } } /// <summary> /// 获取一个值,该值指示控件是否有输入焦点。 /// </summary> public bool Focused { get { return myControl == null ? false : myControl.Focused; } } /// <summary> /// 强制控件使其工作区无效并立即重绘自己和任何子控件。 /// </summary> public virtual void Refresh() { if (myControl != null) myControl.Refresh(); } /// <summary> /// 获取包含在控件内的控件集合 /// </summary> public System.Windows.Forms.Control.ControlCollection Controls { get { return myControl == null ? null : myControl.Controls; } } /// <summary> /// 使控件内指定区域无效,并向控件发送绘制消息 /// </summary> /// <param name="Rect"></param> public virtual void Invalidate(System.Drawing.Rectangle Rect) { if (myControl != null) myControl.Invalidate(Rect, true); } /// <summary> /// 判断控件是否已捕获鼠标 /// </summary> public bool Capture { get { return myControl == null ? false : myControl.Capture; } } /// <summary> /// 使控件重绘工作区内无效区域 /// </summary> public void Update() { if (myControl != null) myControl.Update(); } } //public class VirtualControlBase