如何:开发简单的 Windows 窗体控件
更新:2007 年 11 月
本节将带您步入创作自定义 Windows 窗体控件的关键步骤。在此演练中开发的简单控件允许更改其 Text 属性的对齐方式。它不会引发或处理事件。
创建简单的自定义控件
定义一个从 System.Windows.Forms.Control 派生的类。
Public Class FirstControl Inherits Control End Class
public class FirstControl:Control{}
定义属性。(不要求您定义属性,因为控件从 Control 类继承了许多属性,但大多数自定义控件通常需要定义附加属性。) 以下代码片段定义名为 TextAlignment 的属性, FirstControl 使用该属性来设置从 Control 继承的 Text 属性的显示格式。有关定义属性的更多信息,请参见 属性概述。
' ContentAlignment is an enumeration defined in the System.Drawing ' namespace that specifies the alignment of content on a drawing ' surface. Private alignmentValue As ContentAlignment = ContentAlignment.MiddleLeft <Category("Alignment"), Description("Specifies the alignment of text.")> _ Public Property TextAlignment() As ContentAlignment Get Return alignmentValue End Get Set alignmentValue = value ' The Invalidate method invokes the OnPaint method described ' in step 3. Invalidate() End Set End Property
// ContentAlignment is an enumeration defined in the System.Drawing // namespace that specifies the alignment of content on a drawing // surface. private ContentAlignment alignmentValue = ContentAlignment.MiddleLeft;
在设置更改控件可视显示的属性时,必须调用 Invalidate 方法来重新绘制该控件。Invalidate 是在 Control 基类中定义的。
重写从 Control 继承的受保护的 OnPaint 方法,以便为控件提供呈现逻辑。如果不改写 OnPaint,您的控件将无法自行绘制。在下面的代码片段中,OnPaint 方法显示从 Control 继承的 Text 属性,并使用 alignmentValue 字段指定的对齐方式。
Protected Overrides Sub OnPaint(e As PaintEventArgs) MyBase.OnPaint(e) Dim style As New StringFormat() style.Alignment = StringAlignment.Near Select Case alignmentValue Case ContentAlignment.MiddleLeft style.Alignment = StringAlignment.Near Case ContentAlignment.MiddleRight style.Alignment = StringAlignment.Far Case ContentAlignment.MiddleCenter style.Alignment = StringAlignment.Center End Select ' Call the DrawString method of the System.Drawing class to write ' text. Text and ClientRectangle are properties inherited from ' Control. e.Graphics.DrawString( _ me.Text, _ me.Font, _ New SolidBrush(ForeColor), _ RectangleF.op_Implicit(ClientRectangle), _ style) End Sub
protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); StringFormat style = new StringFormat(); style.Alignment = StringAlignment.Near; switch (alignmentValue) { case ContentAlignment.MiddleLeft: style.Alignment = StringAlignment.Near; break; case ContentAlignment.MiddleRight: style.Alignment = StringAlignment.Far; break; case ContentAlignment.MiddleCenter: style.Alignment = StringAlignment.Center; break; } // Call the DrawString method of the System.Drawing class to write // text. Text and ClientRectangle are properties inherited from // Control. e.Graphics.DrawString( Text, Font, new SolidBrush(ForeColor), ClientRectangle, style); }
提供控件属性。属性可使可视化设计器在设计时适当地显示控件及其属性和事件。以下代码片段将属性应用于 TextAlignment 属性。在 Visual Studio 这样的设计器中,Category 属性 (Attribute)(如代码片段所示)使该属性 (Property) 显示在逻辑类别中。在选择 TextAlignment 属性 (Property) 时,Description 属性 (Attribute) 使说明字符串显示在“属性”窗口的底部。有关属性的更多信息,请参见 组件的设计时属性 (Attribute)。
<Category("Alignment"), Description("Specifies the alignment of text.")> _ Public Property TextAlignment() As ContentAlignment
[ Category("Alignment"), Description("Specifies the alignment of text.") ]
(可选)提供控件资源。通过使用编辑器选项(C# 中为 /res),可以为控件提供诸如位图之类的资源,从而将资源与控件打包。运行时,可以使用 ResourceManager 类的方法检索资源。有关创建和使用资源的更多信息,请参见 应用程序中的资源。
编译和部署控件。要编译和部署 FirstControl,请执行以下步骤:
将下列示例中的代码保存到源文件(如 FirstControl.cs 或 FirstControl.vb)。
将源代码编译成程序集,并将其保存到应用程序的目录中。为了实现这一目的,需在包含源文件的目录中执行以下命令。
vbc /t:library /out:[path to your application's directory]/CustomWinControls.dll /r:System.dll /r:System.Windows.Forms.dll /r:System.Drawing.dll FirstControl.vb
csc /t:library /out:[path to your application's directory]/CustomWinControls.dll /r:System.dll /r:System.Windows.Forms.dll /r:System.Drawing.dll FirstControl.cs
/t:library 编译器选项告诉编译器正在创建的程序集是一个库(而不是一个可执行文件)。/out 选项用来指定程序集的路径和名称。/r 选项提供代码所引用的程序集的名称。在本示例中,创建了一个仅供您自己的应用程序使用的专用程序集。因此,您必须将其保存到您的应用程序的目录中。有关打包和部署控件以进行分发的更多信息,请参见 部署 .NET Framework 应用程序。
下面的示例显示了 FirstControl 的代码。该控件包含在命名空间 CustomWinControls 中。命名空间提供了相关类型的逻辑分组。可以在新命名空间或现有的命名空间中创建控件。在 C# 中,using 声明(在 Visual Basic 中,Imports)允许从命名空间访问类型,而无须使用完全限定的类型名称。在下面的示例中,using 声明允许代码仅以 Control 来访问 System.Windows.Forms 中的 Control 类,而无需使用完全限定名称 System.Windows.Forms.Control。
Imports System
Imports System.Drawing
Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms
Public Class FirstControl
Inherits Control
Public Sub New()
End Sub
' ContentAlignment is an enumeration defined in the System.Drawing
' namespace that specifies the alignment of content on a drawing
' surface.
Private alignmentValue As ContentAlignment = ContentAlignment.MiddleLeft
<Category("Alignment"), Description("Specifies the alignment of text.")> _
Public Property TextAlignment() As ContentAlignment
Get
Return alignmentValue
End Get
Set
alignmentValue = value
' The Invalidate method invokes the OnPaint method described
' in step 3.
Invalidate()
End Set
End Property
Protected Overrides Sub OnPaint(e As PaintEventArgs)
MyBase.OnPaint(e)
Dim style As New StringFormat()
style.Alignment = StringAlignment.Near
Select Case alignmentValue
Case ContentAlignment.MiddleLeft
style.Alignment = StringAlignment.Near
Case ContentAlignment.MiddleRight
style.Alignment = StringAlignment.Far
Case ContentAlignment.MiddleCenter
style.Alignment = StringAlignment.Center
End Select
' Call the DrawString method of the System.Drawing class to write
' text. Text and ClientRectangle are properties inherited from
' Control.
e.Graphics.DrawString( _
me.Text, _
me.Font, _
New SolidBrush(ForeColor), _
RectangleF.op_Implicit(ClientRectangle), _
style)
End Sub
End Class
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
namespace CustomWinControls
{
public class FirstControl : Control
{
public FirstControl()
{
}
// ContentAlignment is an enumeration defined in the System.Drawing
// namespace that specifies the alignment of content on a drawing
// surface.
private ContentAlignment alignmentValue = ContentAlignment.MiddleLeft;
[
Category("Alignment"),
Description("Specifies the alignment of text.")
]
public ContentAlignment TextAlignment
{
get
{
return alignmentValue;
}
set
{
alignmentValue = value;
// The Invalidate method invokes the OnPaint method described
// in step 3.
Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
StringFormat style = new StringFormat();
style.Alignment = StringAlignment.Near;
switch (alignmentValue)
{
case ContentAlignment.MiddleLeft:
style.Alignment = StringAlignment.Near;
break;
case ContentAlignment.MiddleRight:
style.Alignment = StringAlignment.Far;
break;
case ContentAlignment.MiddleCenter:
style.Alignment = StringAlignment.Center;
break;
}
// Call the DrawString method of the System.Drawing class to write
// text. Text and ClientRectangle are properties inherited from
// Control.
e.Graphics.DrawString(
Text,
Font,
new SolidBrush(ForeColor),
ClientRectangle, style);
}
}
}
在窗体上使用自定义控件
下面的示例说明了一个使用 FirstControl 的简单窗体。它创建了三个 FirstControl 实例,每个实例都有不同的 TextAlignment 属性值。
编译和运行该示例
将下列示例中的代码保存到源文件(SimpleForm.cs 或 SimpleForms.vb)。
通过从包含该源文件的目录中执行以下命令,将源代码编译成可执行的程序集。
vbc /r:CustomWinControls.dll /r:System.dll /r:System.Windows.Forms.dll /r:System.Drawing.dll SimpleForm.vb
csc /r:CustomWinControls.dll /r:System.dll /r:System.Windows.Forms.dll /r:System.Drawing.dll SimpleForm.cs
CustomWinControls.dll 是包含类 FirstControl 的程序集。该程序集必须与存取它的窗体源文件位于同一目录中(SimpleForm.cs 或 SimpleForms.vb)。
使用下列命令执行 SimpleForm.exe。
SimpleForm
Imports System
Imports System.Drawing
Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms
Public Class SimpleForm
Inherits System.Windows.Forms.Form
Private firstControl1 As FirstControl
Private components As System.ComponentModel.Container = Nothing
Public Sub New()
InitializeComponent()
End Sub
Private Sub InitializeComponent()
Me.firstControl1 = New FirstControl()
Me.SuspendLayout()
'
' firstControl1
'
Me.firstControl1.BackColor = System.Drawing.SystemColors.ControlDark
Me.firstControl1.Location = New System.Drawing.Point(96, 104)
Me.firstControl1.Name = "firstControl1"
Me.firstControl1.Size = New System.Drawing.Size(75, 16)
Me.firstControl1.TabIndex = 0
Me.firstControl1.Text = "Hello World"
Me.firstControl1.TextAlignment = System.Drawing.ContentAlignment.MiddleCenter
'
' SimpleForm
'
Me.ClientSize = New System.Drawing.Size(292, 266)
Me.Controls.Add(firstControl1)
Me.Name = "SimpleForm"
Me.Text = "SimpleForm"
Me.ResumeLayout(False)
End Sub
<STAThread()> _
Shared Sub Main()
Application.Run(New SimpleForm())
End Sub
End Class
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
namespace CustomWinControls
{
public class SimpleForm : System.Windows.Forms.Form
{
private FirstControl firstControl1;
private System.ComponentModel.Container components = null;
public SimpleForm()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
private void InitializeComponent()
{
this.firstControl1 = new FirstControl();
this.SuspendLayout();
//
// firstControl1
//
this.firstControl1.BackColor = System.Drawing.SystemColors.ControlDark;
this.firstControl1.Location = new System.Drawing.Point(96, 104);
this.firstControl1.Name = "firstControl1";
this.firstControl1.Size = new System.Drawing.Size(75, 16);
this.firstControl1.TabIndex = 0;
this.firstControl1.Text = "Hello World";
this.firstControl1.TextAlignment = System.Drawing.ContentAlignment.MiddleCenter;
//
// SimpleForm
//
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.firstControl1);
this.Name = "SimpleForm";
this.Text = "SimpleForm";
this.ResumeLayout(false);
}
[STAThread]
static void Main()
{
Application.Run(new SimpleForm());
}
}
}