Responding to Events and the With Events Keyword

Now that you know how to create custom events in your object, you might want to know how to listen and respond to them in your code. It's actually quite simple. All you need to do is declare the object variable using the WithEvents keyword. Unfortunately however, you can only use WithEvents for object variables declared at module level and only in class modules.

Remember that the code behind forms are class modules too, so you can also use the WithEvents keyword in forms. The following declaration example demonstrates how easy it is:

Private WithEvents myKennel As clsKennel

Once you declare an object variable using the WithEvents keyword, select the object from the Object drop-down list, and the event becomes available from the Procedure drop-down list, as shown in Figure 12-10. VBA creates the procedure stub based on the arguments you supplied when you defined the event.

The only thing that might be considered a drawback to class events is that the object that raises the event must wait until the event code is responded to before it can continue processing.

Now let's see how we might be able to use the WithEvents keyword in a way that makes practical sense in your day-to-day application development. Let's say you have several text boxes on several different forms whose BeforeUpdate and AfterUpdate events contain exactly the same code. Normally, you would simply write the same code over and over in the event procedures for each control. But what if you were able to write the code once and have every control implement that code.

You're probably wondering, why not just write a public procedure in a standard module? That might work in many cases, but some built-in events have parameters, like the BeforeUpdate event's Cancel parameter. Access won't let you replicate that in a standard module.

We'll start by creating our class module, which we'll call clsTBox.

'Declare the class instance

Public WithEvents myTextbox As Textbox

Private Sub myTextbox_AfterUpdate() 'Set the text to normal weight. Me.myTextbox.FontBold = False End Sub iviui^Withfcveijirt? ray^ n.rie'.L r clsKenne .1

BeforePurchase

Private Sul: rayKsnne,l_BeforePurchaae [Cancel As Integer)

End Sul:

Figure 12-10

Public Sub myTextbox_BeforeUpdate(Cancel As Integer) 'Test for the text box's value. Select Case Me.myTextbox.Value Case "Fred", "Mary" 'The vaue is OK. 'Change the text to black. Me.myTextbox.ForeColor = vbGreen Case Else

'Wront value! Undo the changes, 'and change the text to bold red. Cancel = True

Me.myTextbox.ForeColor = vbRed Me.myTextbox.FontBold = True End Select End Sub

As you can see, this code implements the BeforeUpdate and AfterUpdate events for text boxes that can be anywhere in the project. The BeforeUpdate event checks the value of the text box and turns its text green if it equals "Fred" or "Mary", otherwise it turns it bold red. The AfterUpdate event only fires (setting the text weight to normal) if the text is correct.

Now let's create the form, shown in Figure 12-11.

Figure 12-11

Add two text boxes named txtFirst and txtLast (it doesn't really matter what their captions read), and then add the following code to the form's module:

'Declare a reference to the class module Public FirstTB As New clsTBox Public LastTB As New clsTBox

Public Sub Form_Load()

'Instantiate the class object for each control Set FirstTB.myTextbox = Me.txtFirst Set LastTB.myTextbox = Me.txtLast End Sub

Private Sub Form_Unload(Cancel As Integer) 'Clean up

Set FirstTB = Nothing Set LastTB = Nothing End Sub

Private Sub txtFirst_AfterUpdate()

'This event exists solely to allow subclassing End Sub

Private Sub txtFirst_BeforeUpdate(Cancel As Integer)

'This event exists solely to allow subclassing End Sub

Private Sub txtLast_AfterUpdate()

'This event exists solely to allow subclassing End Sub

Private Sub txtLast_BeforeUpdate(Cancel As Integer) 'This event exists solely to allow subclassing End Sub

You'll notice that the BeforeUpdate and AfterUpdate events exist, but contain no code. This is because they must exist in the form's class module for them to exist in our clsTBox class. All they need is the stub, but I always put a comment inside them to assist other programmers to understand what's going on.

The only other thing to mention here is that we have declared FirstTB and LastTB as Public. This is done so that clsTBox can see them.

Open the form and type "Fred" into the first text box. It turns green. Now enter "John" into the second text box, as shown in Figure 12-12.

Figure 12-12

How It Works

1. A two-way "link" has been set up by declaring module-level object variables in both the form and clsTBox. In this way, when each is instantiated, they can "see" the other.

2. When the form class module is instantiated, clsTBox is immediately instantiated into FirstTB and LastTB (note that we used early binding). When the form loads, the two text box instances are created in clsTBox through the FirstTB.myTextBox object chain.

3. Once that happens, the linking is complete, and all the text box events that are exposed in the form are now available in clsTBox.

4. When the BeforeUpdate or AfterUpdate events occur for either text box, they actually fire in the instance of clsTBox created for it.

5. Try placing breakpoints in the form's Load event, and clsTBox's BeforeUpdate and AfterUpdate events to see what happens.

This is just a small example of how to subclass form controls using the WithEvents keyword. You can do the same thing with other controls and events, and also with forms and reports.

Was this article helpful?

0 0

Post a comment