Introduction
The VBA Composite Control Object Model encapsulates event-driven interactions between controls and objects in Visual Basic for Applications. By encapsulating complex control interactions, standard Office ActiveX controls and other objects may be used to create new "controls" with custom special effects, or enhanced functionality (like adding a RecordSource
to a TabControl
).
Background
This project was initially developed out of an interest in creating dynamic callbacks for ActiveX controls in Microsoft Access using the WithEvents
keyword.
You can find my original blogs about the project on the Microsoft Access Team Blog:
You can also visit the Codeplex site established for this project.
To date, the project has been developed entirely in Microsoft Access VBA. However, effort has been made to make the code as generic as possible to facilitate implementation in other Microsoft Office products or 3rd party applications which support VBA.
Ultimately, the code lives entirely within VBA. That is, a chief project requirement is that all functionality be maintained entirely in VBA code. No add-ins, DLLs, or other external 3rd party solutions allowed. This includes avoiding adding project references and limited use of the WinAPI. The chief reason behind this decision was to make the object model suitable for implementation in environments with restrictive IT policies toward macros.
Using the Code
Since the project is more about developing an object model than it is about creating widgets, it's a bit difficult to cite code examples in a meaningful way. The Codeplex tutorials provide some in-depth examples of developing composite controls and event handlers.
Briefly, the object model consists of the following elements:
Interfaces
Interfaces make it possible to cast a variety of Composite Control classes to a generic type, exposing core members and eliminating the need to rely on late-bound VBA data types (Object
and Variant
) and slow VBA calling functions (CallByName()
, Application.Run()
, etc.). Employing interfaces to facilitate early binding can realize performance increases on an order of magnitude over late-bound techniques.
Interfaces implemented in the object model include:
iControl_Base
- Defines basic properties (Name
, ID
, and ControlType
) common to all Composite Control classes. iControl
- Defines members specific to cControl
and cControl_EventHandler
classes. iControl_EventHandler
- Defines members specific to the cControl_EventHandler
class. iCallback
- Defines members specific to the cCallback
class.
Classes
The object model lives in its classes. The class hierarchy is characterized by a shallow structure, lending itself to simpler memory management and reduced code modules. Further, the object model is designed to be modular with a core extended only with the classes required by a given project.
Classes core to the object model include:
cCompositeControl
- Top-level management class. cCompositeControlManager
- Instanced in the cCompositeControls
object, this class creates / initializes cControl
and cControl_EventHandler
objects. cControl
- Workhorse of the object model. This class encapsulates the event-driven interactions between objects of any variety, whether they are ActiveX controls, Composite Controls or something else! cControl_EventHandler
- A special case of the cControl
class. The cControl_EventHandler
class acts as a delegator for declared events. cControlChild_Event
- A child class to the cControl_EventHandler
class. This class provides the actual delegation, executing callbacks registered with the class instance when it's associated event is triggered. cCallback
- Class which provides callback functions which may be registered with a cControlChild_Event
class delegator.
Support Modules
The support modules serve as a repository for functions called across the classes, or functions specific to a class that do not need to be contained within the class. Using support modules provides a way to reduce the amount of code in a class thus reducing memory demands and overall loading time. Support modules are specific to the individual classes to encourage modularity, with only two modules serving as general-purpose repositories for functions, enumerations, data types, and constants.
Also contained in the support modules are the creation functions. Simply, a creation function is a publicly available function that is specific to the type of Composite Control it creates. The implementation of this type of function encapsulates the code needed to create / initialize / configure a composite control in a single line of code at the Form
level.
Points of Interest
Some key ideas that come from OOP were implemented to make the object model work. First is the concept of delegation. It works and works well. Second was the implementation of interfaces to allow for "casting" of the classes. This ability to cast a class to a more generic interface type is what allows the object model to maintain its ability to interact with almost any type of object while circumventing slower late-binding techniques typically required to interface with unknown object types.
History
Improvements from the alpha release include prolific implementation of interfaces, reduction / reorganization of code modules, and a more robust implementation of the Object Monitor development tool. Also notable is the absence of the cControl_Binder
class in the Beta release, pending the development of a more robust implementation, the cDataSource
class.