Developing a Simple Windows Forms Control
This section walks you through the key steps for authoring a custom Windows Forms control. The simple control developed in this walkthrough allows the alignment of its Text property to be changed. It does not raise or handle events.
To create a simple custom control
Define a class that derives from System.Windows.Forms.Control.
Public Class FirstControl Inherits Control ... End Class [C#]public class FirstControl:Control{...}
Define properties. (You are not required to define properties, because a control inherits many properties from the Control class, but most custom controls generally do define additional properties.) The following code fragment defines a property named
TextAlignment
thatFirstControl
uses to format the display of the' ContentAlignment is an enumeration defined in the System.Drawing ' namespace that specifies the alignment of content on a drawing ' surface. Private alignment As ContentAlignment = ContentAlignment.MiddleLeft Public Property TextAlignment() As ContentAlignment Get Return alignment End Get Set alignment = value ' The Invalidate method invokes the OnPaint method described ' in step 3. Invalidate() End Set End Property [C#]// ContentAlignment is an enumeration defined in the System.Drawing // namespace that specifies the alignment of content on a drawing // surface. private ContentAlignment alignment = ContentAlignment.MiddleLeft; public ContentAlignment TextAlignment { get { return alignment; } set { alignment = value; // The Invalidate method invokes the OnPaint method described // in step 3. Invalidate(); } }
When you set a property that changes the visual display of the control, you must invoke the Invalidate method to redraw the control. Invalidate is defined in the base class Control.
Override the protected OnPaint method inherited from Control to provide rendering logic to your control. If you do not override OnPaint, your control will not be able to draw itself. In the following code fragment, the OnPaint method displays the Text property inherited from Control with a default alignment.
Public Class FirstControl Inherits Control Public Sub New() ... End Sub Protected Overrides Sub OnPaint(e As PaintEventArgs) MyBase.OnPaint(e) e.Graphics.DrawString(Text, Font, New SolidBrush(ForeColor), RectangleF.op_Implicit(ClientRectangle), style) End Sub End Class [C#]public class FirstControl : Control{ public FirstControl() {...} protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); e.Graphics.DrawString(Text, Font, new SolidBrush(ForeColor), ClientRectangle, style); } }
The preceding code displays text with the default alignment. The code example at the end of this topic shows how to change the alignment of Text to that specified by the
TextAlignment
property, defined in step 2 earlier in this section.Provide attributes for your control. Attributes enable a visual designer to display your control and its properties and events appropriately at design time. The following code fragment applies attributes to the
TextAlignment
property. In a designer such as Microsoft Visual Studio .NET, the Category attribute (shown in the code fragment) causes the property to be displayed under a logical category. The Description attribute causes a descriptive string to be displayed at the bottom of the Properties window when theTextAlignment
property is selected. For more information about attributes, see Design-Time Attributes for Components.<Category("Alignment"), _ Description("Specifies the alignment of text.")> _ Public Property TextAlignment() As ContentAlignment ... End Class [C#][ Category("Alignment"), Description("Specifies the alignment of text.") ] public ContentAlignment TextAlignment {...}
(optional) Provide resources for your control. You can provide a resource, such as a bitmap, for your control by using a compiler option (/res for C#) to package resources with your control. At run time, the resource can be retrieved using the methods of the System.Resources.ResourceManager class. For more information about creating and using resources, see the .NET Samples – How To: Resources QuickStart.
Compile and deploy your control. To compile and deploy
FirstControl,
execute the following steps:Save the code in the following sample to a source file (such as FirstControl.cs or FirstControl.vb).
Compile the source code into an assembly and save it in your application's directory. To accomplish this, execute the following command from the directory that contains the source file.
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
The /t:library compiler option tells the compiler that the assembly you are creating is a library (and not an executable). The /out option specifies the path and name of the assembly. The
The following sample shows the code for FirstControl
. The control is enclosed in the namespace CustomWinControls
. A namespace provides a logical grouping of related types. You can create your control in a new or existing namespace. In C#, the using declaration (in Visual Basic, Imports) allows types to be accessed from a namespace without using the fully qualified name of the type. In the following example, the using declaration allows code to access the class Control from System.Windows.Forms as simply Control instead of having to use the fully qualified name System.Windows.Forms.Control.
Option Explicit
Option Strict
Imports System
Imports System.ComponentModel
Imports System.Windows.Forms
Imports System.Drawing
Namespace CustomWinControls
Public Class FirstControl
Inherits Control
Private alignment As ContentAlignment = ContentAlignment.MiddleLeft
<Category("Alignment"), _
Description("Specifies the alignment of text.")> _
Public Property TextAlignment() As ContentAlignment
Get
Return alignment
End Get
Set
alignment = value
' The Invalidate method invokes the OnPaint method.
Invalidate()
End Set
End Property
' OnPaint aligns text, as specified by the
' TextAlignment property, by passing a parameter
' to the DrawString method of the System.Drawing.Graphics object.
Protected Overrides Sub OnPaint(e As PaintEventArgs)
MyBase.OnPaint(e)
Dim style As New StringFormat()
style.Alignment = StringAlignment.Near
Select Case alignment
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(Text, Font, New SolidBrush(ForeColor), RectangleF.op_Implicit(ClientRectangle), style)
End Sub
End Class
End Namespace
[C#]namespace CustomWinControls {
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
public class FirstControl : Control {
private ContentAlignment alignment = ContentAlignment.MiddleLeft;
[
Category("Alignment"),
Description("Specifies the alignment of text.")
]
public ContentAlignment TextAlignment {
get {
return alignment;
}
set {
alignment = value;
// The Invalidate method invokes the OnPaint method.
Invalidate();
}
}
// OnPaint aligns text, as specified by the
// TextAlignment property, by passing a parameter
// to the DrawString method of the System.Drawing.Graphics object.
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
StringFormat style = new StringFormat();
style.Alignment = StringAlignment.Near;
switch (alignment) {
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);
}
}
}
Using the Custom Control on a Form
The following example shows a simple form that uses FirstControl
. It creates three instances of FirstControl
, each with a different value for the TextAlignment
property.
To compile and run this sample
Save the code in the following example to a source file (SimpleForm.cs or SimpleForms.vb).
Compile the source code into an executable assembly by executing the following command from the directory that contains the source file.
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 is the assembly that contains the class
FirstControl
. This assembly must be in the same directory as the source file for the form that accesses it (SimpleForm.cs or SimpleForms.vb).Execute SimpleForm.exe using the following command.
SimpleForm
Option Explicit
Option Strict
Imports System
Imports System.Windows.Forms
Imports System.Drawing
Imports CustomWinControls
Class SimpleForm
Inherits Form
Private leftControl As FirstControl
Private centerControl As FirstControl
Private rightControl As FirstControl
Protected Overloads Overrides Sub Dispose(disposing as Boolean)
MyBase.Dispose(disposing)
End Sub
Public Sub New()
leftControl = New FirstControl()
With leftControl
.Text = "Left"
.Location = New Point(50, 50)
.Size = New Size(50, 50)
End With
Controls.Add(leftControl)
centerControl = New FirstControl()
With centerControl
.TextAlignment = ContentAlignment.MiddleCenter
.Text = "Center"
.Location = New Point(125, 50)
.Size = New Size(50, 50)
End With
Controls.Add(centerControl)
rightControl = New FirstControl()
With rightControl
.TextAlignment = ContentAlignment.MiddleRight
.Text = "Right"
.Location = New Point(200, 50)
.Size = New Size(50, 50)
End With
Controls.Add(rightControl)
End Sub
<STAThread()> _
Public Shared Sub Main()
Dim myForm As New SimpleForm()
myForm.Text = "Uses FirstControl"
myForm.Size = New Size(400, 150)
Application.Run(myForm)
End Sub
End Class
[C#]using System;
using System.Windows.Forms;
using System.Drawing;
using CustomWinControls;
class SimpleForm : Form {
private FirstControl left;
private FirstControl center;
private FirstControl right;
protected override void Dispose(bool disposing) {
base.Dispose(disposing);
}
public SimpleForm() : base() {
left = new FirstControl();
left.Text = "Left";
left.Location = new Point(50, 50);
left.Size = new Size(50, 50);
Controls.Add(left);
center = new FirstControl();
center.TextAlignment = ContentAlignment.MiddleCenter;
center.Text = "Center";
center.Location = new Point(125, 50);
center.Size = new Size(50, 50);
Controls.Add(center);
right = new FirstControl();
right.TextAlignment = ContentAlignment.MiddleRight;
right.Text = "Right";
right.Location = new Point(200, 50);
right.Size = new Size(50, 50);
Controls.Add(right);
}
[STAThread]
public static void Main(string[] args) {
Form form = new SimpleForm();
form.Text = "Uses FirstControl";
form.Size = new Size(400, 150);
Application.Run(form);
}
}
See Also
Properties in Windows Forms Controls | Events in Windows Forms Controls