Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning Visual Basic 2005 (2006)

.pdf
Скачиваний:
219
Добавлен:
17.08.2013
Размер:
14.97 Mб
Скачать

Chapter 13

2.Now switch to the Forms Designer for Form1. Drag a Button control from the Toolbox and drop it on your form. Set the Name property to btnTaskbarHeight and the Text property to Taskbar Height.

3.Double-click the button and add the following highlighted code to its Click event handler:

Private Sub btnTaskbarHeight_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles btnTaskbarHeight.Click

MessageBox.Show(“Taskbar Height = “ & _

MyNamespace1.TaskBarHeight & “ pixels”, “Form1”)

End Sub

4.Run your project and click the Taskbar Height button on Form1. You’ll see a message box with the calculated height of the taskbar.

How It Works

Exposing a function or procedure from a user control is no different from exposing a function or procedure from a class. You just need to mark the function or procedure as Public so that it is exposed to the user of the class.

The TaskBarHeight function calculates the height of the taskbar by subtracting the working area height from the screen bounds height and returning the calculated value.

Public Function TaskBarHeight() As Integer

Return My.Computer.Screen.Bounds.Height - _

My.Computer.Screen.WorkingArea.Height

End Function

When you call the TaskBarHeight function from your code in Form1, you specify the control name of MyNamespace1 and then choose the TaskBarHeight function from the drop-down list in IntelliSense.

Private Sub btnTaskbarHeight_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles btnTaskbarHeight.Click

MessageBox.Show(“Taskbar Height = “ & _

MyNamespace1.TaskBarHeight & “ pixels”, “Form1”)

End Sub

There was no need to recompile the MyNamespaceControl control to expose this new function to Form1, as it did not affect the control’s user interface or properties.

Exposing Events from User Controls

Now that you’ve seen how to expose your own properties and methods from your control, you need to take a look at how to expose your own events from the control. When you add events to one of your own controls, people who use your control can take action in their code when the event is raised.

In the next Try It Out, you add three events that will return the data that is displayed in the message boxes that get displayed when the buttons are clicked.

406

Creating Your Own Custom Controls

Try It Out

Defining and Raising Events

1.Defining an event is as simple as adding an Event statement, the event name, and the parameters that the event will return. Add the following highlighted code to the MyNamespace.vb file:

‘Private members

Private strApplicationName As String = String.Empty

‘Public Events

Public Event ApplicationCopyrightChanged(ByVal text As String)

Public Event ScreenBoundsChanged(ByVal bounds As Rectangle)

Public Event ScreenWorkingAreaChanged(ByVal bounds As Rectangle)

2.To raise an event you need to specify the RaiseEvent statement, passing it the event name as well as the parameters for the event being raised. Modify the code in MyNamespace.vb as follows:

Private Sub btnApplicationCopyright_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnApplicationCopyright.Click

RaiseEvent ApplicationCopyrightChanged( _

My.Application.Info.Copyright)

MessageBox.Show(My.Application.AssemblyInfo.LegalCopyright, _

strApplicationName)

End Sub

