本文介绍了自定义控件,并介绍了它们与用户控件的区别。 自定义控件不提供视觉设计界面,依靠用户提供的代码进行绘制。 这不同于提供视觉设计图面的用户控件,用于将多个控件分组到单个可重用单元中。
当现有控件或用户控件不接近提供所需的 UI 或交互性时,将使用自定义控件。 你需要付出更多努力才能完全实现。 键盘和鼠标的处理仍然由 Windows 窗体提供,但任何需要实现的行为均留给你去完成。 自定义控件不提供设计界面,因为所有绘图都通过 OnPaint 方法中的代码完成。 仍可通过非可视化设计界面添加组件(例如 Timer)。
创建自定义控件时,有两个基类可供选择:
-
这是其他 Windows 窗体控件使用的同一基类。 直接控制控件的输入和输出。
System.Windows.Forms.ScrollableControl
某些 Windows 窗体控件使用此基类。 通过增加滚动内容的功能,此类扩展了
Control
。
除非需要滚动自定义控件的内容,否则请使用 Control
基类。
由于自定义控件的基类是 Control,因此会自动继承由所有控件共享的 Windows 窗体功能。 下面是使用自定义控件获取的一些功能:
- 键盘和鼠标输入。
- 布局行为,例如定位和停靠。
- 支持标签导航。
- 最小和最大大小限制。
绘制,这意味着绘制控件的视觉对象,是通过重写 OnPaint 方法来实现的。 有关控件如何进行绘制的详细信息,请参阅 控件的绘制和绘图。
使用 Visual Studio 模板创建自定义控件时,系统会自动重写此方法。 模板这样做,是因为需要你编写代码来渲染控件。 下面是模板生成的示例:
public partial class CustomControl1 : Control
{
public CustomControl1()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
}
Public Class CustomControl1
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
'Add your custom paint code here
End Sub
End Class
自定义控件是用OnPaint 方法绘制的。 此方法的单个参数是一个 PaintEventArgs 对象,它提供呈现控件所需的所有信息和功能。
PaintEventArgs
提供用于呈现控件的两个属性:
PaintEventArgs.ClipRectangle— 表示需要重新绘制的控件的一部分。 这可以是整个控件或控件的一部分。
Graphics— 表示控件的图形图面。 它提供多个面向图形的对象和方法,这些对象提供绘制控件所需的功能。
OnPaint
方法会在控件被绘制或刷新到屏幕上时调用,而PaintEventArgs.ClipRectangle
对象代表进行绘制的矩形区域。 如果需要刷新整个控件, PaintEventArgs.ClipRectangle
则表示整个控件的大小。 如果只需要刷新控件的一部分,则它仅表示需要重绘的区域。 例如,当控件被用户界面中的另一个控件部分遮盖,并且其他控件被移开时,必须重新绘制控件下方新公开的部分。
控件方法中的 OnPaint 代码在首次绘制控件时以及每当控件失效时运行。 若要确保控件在大小调整时始终重新绘制,请将以下代码行添加到控件的构造函数中:
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.ResizeRedraw, True)
以下代码片段是一个自定义控件,该控件在控件边缘周围呈现多个彩色矩形。
protected override void OnPaint(PaintEventArgs pe)
{
Rectangle rect = this.ClientRectangle;
// Bring the width/height in by 1 pixel so the rectangle is drawn inside the control.
// Otherwise, it kind of overlaps the outside edge.
rect.Width -= 1;
rect.Height -= 1;
Pen[] colorPens = new Pen[] { Pens.Blue, Pens.BlueViolet,
Pens.AliceBlue, Pens.CornflowerBlue,
Pens.Cyan, Pens.DarkCyan };
foreach (Pen pen in colorPens)
{
pe.Graphics.DrawRectangle(pen, rect);
rect.Inflate(-1, -1);
}
// Raise the Paint event so users can custom paint if they want.
base.OnPaint(pe);
}
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
Dim rect As Rectangle = Me.ClientRectangle
'Bring the width/height in by 1 pixel so the rectangle is drawn inside the control.
'Otherwise, it kind of overlaps the outside edge.
rect.Width -= 1
rect.Height -= 1
Dim colorPens As Pen() = {Pens.Blue, Pens.BlueViolet,
Pens.AliceBlue, Pens.CornflowerBlue,
Pens.Cyan, Pens.DarkCyan}
For Each curPen As Pen In colorPens
e.Graphics.DrawRectangle(curPen, rect)
rect.Inflate(-1, -1)
Next
'Raise the Paint event so users can custom paint if they want.
MyBase.OnPaint(e)
End Sub
前面的代码创建如下图所示的控件:
请注意,控件的背景是用 SystemColors.Control 颜色绘制的,即使 OnPaint
代码未清除或用颜色填充控件。
OnPaint
被调用之前,背景实际上是通过 OnPaintBackground(PaintEventArgs) 方法绘制的。 重写 OnPaintBackground
以负责绘制控件的背景区域。 此方法的默认实现是分别绘制由 BackColor 属性设置的颜色和 BackgroundImage 属性设置的图像。