Implementing Custom Events

In the early versions of VB, programmers were limited to working with the built-in events. In VB5, however, three simple keywords—Event, RaiseEvent, and WithEvents—were added to the language to allow the programmer to define custom events or to trap events in external objects that would otherwise be inaccessible.

Custom events applications

Custom events can be used for any of the following:

• To report the progress of an asynchronous task back to the client application from an out-of-process ActiveX EXE component.

• To pass through events fired by the underlying control in an ActiveX custom control.

• As a central part of a real-time multiuser application in an n-tier client-server application. (Incidentally, events can't be fired from within a Microsoft Transaction Server Context.)

• To receive notification of events fired in automation servers.

• To query the user and receive further input.

Custom event rules

The following are some of the rules and "gotchas" for defining custom events:

• Events can be declared and fired only from within object modules (i.e., Form, User Control, and Class modules). You can't declare and fire events from a standard code module.

• Events can be handled or intercepted only from within object modules. You can't handle any type of event from within a code module. This isn't really a limitation because you can simply include a call to a function or sub within a code module from within your event handler, to pass program control to a code module—just like you would write code in form and control event handlers.

• The event declaration must be Public so that it's visible outside the object module; it can't be declared as Friend or Private.

• You can't declare an object variable as WithEvents if the object doesn't have any events.

• To allow the client application to handle the event being fired, the object variable must be declared using the WithEvents keyword.

• VB custom events don't return a value; however, you can use a ByRef argument to return a value, as you will see in the next section, "Creating a custom event."

• If your class is one of many held inside a collection, the event isn't fired to the "outside world"—unless you have a live object variable referencing the particular instance of the class raising the event.

66 Chapter 4 - Class Modules

Creating a custom event

To raise an event from within an object module, you first of all must declare the event in the declarations section of the object module that will raise the event. You do this with the Event statement using the following syntax:

[Public] Event eventname [(arglist)]

For example:

Public Event DetailsChanged(sField As String)

In the appropriate place in your code, you need to fire the event using the RaiseEvent statement. For example:

RaiseEvent DetailsChanged("Employee Name")

That is all you need to do within the object module. Simply declare an event using Event, and fire it using RaiseEvent.

The client code is just as simple. You declare an object variable using the WithEv-ents keyword to alert VB that you wish to be informed when an event is fired in the object. For example:

Private WithEvents oEmployee As Employee

This declaration should be placed in the Declarations section of the module. VB automatically places an entry for the object variable name in the Object dropdown list at the top left of your code window. When you select this, note that the events declared in the object are available to you in the Procedure drop-down list at the top right of your code window. You can then select the relevant event and its event handler. For example:

Private Sub oEmployee_DetailsChanged(sField As String)

MsgBox sField & " has been changed" End Sub

In the earlier section "The Property Let procedure," we mentioned using a custom event to fire a warning to the client as part of a data-validation procedure. Unfortunately, though, events don't return a value. However, if you define one of the parameters of your event to be ByRef, you can examine the value of the variable once the event has been handled to determine the outcome of the event handling within the client application. Here's a simple example:

Server code:

Public Event Warning(sMsg As String, ByRef Cancel As Boolean)

Public Property Let ClaimValue(dVal As Double)

Dim blnCancel As Boolean

If dVal > 10000 Then

RaiseEvent Warning("The Claim Value appears high", _ blnCancel)

If blnCancel Then

Exit Property End If






Class Module Events 67

End If mdClaimValue = dVal

End Property Client code:

Private WithEvents oServer As clsServer

Private Sub oServer_Warning(sMsg As String, _

Cancel As Boolean)

Dim iResponse As Integer iResponse = MsgBox(sMsg & " is this OK?", _ vbQuestion + vbYesNo, _ "Warning") If iResponse = vbNo Then Cancel = True


Cancel = False End If

End Sub

As you can see, this is a powerful technology. However, it also demonstrates another aspect of custom events that may not be desirable in certain circumstances: RaiseEvent is not asynchronous. In other words, when you call the RaiseEvent statement in your class code, your class code won't continue executing until the event has been either handled by the client or ignored. (If the client has not created an object reference using the WithEvents keyword, then it isn't handling the events raised by the class, and any events raised will be ignored by that client.) This can have undesirable side effects, and you should bear it mind when planning your application.

For more information on the custom event statements, see the entries for the Event, Friend, Private, Public, RaiseEvent, and WithEvents statements in Chapter 7.

Was this article helpful?

+1 -4

Post a comment