呈现 Windows 窗体控件Rendering a Windows Forms Control

呈现是指在用户屏幕上创建视觉对象表示形式的过程。Rendering refers to the process of creating a visual representation on a user's screen. Windows 窗体使用 GDI (新的 Windows 图形库) 来呈现。Windows Forms uses GDI (the new Windows graphics library) for rendering. 提供对 GDI 的访问的托管类位于 System.Drawing 命名空间及其子命名空间中。The managed classes that provide access to GDI are in the System.Drawing namespace and its subnamespaces.

控件呈现涉及以下元素:The following elements are involved in control rendering:

  • 基类提供的绘制功能 System.Windows.Forms.ControlThe drawing functionality provided by the base class System.Windows.Forms.Control.

  • GDI 图形库的重要元素。The essential elements of the GDI graphics library.

  • 绘图区域的几何。The geometry of the drawing region.

  • 用于释放图形资源的过程。The procedure for freeing graphics resources.

控件提供的绘制功能Drawing Functionality Provided by Control

基类 Control 通过其事件提供绘制功能 PaintThe base class Control provides drawing functionality through its Paint event. Paint每当控件需要更新其显示时,都会引发事件。A control raises the Paint event whenever it needs to update its display. 有关 .NET Framework 中事件的详细信息,请参阅 处理和引发事件For more information about events in the .NET Framework, see Handling and Raising Events.

事件的事件数据类 Paint PaintEventArgs 包含绘制控件所需的数据-图形对象的句柄和表示要在其中绘制的区域的矩形对象。The event data class for the Paint event, PaintEventArgs, holds the data needed for drawing a control — a handle to a graphics object and a rectangle object that represents the region to draw in. 这些对象在以下代码片段中显示为粗体。These objects are shown in bold in the following code fragment.

Public Class PaintEventArgs  
   Inherits EventArgs  
   Implements IDisposable  
   Public ReadOnly Property ClipRectangle() As System.Drawing.Rectangle  
   End Property  
   Public ReadOnly Property Graphics() As System.Drawing.Graphics  
   End Property  
   ' Other properties and methods.  
