Recipe 14.2. Creating a Simple User Control


Problem

You would like to create your own Windows Forms control by building it up from other existing controls.

Solution

Sample code folder: Chapter 14\UserControl

Create a user control, a custom user-interface control built from a drawing surface in which any other existing controls can appear.

Discussion

Visual Basic allows you to build two types of controls: user controls and custom controls. User controls act somewhat like borderless forms on which you can "draw" other existing controls. Custom controls provide no default user interface; you must manage all custom control drawing yourself through source code. This recipe will focus on the user control, designing a simple control that displays the current time.

Create a new Windows Forms application. For now, we'll just ignore the Form1 form included in the project. To add a new user control to the project, select the Project Add User Control menu command. Accept the default Figure 14-2. A new user control surface


Our simple user control will include two constituent controls: a label to display the time, and a timer that will trigger once a second to update the time. First, resize the user control down to a reasonable size. We used a Size property of 96, 24. Add a Label control named Label1, and set the following properties:

  • Set AutoSize to False.

  • Set Location to 0, 0.

  • Set Size to 96, 24.

  • Set Text to 12:00am.

  • Set TextAlign to MiddleCenter.

Add a Timer control named Timer1, and set the following properties:

  • Set Enabled to true.

  • Set Interval to 1000, which sets it to trigger once every second.

Switch to the source code for the user control through the View Code menu command, and add the following source code:

 Public Class UserControl1    Public Event TimeChanged(ByVal sender As UserControl1, _       ByVal e As System.EventArgs)    Private Sub Timer1_Tick(ByVal sender As System.Object, _          ByVal e As System.EventArgs) Handles Timer1.Tick       ' ----- Update every second.       Dim newTime As String       If (Me.DesignMode = False) Then          newTime = Format(Now, "h:mmtt").ToLower( )          If (newTime <> Label1.Text) Then             Label1.Text = newTime             RaiseEvent TimeChanged(Me, New System.EventArgs)          End If       End If    End Sub    Private Sub UserControl1_Load(ByVal sender As Object, _          ByVal e As System.EventArgs) Handles Me.Load       ' ----- Always reset the time when first started.       If (Me.DesignMode = False) Then          Label1.Text = Format(Now, "h:mmtt").ToLower( )          RaiseEvent TimeChanged(Me, New System.EventArgs)       End If    End Sub End Class 

That's the whole control. It's just about ready to add to the Form1 surface, but you first have to build the project to allow Visual Studio to create an instance of the control. Build it using the Build Build WindowsApplication1 menu command.

Switch over to the Form Designer for Form1. If you open the Toolbox, you will see the user control UserControl1 in the magically added WindowsApplication1 Components section, as shown in Figure 14-3. (The section name will vary if you gave your project a different name.)

Figure 14-3. The new UserControl1 control in the Toolbox


Double-click the user control in the Toolbox to add it to the form surface. It should display the "12:00am" message we added to the control's label. However, if you run the application, the running form will display the correct time.

Our user control included a public event named TimeChanged:

 Public Event TimeChanged(ByVal sender As UserControl1, _    ByVal e As System.EventArgs) 

You can respond to this event from Form1. Open the source code for Form1, and add the following event handler:

 Private Sub UserControl11_TimeChanged( _       ByVal sender As UserControl1, _       ByVal e As System.EventArgs) _       Handles UserControl11.TimeChanged    MsgBox("Changed!") End Sub 

Now, when you run the program, a "Changed!" message appears at startup (via the code for the user control's UserControl1_Load event handler), and also every time the minute changes (via the user control's Timer1_Tick event handler).

Visual Basic 2005 lets you easily design a new user control using mixtures of existing controls. You can also draw on the user control's surface through its Paint event handler, but you don't have to. (If you wish to update the surface via Paint, and not through subordinate controls, use a custom control instead of a user control.)

All child controls added to the surface of the user control are "owned" by the user control, not by (in this example) Form1. This means that your control can monitor any normal control events for its child controls, but the form using your user control will not know about those events. In this recipe, the user control exposes a Click event that Form1 can monitor. An event fires any time the user clicks on the user control surface. However, because we covered the surface with a label, clicks will never reach the user control surface, and the form will never be informed of such click events. If you want clicks on the label to transfer to the user control, you must manage that yourself. Adding this code to the user control's source code will do the trick:

 Public Shadows Event Click(ByVal sender As Object, _    ByVal e As System.EventArgs) Private Sub Label1_Click(ByVal sender As Object, _       ByVal e As System.EventArgs) Handles Label1.Click    RaiseEvent Click(Me, e) End Sub Private Sub UserControl1_Click(ByVal sender As Object, _       ByVal e As System.EventArgs) Handles MyBase.Click    RaiseEvent Click(Me, e) End Sub 

Because the UserControl class (from which our UserControl1 class derives) already exposes a Click event, you have to cover it up by declaring a new Click event. The Shadows keyword covers up the event in the base. Now add Click event handlers to capture clicks on both the Label and UserControl surfaces, and pass them on to those who add UserControl1 to their forms. Look carefully at the UserControl1_Click event handler just above. Make sure that it handles MyBase.Click, and not Me.Click. If you use Me.Click, a click on the control surface will repeatedly call itself until you run out of stack space.

After adding this code, resize the label a little smaller so that the user can click on the user control surface. Return to the source code for Form1, and add this code to its class template:

 Private Sub UserControl11_Click(ByVal sender As Object, _       ByVal e As System.EventArgs) Handles UserControl11.Click    MsgBox("Clicked!") End Sub 

Now run the program. You will see the "Clicked!" message whether you click on the label or the user control surface.

If you are building a user control for use elsewhere in the same project, any child controls you include on the surface of your user control will, by default, be accessible to the entire application. For instance, in this recipe's code, you can access the caption for the user control's label from the code for Form1. Go back to that UserControl11_TimeChanged event handler you added to Form1. On a new line, type the following:

 UserControl1.L 

As you type the letter L, you will see Label1 appear in the IntelliSense pop up. If you don't want this to happen, return to the user control designer, select Label1, and change its Modifers property to Private instead of Friend.




Visual Basic 2005 Cookbook(c) Solutions for VB 2005 Programmers
Visual Basic 2005 Cookbook: Solutions for VB 2005 Programmers (Cookbooks (OReilly))
ISBN: 0596101775
EAN: 2147483647
Year: 2006
Pages: 400

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net