227
Dim dlg As New ColorDialog dlg.Color = Label1.BackColor
If dlg.ShowDialog = DialogResult.OK Then Label1.BackColor = dlg.Color
End If dlg.Dispose
End Sub Resent Click event handler
Private Sub mnuFormatReset_Click _ ByVal sender As Object, _
ByVal e As EventArgs _ Handles mnuFormatReset.Click
Label1.Font = origFont Label1.ForeColor = origForeColor
Label1.BackColor = origBackColor End Sub
End Class
5.6 Creating a Control
A control is a component with a visual representation. The Windows Forms class library provides the base functionality for controls through the Control class defined in the System.Windows.Forms
namespace. All controls derive directly or indirectly from the Control class. In addition, Windows Forms provides a class called UserControl for the purpose of making it easy to write custom control
classes. The derivation of the UserControl class is shown in
Figur e 5- 27 .
Figure 5-27. The derivation hierarchy of the UserControl class
5.6.1 Building Controls from Other Controls
The easiest way to create a new control is to aggregate and modify the functionality of one or more existing controls. To do this in Visual Studio .NETs Windows Forms Designer, perform the following
steps:
1. Choose Project Add User Control from the main menu.
2. Type the name of the .vb file that will hold the code for the control, and click OK. The designer displays a blank user control in design mode, as shown in
Figur e 5- 28 .
Figure 5-28. A blank user control in Visual Studio .NETs Windows Forms Designer
228
3. Add controls from the Toolbox window just as you would when laying out a form. Controls that are made part of another control are called constituent controls .
Figur e 5- 29 shows a user
control that has two constituent controls: a Label and a TextBox.
Figure 5-29. A user control with two constituent controls
The user control shown in Figur e 5- 29
is a good start on a captioned text-box control—a text box that carries around its own caption. These additional steps would also be helpful:
a. Set the Label controls AutoSize property to True
so the label expands to the size needed for displaying its text.
b. Dock the Label control to the left side of the user control. This allows the TextBox control to be docked to the Label control. The benefit of docking the TextBox control
to the Label control is that the TextBox control will move whenever the Label control resizes itself.
c. Dock the TextBox control to fill the remainder of the space. 4. Add any appropriate properties to the user control. This could involve overriding properties
inherited from base classes or creating new properties. For the captioned text-box user control, do the following:
a. Override the Text property. The purpose of this property is to allow the client environment to set and read the text displayed in the constituent TextBox control.
Here is the code: b.
Public Overrides Property Text As String c.
Get d.
Return txtText.Text e.
End Get f.
SetByVal Value As String g.
txtText.Text = Value h.
End Set End Property
As can be seen from the code, the user controls Text property is simply mapped to the TextBox controls Text property.
i. Create a new property for setting the caption text. Here is the code:
j. Public Property Caption As String
k. Get
l. Return lblCaption .Text
m. End Get
n. SetByVal Value As String
o. lblCaption .Text = Value
p. End Set
229
End Property In this case, the Caption property is mapped to the Label controls Text property.
5. Add any appropriate events to the user control. This could involve invoking base-class events or creating and invoking new events. For the captioned text-box user control, do the following:
a. Add a handler for the constituent TextBox controls TextChanged property. Within the handler, invoke the base classs TextChanged event. Here is the code:
b. Private Sub txtText_TextChanged _
c. ByVal sender As Object, _
d. ByVal e As EventArgs _
e. Handles txtText.TextChanged
f. Me.OnTextChangede
End Sub Notice that this code calls the OnTextChanged method, which is declared in the
Control class. The purpose of this method is to fire the TextChanged event, which is also declared in the Control class Visual Basic .NET doesnt provide a way to fire a
base-class event directly. There are On EventName
methods for each of the events defined in the Control class.
The OnTextChanged method is overridable. If you override it in your derived class, be sure that your overriding method calls MyBase.OnTextChanged. If you dont, the
TextChanged event wont be fired.
g. Declare a new event to notify the client when the user controls Caption property is changed. Name the event CaptionChanged. Add a handler for the Label controls
TextChanged event and raise the CaptionChanged event from there. Heres the code: h.
Event CaptionChanged As EventHandler i.
j. Private Sub lblCaption_TextChanged _
k. ByVal sender As Object, _
l. ByVal e As EventArgs _
m. Handles lblCaption.TextChanged
n. RaiseEvent CaptionChangedMe, EventArgs.Empty
End Sub Note the arguments to the CaptionChanged event. The value
Me is passed as the
sender of the event, and EventArgs.Empty
is passed as the event arguments. The Empty field of the EventArgs class returns a new, empty EventArgs object.
6. Add any appropriate attributes to the syntax elements of the class. For example, the Caption property will benefit from having a Category attribute and a Description attribute, as shown in
bold here:
7. 8.
CategoryAppearance, _
9. DescriptionThe text appearing next to the textbox. _
10. Public Property _
11. Caption As String
12. Get
13. Return lblCaption .Text
14. End Get
15. SetByVal Value As String
16. lblCaption .Text = Value
17. End Set
End Property These attributes are compiled into the code and are picked up by the Visual Studio .NET IDE.
The Category
attribute determines in which category the property will appear in the
230
Properties window. The Description
attribute determines the help text that will be displayed in the Properties window when the user clicks on that property. See Component Attributes in
Chapt er 4 for a list of attributes defined in the System.ComponentModel namespace.
This is all very similar to creating forms. As with forms, custom controls can be defined directly in code. Ex am ple 5- 4
shows a complete class definition for the captioned text-box control, created without the aid of the Windows Forms Designer. It can be compiled from the command line with this command:
vbc filename.vb r:System.dll,System.Drawing.dll,System.Windows.Forms.dll t:library
Note the t:library
switch for creating a .dll rather than an .exe file.
Example 5-4. A custom Control class
Imports System Imports System.ComponentModel
Imports System.Drawing Imports System.Windows.Forms
Public Class MyControl Inherits UserControl
Private WithEvents lblCaption As Label Private WithEvents txtText As TextBox
Event CaptionChanged As EventHandler Public Sub New
MyBase.New Instantiate a Label object and set its properties.
lblCaption = New Label With lblCaption
.AutoSize = True .Dock = DockStyle.Left
.Size = New Size53, 13 .TabIndex = 0
.Text = lblCaption End With
Instantiate a TextBox object and set its properties. txtText = New TextBox
With txtText .Dock = DockStyle.Fill
.Location = New Point53, 0 .Size = New Size142, 20
.TabIndex = 1 .Text = txtText
End With Add the label and text box to the forms Controls collection.
Me.Controls.AddRangeNew Control {txtText, lblCaption} Set the size of the form.
Me.Size = New Size195, 19 End Sub
Override the Control classs Text property. Map it to the
231
constituent TextBox controls Text property. CategoryAppearance, _
DescriptionThe text contained in the textbox. _ Public Overrides Property Text As String
Get Return txtText.Text
End Get SetByVal Value As String
txtText.Text = Value End Set
End Property Add a Caption property. Map it to the constituent Label
controls Text property. CategoryAppearance, _
DescriptionThe text appearing next to the textbox. _ Public Property _
Caption As String Get
Return lblCaption.Text End Get
SetByVal Value As String lblCaption.Text = Value
End Set End Property
When the constituent TextBox controls TextChanged event is received, fire the user controls TextChanged event.
Private Sub txtText_TextChanged _ ByVal sender As Object, _
ByVal e As EventArgs _ Handles txtText.TextChanged
Me.OnTextChangede End Sub
When the constituent Label controls TextChanged event is received, fire the user controls CaptionChanged event.
Private Sub lblCaption_TextChanged _ ByVal sender As Object, _
ByVal e As EventArgs _ Handles lblCaption.TextChanged
RaiseEvent CaptionChangedMe, EventArgs.Empty End Sub
End Class
After compiling the code in Ex am ple 5- 4
, either the custom control can be added to the Visual Studio .NET toolbox and added to forms just like other controls, or it can be referenced and
instantiated from an application compiled at the command line. To add the custom control to the Visual Studio .NET toolbox:
1. Deploy the custom controls .dll file into the client applications bin directory. The bin directory is a directory created by Visual Studio .NET when the client application is created.
2. From the Visual Studio .NET menu, select Tools Customize Toolbox. The Customize
Toolbox dialog box appears, as shown in Figur e 5- 3 0
.
Figure 5-30. The Customize Toolbox dialog box
232
3. Click the .NET Framework Components tab, then click the Browse button. 4. Browse for and select the .dll file compiled from the code in
Ex am ple 5- 4 .
5. The controls in the .dll file are added to the Customize Toolbox dialog box, as shown in Figur e 5- 31
. In this case there is only one control in the .dll file—the MyControl control.
Figure 5-31. Adding a control to the Customize Toolbox dialog box
6. Ensure that a checkmark appears next to the control name, and click OK. The control should now appear on the General tab of the Toolbox window, as shown in
Figur e 5- 32 .
Figure 5-32. The Toolbox window, showing the custom control from Ex a m ple 5 - 4
233
After you add the custom control to the Toolbox, the control can be added to a form just like any other control.
To use the custom control from a non-Visual Studio .NET application, these steps are required: 1. Deploy the custom controls .dll file into the same directory as the client .vb file.
2. Declare, instantiate, and use the control in client application code, in the same way that has been done throughout this chapter for standard controls.
3. Reference the controls assembly in the compilation command. The code in
Ex am ple 5- 5 shows how to use the control. It can be compiled with this command:
vbc MyApp.vb r:System.dll,System.Drawing.dll,System.Windows.Forms.dll,MyControl.dll
t:winexe
Note that the command should be typed on a single line.
Example 5-5. Using a custom control
Imports System.Drawing Imports System.Windows.Forms
Module modMain System.STAThreadAttribute Public Sub Main
System.Threading.Thread.CurrentThread.ApartmentState = _ System.Threading.ApartmentState.STA
System.Windows.Forms.Application.RunNew Form1 End Sub
End Module Public Class Form1
Inherits System.Windows.Forms.Form Private ctrl As New MyControl
Public Sub New ctrl.Caption = This is the caption.
ctrl.Text = This is the text. Controls.Addctrl
End Sub End Class
The resulting display is shown in Figur e 5- 33
.
234
Figure 5-33. Using a custom control
5.6.2 Building Controls That Draw Themselves