Private Sub btnScreenBounds_Click(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles btnScreenBounds.Click

RaiseEvent ScreenBoundsChanged(My.Computer.Screen.Bounds)

MessageBox.Show(My.Computer.Screen.Bounds.ToString, _

strApplicationName)

End Sub

Private Sub btnScreenWorkingArea_Click(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles btnScreenWorkingArea.Click

RaiseEvent ScreenWorkingAreaChanged(My.Computer.Screen.WorkingArea)

MessageBox.Show(My.Computer.Screen.WorkingArea.ToString, _

strApplicationName)

End Sub

3.Start your application to test your changes.

How It Works

As mentioned earlier, to define an event, you specify the Event statement, the event name, and the parameters that the event will return. Most events for controls are going to be Click or Changed; thus you have specified the different button names suffixed with the word Changed.

The Application Copyright button returns the application copyright as a string; thus, the parameter for the ApplicationCopyrightChanged event is specified as a String data type. The Screen Bounds and Screen Working Area buttons will return the screen information in a Rectangle structure; thus you specified the Rectangle structure as the data type for these events.

407

Chapter 13

‘Public Events

Public Event ApplicationCopyrightChanged(ByVal text As String) Public Event ScreenBoundsChanged(ByVal bounds As Rectangle) Public Event ScreenWorkingAreaChanged(ByVal bounds As Rectangle)

To raise an event, you have to use the RaiseEvent statement. This looks after the tricky aspect of actually telling the control’s owner what event has been raised and passes it the appropriate parameters.

You’ll have noticed that when you typed the word RaiseEvent, Visual Studio 2005 IntelliSense kicked in and provided a drop-down list of the events that you defined. This is just another example of how the IDE makes your life as a developer much easier.

In each instance of raising the events, you simply pass the event being raised; the data that will be displayed in the message box when the appropriate button is clicked.

Private Sub btnApplicationCopyright_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnApplicationCopyright.Click

RaiseEvent ApplicationCopyrightChanged( _

My.Application.Info.Copyright)

MessageBox.Show(My.Application.Info.Copyright, _

strApplicationName)

End Sub

Private Sub btnScreenBounds_Click(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles btnScreenBounds.Click

RaiseEvent ScreenBoundsChanged(My.Computer.Screen.Bounds)

MessageBox.Show(My.Computer.Screen.Bounds.ToString, _

strApplicationName)

End Sub

Private Sub btnScreenWorkingArea_Click(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles btnScreenWorkingArea.Click

RaiseEvent ScreenWorkingAreaChanged(My.Computer.Screen.WorkingArea)

MessageBox.Show(My.Computer.Screen.WorkingArea.ToString, _

strApplicationName)

End Sub

All that remains now is to detect when the event has fired and do something. This is known as consuming an event. When a control fires an event, you can hook into the event handler. By doing this, you receive notification that the event has fired and can do something with the data that the event exposes. This is one of the core concepts of the control/event methodology that you have been using throughout this book.

Try It Out

Consuming Events

1.Switch to the Forms Designer for Form1 and add three TextBox controls as shown in Figure 13-3. Set the Name properties to txtApplicationCopyright, txtScreenBounds, and txtScreenWorkingArea, respectively.

408

Creating Your Own Custom Controls

Figure 13-3

2.Now switch to the Code Editor for Form1 and select MyNamespace1 in the Class Name combo box at the top of the Code Editor. Now click in the Method Name combo box, and you’ll see your ApplicationCopyrightChanged event in the Method Name combo box as shown in Figure 13-4. Remember, although you specifically defined three events for this control, you still get all of the other events that were defined on the various base classes that your control class inherits from.

Figure 13-4

3.Of course, if you select the control and an event, you are automatically given a handler “stub” into which you can add your event-handling code, just as you have been doing with the other controls that you’ve used all along. Select the ApplicationCopyrightChanged event in the Method Name combo box. Now add the following highlighted code to the

ApplicationCopyrightChanged event handler:

Private Sub MyNamespace1_ApplicationCopyrightChanged(ByVal text As String) _ Handles MyNamespace1.ApplicationCopyrightChanged

txtApplicationCopyright.Text = text End Sub

409

Chapter 13

4.Now select MyNamespace1 in the Class Name combo box and the ScreenBoundsChanged event in the Method Name combo box. Add the following highlighted code:

Private Sub MyNamespace1_ScreenBoundsChanged(ByVal bounds As _ System.Drawing.Rectangle) Handles MyNamespace1.ScreenBoundsChanged

txtScreenBounds.Text = bounds.ToString End Sub

5.Finally, select MyNamespace1 in the Class Name combo box and the ScreenWorkingAreaChanged event in the Method Name combo box. Add the following highlighted code to the

ScreenWorkingAreaChanged event handler:

Private Sub MyNamespace1_ScreenWorkingAreaChanged(ByVal bounds As _ System.Drawing.Rectangle) Handles MyNamespace1.ScreenWorkingAreaChanged

txtScreenWorkingArea.Text = bounds.ToString End Sub

6.Now run your project. When you click each of the buttons, the corresponding text box will be populated with the data returned by the event, and then the message box will be displayed.

How It Works

Consuming control events in your application is very straightforward and something that you’ve been doing all along with Button and TextBox controls. You merely select the control name in the Class Name combo box in the Code Editor and the appropriate event in the Method Name combo box and then write the appropriate code to consume, or handle, the event that has been raised by the control. In the case of the MyNamespace control, you are consuming three different events; ApplicationCopyrightChanged, ScreenBoundsChanged, and ScreenWorkingAreaChanged.

For the ApplicationCopyrightChanged event, you simply take the text returned from the event and set it in the Text property of your text box.

Private Sub MyNamespace1_ApplicationCopyrightChanged(ByVal text As String) _ Handles MyNamespace1.ApplicationCopyrightChanged

txtApplicationCopyright.Text = text End Sub

The ScreenBoundsChanged event is a little different. This event returns data in a Rectangle structure, which you must convert to a String data type in order to set it in the Text property of your text box. This is done using the ToString method of the Rectangle structure.

Private Sub MyNamespace1_ScreenBoundsChanged(ByVal bounds As _ System.Drawing.Rectangle) Handles MyNamespace1.ScreenBoundsChanged

txtScreenBounds.Text = bounds.ToString End Sub

410

Creating Your Own Custom Controls

The ScreenWorkingAreaChanged event is like the ScreenBoundsChanged event. This event also returns data in a Rectangle structure, which must be converted to a String data type before it can be set in the Text property of your text box.

Private Sub MyNamespace1_ScreenWorkingAreaChanged(ByVal bounds As _ System.Drawing.Rectangle) Handles MyNamespace1.ScreenWorkingAreaChanged

txtScreenWorkingArea.Text = bounds.ToString End Sub

Design Time or Run Time

In certain circumstances, it’s useful to know whether your control is in design mode or run mode. The control is in design mode is when a form is being designed and the properties of the control are being set; it is in run mode when the form is being run and the control is able to expose methods and events.

As an example, imagine that you have a control that establishes a database connection when a certain property is set. It might not be appropriate for that control to establish the connection when the form is being designed, but you will want it to when the application is being run.

Usually, a control itself has a Boolean property called DesignMode, which returns True if the control is in design mode and False if it isn’t.

In this next Try It Out, you’re going to modify the MyNamespace control by adding a Label and Timer control to it. The Text property of the label will be updated with the text “Design Mode” when your MyNamespace control is in design mode and updated with the current time when the control is in run mode.

Try It Out

Creating a Control That Understands “DesignMode”

1.Switch to the Control Designer for the MyNamespace control. Expand the height of the control so that you can place a Label control underneath the last button.

2.Drag a Label control from the Toolbox and center it underneath the last button control. Set the Name property to lblTime.

3.Now drag and drop a Timer control from the Toolbox onto the Control Designer. The timer will be added to the bottom of the IDE. Accept the default properties for this control and ensure that the Enabled property is set to False and that Interval is set to 100.

4.Now switch to the Code Editor for your MyNamespace control. You can detect when your control has been added to a form through the InitLayout method, which is defined on System. Windows.Forms.Control. This happens both at design time and at run time. This is the best point to determine which mode you’re in and, if appropriate, to start the timer. Add this code:

Protected Overrides Sub InitLayout()

‘Are we in design mode?

If DesignMode Then

lblTime.Text = “Design Mode”

Else

411

Chapter 13

Timer1.Enabled = True

End If

End Sub

5.The last thing to do is to add code to the Tick event of the timer. Select Timer1 in the Class Name combo box at the top of the Code Editor and the Tick event in the Method Name combo box. Add the highlighted code to the Tick event handler:

Private Sub Timer1_Tick(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles Timer1.Tick

‘Display the time

lblTime.Text = Now.ToLongTimeString End Sub

6.You’ll need to build the project before the changes to the control can be picked up by your Controls application. Build the project by right-clicking the MyNamespaceControl project in the Solution Explorer and choosing Build from the context menu.

7.Open the Forms Designer for Form1 in the Controls project. Delete the current MyNamespace control from the form and drag a new one from the Toolbox and drop it on your form. You’ll see the text Design Mode as shown in Figure 13-5.

Figure 13-5

8.Now run the project. You will see that the Design Mode text is replaced by the current time.

How It Works

The InitLayout method is fired when the control is initialized, both at design time and at run time. The DesignMode property of your control returns a Boolean value of True when the control is in design mode and a value of False when the control is in run mode.

If your control is in design mode, you simply want to display the text Design Mode on your label control. When the control is in run mode, you want to enable the Timer control, and the Timer control will update the label with the current time.

Protected Overrides Sub InitLayout()

‘Are we in design mode?

If DesignMode Then

lblTime.Text = “Design Mode”

412

Creating Your Own Custom Controls

Else

Timer1.Enabled = True

End If

End Sub

Of course, there are many other occasions when you might want your code to behave differently at run time than at design time. An example could be that validation rules for a property will be different. In these cases, you would check the control’s DesignMode property in exactly the same way.

The Tick event of the Timer control gets called at the specified interval of the Timer control, which in this case is every 100 milliseconds. When the Tick event is fired, you want to update the Text property of the label control with the current time. This is done by retrieving the current long time from the ToLongTimeString property of the Now object.

Private Sub Timer1_Tick(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles Timer1.Tick

‘Display the time

lblTime.Text = Now.ToLongTimeString End Sub

Because you made changes to the actual UI of the control, you had to rebuild the control and then delete the current control from Form1 and get a new instance of it from the Toolbox. You don’t have to do this when simply making code changes to the control, because those changes are automatically picked up.

Creating a Form Librar y

You do not always have to encapsulate this kind of functionality as a control. You could encapsulate the entire form and display it on demand. This is, in fact, what happens whenever an application wants to display the Open File or Print dialog boxes or any other standard dialog box. You may well discover a common functionality in your applications that would be useful to add to a reusable library. For example, you might want to have a “Customer Lookup” tool available to all of your applications, or a common login window like the one discussed earlier.

Luckily, building form libraries is incredibly easy in .NET. In fact, it’s not different from creating the kinds of forms that you’ve built so far. You just need to provide some kind of interface that allows the caller to start up the form and get values back.

Building the Form Library Project Login Form

In this Try It Out, you’ll build a simple login form. Don’t bother adding any functionality behind it to actually authenticate the user. Instead, concentrate on getting the form to display itself to the user.

Try It Out

Creating the Form Library Project

1.Close your existing project and create a new Class Library project and call it FormsLibrary.

2.Right-click the project in the Solution Explorer and select Add Reference. Select System. Windows.Forms from the available .NET components and then click OK.

413

Chapter 13

3.Now, create a new form by right-clicking the project within the Solution Explorer and selecting Add Windows Form. Call the new form Login.vb and click Add.

4.To build the form, you need to change a few of the properties. Change these properties on the form:

Set FormBorderStyle to Fixed Dialog.

Set MaximizeBox to False.

Set MinimizeBox to False.

Set StartPosition to CenterScreen.

5.Now add two labels and set their Text properties to User Name and Password, respectively.

6.Add two text boxes called txtUserName and txtPassword. Set the PasswordChar property of the Password text box to *, so that entered passwords are not displayed on the screen.

7.Now add a Button control and set the following properties:

Set Name to btnOk.

Set DialogResult to OK.

Set Text to OK.

8.Add another Button control and set the following properties:

Set Name to btnCancel.

Set DialogResult to Cancel.

Set Text to Cancel.

9.You completed Login form should look similar to the form shown in Figure 13-6.

Figure 13-6

10.In the Solution Explorer, rename Class1.vb to LoginEventArgs.vb and then add the highlighted code to that class:

Public Class LoginEventArgs

Inherits EventArgs

‘Public member

Public UserID As Integer

‘Constructor

Public Sub New(ByVal userIdentifier As Integer) UserID = userIdentifier

End Sub End Class

414

Creating Your Own Custom Controls

11.Switch to the Code Editor for the Login form and add the highlighted code:

Imports System.Windows.Forms

Public Class Login ‘Private members

Private intAttemptCount As Integer = 0 Private blnAllowClosing As Boolean = False Private intUserID As Integer

‘Public events

Public Event LoginFailed(ByVal sender As Object, ByVal e As EventArgs) Public Event LoginSucceeded(ByVal sender As Object, _

ByVal e As LoginEventArgs)

Public Event LoginCancelled(ByVal sender As Object, ByVal e As EventArgs)

End Class

12.You want to add a read-only property that allows the consumer of this class library to get the UserID of the user who has successfully logged on. Add the following code:

Public ReadOnly Property UserID() As Integer

Get

Return intUserID

End Get

End Property

13.When the Login form is activated, you want to populate the User Name field with the domain name and user name of the user who is logged into Windows. In the Class Name combo box at the top of the Code Editor, select (Login Events) and select Activated in the Method Name combo box. Add the following highlighted code to the Activated event:

Private Sub Login_Activated(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles Me.Activated

‘Populate the user name text box txtUsername.Text = My.User.Name

‘Set focus to the password text box txtPassword.Focus()

End Sub

14.You need to control when the form closes, so you’ll need to add some code to the FormClosing event. Select (Login Events) in the Class Name combo and the FormClosing event in the Method Name combo box. Add the following highlighted code:

Private Sub Login_FormClosing(ByVal sender As Object, _

ByVal e As System.Windows.Forms.FormClosingEventArgs) _

Handles Me.FormClosing

‘If we are not allowing the form to close...

If Not blnAllowClosing Then ‘Set the Cancel flag to True e.Cancel = True

End If End Sub

415