MS-Access / Getting Started

Trapping custom events

Just about the only place where event-driven programming with Access classes becomes tricky is when it's time to capture events (also called sinking events) in consumer code. There are a number of rules governing event consumption:

  • The class hosting events must be declared within another class module. It shouldn't be surprising that events can only be captured by code within class modules. After all, class modules are special critters and have capabilities beyond simple code modules. You've never seen a stand-alone VBA code module directly respond to events raised by controls on an Access form, so there's no reason to expect a plain code module to be able to consume events raised by the classes you add to an application.
    However, a plain code module can very well create and use objects derived from class modules. It's just that VBA code modules can't capture events raised from class modules.
    This requirement is not quite as onerous as it first appears. After all, every form and report module is a class module. That means that forms and reports are ready-built for consuming the events thrown by your class modules.
  • The object variable created from the class must be module-level and can't be declared within a procedure. There's no way to capture an event from within a procedure. Procedures know nothing about objects, and there's no provision for hooking a locally declared object variable to its events.
    When you look at the class module behind a form, it becomes obvious why object variables must be module-level before their events can be sunk by consumer code. You've seen the typical Access form module. Notice what appears in the code module's event list when an object variable has been declared with the WithEvents keyword.
    As you'd expect, selecting an event from the Product object's event list opens a new event procedure, enabling you to write code in response to the event. The Product_ InvalidSupplierID event procedure notifies the user whenever the Product class determines that the SupplierID value cannot be used by the class.
    Obviously, the code in the event procedure runs whenever the corresponding event is raised from the object's class module. The consumer doesn't have to explicitly check the value returned by the SupplierName property. Instead, the event procedure linked to the InvalidSupplierID handles the event and takes appropriate action.
    Also, because the same event can be raised from multiple places within the class module, a single event procedure may handle many different situations related to a single problem within the class module.
    Behind the scenes, Access does exactly the same thing for built-in objects such as text boxes and command buttons. As soon as you add a control to an Access form, you're able to add code to event procedures hooked into the control's events.
  • The object variable declaration must include the WithEvents keyword. The keyword WithEvents is how Access knows that it needs to monitor events raised by the class to enable you to include code to react to the events.

Passing data through events

You probably noticed that the event declaration example given earlier in this tutorial included a set of empty parentheses:

Public Event InvalidSupplierID()

What may not be obvious is that event arguments may be added within the parentheses:

Public Event ProductSold(Quantity As Integer)

The RaiseEvent statement includes a value for the event argument:

RaiseEvent ProductSold(UnitsSold)

Event declarations may include multiple arguments and can pass any valid VBA data type, including complex data such as recordsets and other objects.

The ability to pass data through event arguments is an incredibly powerful tool for developers. A class module can directly communicate with its consumers, passing whatever data and information is necessary for the consumer to benefit from the class's resources.

[Previous] [Contents] [Next]