So, let's try it in English this time!
First of all, sorry for the delay - I know I've promised to get this post out to you in a weeks time when I wrote the first blog post in this series "Event Handling mit LotusScript Teil I - Persistente Event-Handler" and now it's been FOUR weeks... But to make this up to you I will publish the first blog post in English as well - let's say within the next four weeks
.
But now, let's get started so I can show you how event-handlers can also profit from inheritance in LotusScript!
Once you have a class that implements custom event-handlers you should know how its instances behave in case the class is part of an inheritance hierarchy. There are a couple of things you have to consider when designing inheritance hierarchies in general and inheritance with event-handlers in particular.
Flow Control
As briefly mentioned in the first part of this series: you can in fact bind multiple event-handlers to the same event. In case of Query-Events the triggering command (Open, Save, Send, Close) will only be executed if none of the bound handlers set ‘Continue’ to False. Since ‘Continue’ is declared as a Variant (which of course is a reference type) it is shared between all methods that handle the event. So if you set ‘Continue’ to True it will be true for all handlers from there on until another handler sets it to false again. Since you can’t be (reasonably) sure in which order your bound event-handlers are executed you really shouldn’t build handlers that depend on each other or use the ‘Continue’ to communicate. Fortunately this is not how inherited event-handlers work.
Inheritance
If your class overwrites an event-handler which it inherited from some base class only the child event-handler will be triggered when the event fires. The event-handler of the base class will be ignored completely. It does not matter where you bind the handler, in the base class or the child. Both times only the child event-handler will be bound.
Let’s take a look at an example (Code 1), the following code defines a controller base class:
Public Class UIDocControllerBase
Private p_uidoc As NotesUIDocument
Public Property Get UIDoc() As NotesUIDocument
Set UIDoc = p_uidoc
End Property
Public Sub New( pUIDoc As NotesUIDocument )
Set p_uidoc = pUIDoc
End Sub
Public Sub BindEvents()
On Event PostOpen From UIDoc Call PostOpen
On Event QueryClose From UIDoc Call QueryClose
On Event QuerySave From UIDoc Call QuerySave
End Sub
Public Sub PostOpen( Source As NotesUIDocument )
Print "BASE: Post Open"
End Sub
Public Sub QueryClose( Source As NotesUIDocument, Continue As Variant )
Print "BASE: Query Close"
End Sub
Public Sub QuerySave( Source As NotesUIDocument, Continue As Variant )
Print "BASE: Query Save"
End Sub
Public Sub Delete()
Print "Delete: UIDocControllerBase"
End Sub
End Class
The class implements handlers for the PostOpen, QueryClose and QuerySave events. In addition it implements the BindEvents-Method which takes care of the event binding.
The following code (Code 2) defines a class CompanyUIDocController which inherits from the UIDocControllerBase class. It implements its own handlers for the QueryClose and PostOpen events, it does however not overwrite its parent’s QuerySave event-handler nor does it overwrite the BindEvents-Method.
Public Class CompanyUIDocController As UIDocControllerBase
Public Sub New( pUIDoc As NotesUIDocument )
End Sub
Public Sub QueryClose( Source As NotesUIDocument, Continue As Variant )
Call UIDocControllerBase..QueryClose( Source, Continue )
Print "CompanyUIDocController: QueryClose"
End Sub
Public Sub PostOpen( Source As NotesUIDocument )
Print "CompanyUIDocController: PostOpen"
End Sub
Public Sub Delete()
Print "Delete: CompanyUIDocController"
End Sub
End Class
If you now substitute the class definition from the first blog entry of this series with the two classes of Code 1 and Code 2 and then Open, Save and finally Close the corresponding document the output will be as follows:
Fig. 1: Example output
Analysis
First the BindEvents-Method is called and binds the events of the NotesUIDocument to all not overridden event-handlers. That means that the PostOpen and QueryClose events are bound to the CompanyUIDocController class while the QuerySave event is bound to the base class. When we trigger the events those and only those event-handler are being executed. The QueryClose event-handler in the base class is only executed because we are explicitly calling it inside the QueryClose event-handler of CompanyUIDocController by using the “..”-notation in the function call.
Call UIDocControllerBase..QueryClose( Source, Continue )
A call like that will always refer to the base-instance instead of the “youngest”-instance like
Call me.QueryClose( Source, Continue )
would. And before you get any ideas both of the above calls are illegal in the event binding definition!
The only two methods which automatically call their equivalents in the base instance(s) are New and Delete. If you wish to cascade any other function calls you have to do it explicitly.
In conclusion, if you want to implement some functionality which is the same for all of your derived classes that code should go in the base class event-handler. On the other hand any functionality that deals with issues specific to your current class should be located within the derived class. An example would be a base class that implements a function which forces the user to write a comment during the QuerySave event. More specific functionality like updating a parent document which is only needed on a specific form would go in the event-hander of the derived class. Just remember that you have to call the base class handler explicitly if you need the base functinality too.
If you have any more questions concerning event handling in LotusScript, please leave us a comment so we can expand this mini-series a little further.