End Class  
public class PaintEventArgs : EventArgs, IDisposable {  
public System.Drawing.Rectangle ClipRectangle {get;}  
public System.Drawing.Graphics Graphics {get;}  
// Other properties and methods.  

Graphics 是一个封装了绘制功能的托管类,如本主题后面的 GDI 讨论中所述。Graphics is a managed class that encapsulates drawing functionality, as described in the discussion of GDI later in this topic. ClipRectangle是结构的实例 Rectangle ,用于定义可在其中绘制控件的可用区域。The ClipRectangle is an instance of the Rectangle structure and defines the available area in which a control can draw. 控件开发人员可以 ClipRectangle 使用 ClipRectangle 控件的属性计算,如本主题后面的几何讨论中所述。A control developer can compute the ClipRectangle using the ClipRectangle property of a control, as described in the discussion of geometry later in this topic.

控件必须通过重写继承自的方法来提供呈现逻辑 OnPaint ControlA control must provide rendering logic by overriding the OnPaint method that it inherits from Control. OnPaint 获取对图形对象的访问,以及通过 Graphics ClipRectangle 传递给它的实例的属性在中绘制的矩形 PaintEventArgsOnPaint gets access to a graphics object and a rectangle to draw in through the Graphics and the ClipRectangle properties of the PaintEventArgs instance passed to it.

Protected Overridable Sub OnPaint(pe As PaintEventArgs)  
protected virtual void OnPaint(PaintEventArgs pe);  

OnPaint基类的方法 Control 不会实现任何绘制功能,而只会调用向事件注册的事件委托 PaintThe OnPaint method of the base Control class does not implement any drawing functionality but merely invokes the event delegates that are registered with the Paint event. 重写时 OnPaint ,通常应调用基类的 OnPaint 方法,以便注册的委托接收 Paint 事件。When you override OnPaint, you should typically invoke the OnPaint method of the base class so that registered delegates receive the Paint event. 但是,绘制整个图面的控件不应调用基类的 OnPaint ,因为这会引入闪烁。However, controls that paint their entire surface should not invoke the base class's OnPaint, as this introduces flicker. 有关替代事件的示例 OnPaint ,请参阅 如何:创建显示进度的 Windows 窗体控件For an example of overriding the OnPaint event, see the How to: Create a Windows Forms Control That Shows Progress.


不要 OnPaint 直接从控件调用; 而是调用 Invalidate (继承自) 的方法 Control 或调用的其他方法 InvalidateDo not invoke OnPaint directly from your control; instead, invoke the Invalidate method (inherited from Control) or some other method that invokes Invalidate. Invalidate方法又会调用 OnPaintThe Invalidate method in turn invokes OnPaint. Invalidate重载方法时,控件会重 Invalidate e 绘其部分或全部屏幕区域,具体取决于提供给的参数。The Invalidate method is overloaded, and, depending on the arguments supplied to Invalidate e, a control redraws either some or all of its screen area.

基类 Control 定义可用于绘制的另一种方法,即 OnPaintBackground 方法。The base Control class defines another method that is useful for drawing — the OnPaintBackground method.

Protected Overridable Sub OnPaintBackground(pevent As PaintEventArgs)  
protected virtual void OnPaintBackground(PaintEventArgs pevent);  

OnPaintBackground 绘制背景 (,从而使窗口) 的形状,并保证其速度非常快,同时 OnPaint 绘制详细信息并可能比较慢,因为单个绘制请求合并为一个 Paint 事件,该事件涵盖了所有需要重新绘制的区域。OnPaintBackground paints the background (and thereby the shape) of the window and is guaranteed to be fast, while OnPaint paints the details and might be slower because individual paint requests are combined into one Paint event that covers all areas that have to be redrawn. 例如, OnPaintBackground 如果想要绘制控件的渐变颜色背景,则可能需要调用。You might want to invoke the OnPaintBackground if, for instance, you want to draw a gradient-colored background for your control.

虽然 OnPaintBackground 具有类似事件的命名法并采用与方法相同的参数 OnPaint ,但并 OnPaintBackground 不是真正的事件方法。While OnPaintBackground has an event-like nomenclature and takes the same argument as the OnPaint method, OnPaintBackground is not a true event method. 没有 PaintBackground 事件,并且不 OnPaintBackground 调用事件委托。There is no PaintBackground event and OnPaintBackground does not invoke event delegates. 重写 OnPaintBackground 方法时,派生类不需要调用 OnPaintBackground 其基类的方法。When overriding the OnPaintBackground method, a derived class is not required to invoke the OnPaintBackground method of its base class.

GDI + 基础知识GDI+ Basics

Graphics类提供用于绘制各种形状(如圆、三角形、弧形和椭圆)的方法,以及用于显示文本的方法。The Graphics class provides methods for drawing various shapes such as circles, triangles, arcs, and ellipses, as well as methods for displaying text. System.Drawing命名空间及其子命名空间包含类,这些类封装图形元素,如形状 (圆形、矩形、弧形以及其他) 、颜色、字体、画笔等。The System.Drawing namespace and its subnamespaces contain classes that encapsulate graphics elements such as shapes (circles, rectangles, arcs, and others), colors, fonts, brushes, and so on. 有关 GDI 的详细信息,请参阅 使用托管图形类For more information about GDI, see Using Managed Graphics Classes. 如何:创建显示进度的 Windows 窗体控件中还介绍了 GDI 的基本知识。The essentials of GDI are also described in the How to: Create a Windows Forms Control That Shows Progress.

绘图区域的几何图形Geometry of the Drawing Region

ClientRectangle控件的属性指定可用于用户屏幕上的控件的矩形区域,而的 ClipRectangle 属性 PaintEventArgs 指定实际绘制的区域。The ClientRectangle property of a control specifies the rectangular region available to the control on the user's screen, while the ClipRectangle property of PaintEventArgs specifies the area that is actually painted. (请记住,在将 Paint PaintEventArgs 实例作为其参数) 的事件方法中完成了绘制。(Remember that painting is done in the Paint event method that takes a PaintEventArgs instance as its argument). 控件可能只需要绘制部分可用区域,这种情况下,当控件的小部分显示更改时。A control might need to paint only a portion of its available area, as is the case when a small section of the control's display changes. 在这些情况下,控件开发人员必须计算要在其中进行绘制的实际矩形,并将其传递给 InvalidateIn those situations, a control developer must compute the actual rectangle to draw in and pass that to Invalidate. Invalidate采用或作为参数的的重载 Rectangle 版本 Region 使用该参数来生成的 ClipRectangle 属性 PaintEventArgsThe overloaded versions of Invalidate that take a Rectangle or Region as an argument use that argument to generate the ClipRectangle property of PaintEventArgs.

下面的代码段演示 FlashTrackBar 自定义控件如何计算要在中绘制的矩形区域。The following code fragment shows how the FlashTrackBar custom control computes the rectangular area to draw in. client变量表示 ClipRectangle 属性。The client variable denotes the ClipRectangle property. 有关完整示例,请参阅 如何:创建显示进度的 Windows 窗体控件For a complete sample, see How to: Create a Windows Forms Control That Shows Progress.

Rectangle invalid = new Rectangle(
    client.X + min,
    max - min,

Dim invalid As Rectangle = New Rectangle( _
    client.X + lmin, _
    client.Y, _
    lmax - lmin, _


释放图形资源Freeing Graphics Resources

图形对象开销高昂,因为它们使用系统资源。Graphics objects are expensive because they use system resources. 此类对象包括类的实例 System.Drawing.Graphics System.Drawing.Brush ,以及、 System.Drawing.Pen 和其他图形类的实例。Such objects include instances of the System.Drawing.Graphics class as well as instances of System.Drawing.Brush, System.Drawing.Pen, and other graphics classes. 只有在需要图形资源并在使用完毕后立即将其释放,这一点非常重要。It is important that you create a graphics resource only when you need it and release it soon as you are finished using it. 如果创建实现接口的类型 IDisposable ,请在完成该操作后调用其方法,以便 Dispose 释放资源。If you create a type that implements the IDisposable interface, call its Dispose method when you are finished with it in order to free resources.

下面的代码段演示 FlashTrackBar 自定义控件如何创建和释放 Brush 资源。The following code fragment shows how the FlashTrackBar custom control creates and releases a Brush resource. 有关完整的源代码,请参阅 如何:创建显示进度的 Windows 窗体控件For the complete source code, see How to: Create a Windows Forms Control That Shows Progress.

private Brush baseBackground = null;
Private baseBackground As Brush
if (baseBackground == null) {
    if (showGradient) {
        baseBackground = new LinearGradientBrush(new Point(0, 0),
                                                 new Point(ClientSize.Width, 0),
    else if (BackgroundImage != null) {
        baseBackground = new TextureBrush(BackgroundImage);
    else {
        baseBackground = new SolidBrush(BackColor);

If (baseBackground Is Nothing) Then

    If (myShowGradient) Then
        baseBackground = New LinearGradientBrush(New Point(0, 0), _
                                                 New Point(ClientSize.Width, 0), _
                                                 StartColor, _
    ElseIf (BackgroundImage IsNot Nothing) Then
        baseBackground = New TextureBrush(BackgroundImage)
        baseBackground = New SolidBrush(BackColor)
    End If

End If
protected override void OnResize(EventArgs e) {
    if (baseBackground != null) {
        baseBackground = null;
Protected Overrides Sub OnResize(ByVal e As EventArgs)
    If (baseBackground IsNot Nothing) Then
        baseBackground = Nothing
    End If
End Sub

另请参阅See also