Binding to Multiple Events
It is often desirable to bind one event handler to multiple events. This is easiest explained through an example: In many Visual FoxPro forms, developers us a Validate() method to verify data entered in the form. This method then may be triggered before the data gets saved, or when a certain button is clicked, or perhaps when the data is actually changed. Either way, the Validate() method is called manually. With dynamic event binding however, that method could be called whenever any of the data changes by binding to the Valid events on the controls of the forms. The following code illustrates how to accomplish that task:
FOR EACH loControl IN THIS.Controls
This simply iterates over all the controls on the form the Init()
method belongs to, checks if the control has a Valid
event, and if so, binds the custom Validate()
event handler method to that event. This results in the Validate()
method handling all Valid
events that may occur on any control. Note that this doesn't influence any other event handler (such as the standard Valid()
method on each control).
Note that some controls behave slightly differently than others when we manually bind to events such as When()
. Textboxes, for instance, require that there is code in the actual Valid()
method before the manually bound code will fire. This is an inconvenience, but it has to do with some of FoxPro's internal architecture. You can find more information about these special cases in the Visual FoxPro documentation.
The ability to bind a single event handler to multiple event sources is very convenient in a number of scenarios. For instance, this technique can be used to add debug or logging code to a project. The code in Listing 1
shows a form class that has the ability to log every button click that happens on the form. (I am showing this in full source code in this example, but of course this works very similarly in visual classes.)
The code should be pretty self-explanatory, perhaps with the exception of the call to AEVENTS().
Used as shown in this example, AEVENTS()
will return a reference to the object that fired the event. This is important in many scenarios where an event handler can dynamically be bound to different objects, yet a reference to the object is required (such as querying the object name in our example).
|Note that some controls behave slightly differently than others when we manually bind to events such as When() and Valid().|
Hooks are a popular mechanism to create extensible software. Microsoft uses this mechanism quite a lot in Visual FoxPro itself. A good example for this is the Class Browser. It exposes an "interface" that allows developers to write AddIns by using the browser's proprietary mechanism to hook its events and methods to those written by the developer. The problem with this approach (besides the proprietary nature of the mechanism) is that Microsoft has to write all those "hooks" manually. This is a lot of work, which is the main reason this type of mechanism isn't used in all the software written in VFP. In the typical everyday project, developers simply don't have the time to add this functionality. Therefore, most applications do not offer "hooks."
With dynamic event binding, however, we get this type of functionality automatically. Every application that fires events can be extended using manual event binding. This is even true for internal VFP objects, such as the VFP main screen. In older versions of Visual FoxPro, it was often not possible to use the default screen (VFP's main window) as the application window, since one had very little control over this object. For instance, you could not react programmatically when the screen was resized. Now, however, we can "hook" this event and react to it the same way we otherwise would implement in subclasses.