Previous section   Next section

12.4 Events

Today's Graphical User Interface programming model requires event-driven programming . A GUI program waits for the user to take an action, such as choosing among menu selections, pushing buttons, updating text fields, clicking icons, and so forth. Each action causes an event to be raised. Other events can be raised without direct user action, such as events that correspond to timer ticks of the internal clock, email being received, file-copy operations completing, etc.

An event is the encapsulation of the idea that "something happened" to which the program must respond.

In a GUI environment, any number of widgets can raise an event. For example, when you click a button, it might raise the Click event. When you add to a drop-down list, it might raise a ListChanged event.

Other classes will be interested in responding to these events. How they respond is not of interest to the class raising the event. The button says, "I was clicked," and the responding classes react appropriately.

12.4.1 Publishing and Subscribing

In VB.NET, any object can publish a set of events to which other classes can subscribe. When the publishing class raises an event, all the subscribed classes are notified.

This design is similar to the Publish/Subscribe (Observer) Pattern described in the seminal work Design Patterns by Gamma, et al. (Addison-Wesley). Gamma describes the intent of this pattern: "Define a one to many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically."

With this mechanism, your object can say, "Here are things I can notify you about," and other classes might sign up, saying, "Yes, let me know when that happens." For example, a button might notify any number of interested observers when it is clicked. The button is called the publisher because the button publishes the Click event and the other classes are the subscribers because they subscribe to the Click event.

Visual Basic .NET provides extensive support for handling events such as button clicks. The Button object is declared with the keyword WithEvents. Right-click on your form, and choose View Code. Visual Studio .NET will take you to the code view of your form, as shown in Figure 12-1.

Figure 12-1. Code view
figs/pvn2_1201.gif

It looks like there is not much there. Notice, however, that there is a gray box with the words "Windows Form Designer generated code," and to the left of the box is a plus sign. Click on the plus sign to expand this region of code that was created by Visual Studio .NET.

Inside this area, Visual Studio .NET has provided your class with a constructor, a Dispose( ) method, and various declarations. Just below the Dispose( ) method are the declarations of the two controls you've added to your form: the Label and the Button, as shown circled and highlighted in Figure 12-2.

Figure 12-2. The Label and the Button declared
figs/pvn2_1202.gif

Notice that the declaration of both controls includes the keyword WithEvents. This indicates that the Button will raise events. The Button class raises a number of events, as you can discover by looking up the Button class in the documentation, as shown in Figure 12-3.

Figure 12-3. Button documentation
figs/pvn2_1203.gif

The event we care about is the Click event, which is raised every time the button is clicked. Each control has a default event, and the Button's default event is Click. You can create the event handler for the default event by double-clicking on the Button from the design view.

Doing so causes Visual Studio .NET to create a skeleton event handler for you:

Private Sub btnChange_Click( _
      ByVal sender As System.Object, _
      ByVal e As System.EventArgs) _
        Handles btnChange.Click
End Sub

Every event handler takes two parameters. The first is of type Object and is called sender, by convention. This is the control that raised the event. The second is of type EventArgs (or a class derived from EventArgs) and is a class that contains information about the event. Often this class has no useful content, but for some events this class provides useful information for handling the event.

Finally, the method is appended with the keyword Handles followed by the event that the method is designed to handle. In this case, Visual Studio .NET has declared that the btnChange_Click method will handle the Click event for the control btnChange.

All you need do is write the code within the method for whatever is supposed to happen when the button is clicked. In this case, we'd like to change the contents of the label when the button is clicked. Add the following code to the event handler method:

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

     lblOutput.Text = "Goodbye!"
     lblOutput.BackColor = Color.Blue
     lblOutput.ForeColor = Color.Yellow
End Sub

This code will cause the text of the label to change, along with its background color and foreground color. Run the application with Control-F5. Click on the button. Hey! Presto! The text changes, as shown in Figure 12-4.

Figure 12-4. Testing the event handler
figs/pvn2_1204.gif

To ensure that you fully understand what is happening with this code, put a break point in the event handler and then run the program in debug mode. When you click on the button you'll see the program stop at the break point in the event handler.

12.4.2 Events and Delegates

An alternative to the WithEvents/Handles syntax is to add the keyword AddHandler and to use the keyword AddressOf to mark the method that handles the event.

When you write:

AddHandler myButton.Click, AddressOf MyButton_Click

what you are writing is really shorthand for:

AddHandler myButton.Click, New EventHandler(AddressOf MyButton_Click)

EventHandler is the name of the implicitly defined delegate. Every event-handling delegate in .NET is in the following form:

Public Delegate Event (sender as Object, e as EventArgs)

The first parameter, sender, represents the object raising the event, and the second parameter, e, is an EventArgs (or derived) object that may contain useful information about the event.

When you call RaiseEvent, you are calling Invoke( ) on EventHandler (the implicitly created delegate).


  Previous section   Next section
Top