通过


什么是自定义控件?

本文介绍了自定义控件,并介绍了它们与用户控件的区别。 自定义控件不提供视觉设计界面,依靠用户提供的代码进行绘制。 此设计不同于用户控件,这些控件提供可视化设计图面,用于将多个控件分组到单个可重用单元中。

当现有控件或用户控件不接近提供所需的 UI 或交互性时,请使用自定义控件。 你需要付出更多努力才能完全实现。 Windows 窗体仍然提供键盘和鼠标处理,但您需要实现任何特定的处理行为。 自定义控件不包含设计界面,因为所有绘图都是通过 OnPaint 方法中的代码完成的。 你仍然可以通过非可视化设计界面添加组件,例如Timer

基类

创建自定义控件时,请从两个基类中进行选择:

除非需要滚动自定义控件的内容,否则请使用 Control 基类。

继承的功能

由于自定义控件的基类是 Control,因此会自动继承由所有控件共享的 Windows 窗体功能。 下面是使用自定义控件获取的一些功能:

  • 键盘和鼠标输入。
  • 布局行为,例如定位和停靠。
  • 支持标签导航。
  • 最小和最大大小限制。

绘制是指绘制控件的视觉外观。 可以通过重写 OnPaint 方法来完成此任务。 有关控件如何进行绘制的详细信息,请参阅 控件的绘制和绘图

使用 Visual Studio 模板创建自定义控件时,会自动重写 OnPaint 该方法。 模板执行此操作是因为需要编写用于绘制控件的代码。 下面是模板生成的示例:

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

前面的代码创建如下图所示的控件:

在 Visual Studio 中呈现的自定义控件。控件是一个空框,其边框颜色不同。每个颜色都由单个像素嵌入。

背景

请注意,控件的背景是用 SystemColors.Control 颜色绘制的,即使 OnPaint 代码未清除或用颜色填充控件。 该方法 OnPaintBackground(PaintEventArgs) 在调用 OnPaint之前绘制背景。 重写 OnPaintBackground 以负责绘制控件的背景区域。 此方法的默认实现分别绘制了由 BackColor 属性设置的颜色和由 BackgroundImage 属性设置的图像。