在图形化用户界面编程中,用户控件是一个很重要的概念。本质上我们的图形化用户界面是由各种控件构成,这些控件有些是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 属性来进行控件绑定,如此才可使用。
为何开发一个用户控件需要如此多此一举。其实这样做有不少好处,可列举的有
- 有利于代码的分离和模块化
- 实控件只能使用于图形化用户界面程序,而虚控件除了应用于图形化用户界面程序外还可使用于其他任何类型的程序,包括命令行程序,ASP.NET,WebService,Windows服务。这个特性可以适用于某些程序的移植。例如将GUI程序移植到ASP.NET中,GUI程序中编制了虚控件绘制的复杂图形,而后在ASP.NET程序中,它创建一个BMP图片,然后使用库函数System.Drawing.Graphics.FromImage创建一个Graphics对象,然后调用虚控件的HandlePaint来绘制这个复杂图形,然后就可以发布出去了。这样虚控件既可用于GUI程序又可用于ASP.NET程序,实现了代码的重用。利用这个特性还能比较好的修改旧的GUI代码,保持原有功能并向ASP.NET等非GUI程序提供图形支持。
- 虚控件可以减少控件的个数,在某些GUI应用中,窗体中可能堆积很多一样的控件,例如窗体有一个TabControl,有很多页,每页中放一个相同类型的用户控件,用户需要在这些控件来回切换。大家知道.NET的控件是基于Win32的窗体的,创建一个控件比较费力,消耗资源。而虚控件本质上只是一个类,在.NET中创建一个类是很简单的。这样在窗体中只要放置一个控件,然后生成很多虚控件,在各个控件来回切换就转换为各个虚控件绑定和取消绑定实控件的操作。而且在窗体中放置大量的控件不利于窗体设计器的工作。若某个控件在设计状态下发生错误则会影响窗体设计器的正常工作。(在VB中若用户控件加载错误会自动转换为一个PictureBox控件,所有的设计属性都会丢失)
- 使用某个控件前需要在VS.NET的工具箱中加入这个控件的图标,这个操作比较麻烦,而且打开其他不需要该控件的工程中,工具箱还会显示该控件的图标。而使用虚控件则不会出现这种情况
其实虚控件的概念还能用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