4.3. Class Module Events

Unlike normal code modules, class modules support two events that are automatically defined when you add a class module to your project. These two standard events, the Initialize and Terminate events, are analogous to the class constructor and destructor in an object-oriented programming language like C++; they are fired automatically when a class is instantiated and destroyed, respectively.

An event handler is the code attached to a particular event. When the event is fired, the event handler is executed automatically. Like all event handlers, writing code to handle the Initialize and Terminate events is optional, but it's at the heart of sound VB programming. So let's look at some of the uses you can put these event handlers to and some of the rules relating to these two events.

4.3.1. The Initialize Event

Let's begin by examining precisely when the Initialize event is fired, then look at some possible applications for the Initialize event handler.

4.3.1.1. When is the Initialize event fired?

The firing of the Initialize event depends on how the class object is instantiated. If you use the combined method of declaring a New instance of an object:

Dim oVar As New svrObject

the Initialize event is fired when the first reference is made to a member of the class, and not when the class is declared as New. For example:

Dim oVar As New svrObject ' Initialize event not called
oVar.AnyProp = sAnyVal    ' Initialize event fired _
                       immediately prior to the Property Let

However, if you use the Set statement to instantiate an object, the Initialize event is fired when the Set statement is executed. For example:

Dim oVar As svrObject
Set oVar = New svrObject  ' Initialize event fired here

4.3.1.2. Using the Initialize event

The Initialize event can be used for any of the following:

  • To create new collection objects that are used within the class. For example:

    Set mcolx = New Collection

  • To include conditional debugging code to determine when the class has been initialized. For example:

    #If ccDebug Then
       Debug.Print "xyz Class Initialized"
    #End If

  • To create and instantiate dependent objects. For example:

    Set moDepObj = New clsDependant

4.3.2. The Terminate Event

As with the Initialize event, the precise time the Terminate event is fired has created some confusion. Once again, we'll examine when the Terminate event is fired before looking at some applications of the Terminate event handler.

4.3.2.1. When is the Terminate event fired?

The simple answer is that the Terminate event is fired when all references to the object are set to Nothing. However, life's never that simple. You may assume that because you have placed a Set objVar = Nothing statement in your program that the objVar's Terminate event will be fired, and in the vast majority of cases it will be. However, having a live reference to another object in the objVar class prevents objVar from terminating. This occurs, for example, if your class contains a collection that contains a reference to another object, and you fail to destroy the collection. Similarly, if your class contains a dependent object whose reference was not released, your class may not terminate cleanly.

To prevent this from happening, use debugging code within both the Initialize and Terminate event handlers to ensure that all objects are destroyed cleanly when you think they should be destroyed. In addition, get into the habit of using the following template when handling object variables:

Dim objectVariable As Class
Set objectVariable = New Class
    'indent code then it's easy to see the start and 
    'end of an object reference
Set objectVariable = Nothing

I actually go as far as writing my Set objectVariable = Nothing statement before I write the code between the two Set statements. This makes me approach the two Set statements as if they formed a code block, like an If...Then...End If block.

4.3.2.2. Using the Terminate event

The Terminate event can be used to provide "clean up" code for your class:

  • To destroy collection objects used within the class being terminated. For example:

    Set mcolx = Nothing

  • To include conditional debugging code to determine when the Terminate event has fired. For example:

    #If ccDebug Then
       Debug.Print "xyz Class Terminated"
    #End If

  • To destroy dependent objects of the class being terminated. For example:

    Set moDepObj = Nothing

4.3.3. 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.

4.3.3.1. 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.

4.3.3.2. 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 Section 4.3.3.3

  • 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.

4.3.3.3. 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 WithEvents 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 drop-down 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
   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
    Else
        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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.64.126