Blogs

  • Browse Blogs
  • My Blog
  • My Updates

Tags Help

  • View as cloud  | list

Similar Entries

photo

Summary of New Lotus...

Blog:  Beyond The Ye...
Peter Presnell
Updated 
No RatingsRatings 0     CommentsComments 6
photo

Relearning LotusScri...

Blog:  Beyond The Ye...
Peter Presnell
Updated 
No RatingsRatings 0     CommentsComments 2
photo

Importing PDF Files ...

Blog:  Beyond The Ye...
Peter Presnell
Updated 
No RatingsRatings 0     No CommentsComments 0
photo

Call to NotesEmbedde...

Blog:  Patrick Picar...
Patrick Picard
Updated 
No RatingsRatings 0     CommentsComments 1
photo

8.5.1 changed my way...

Blog:  Urs Meli
Urs Meli
Updated 
No RatingsRatings 0     CommentsComments 5

Bookmarks

Yellow is the New Blog

Blog Authors:  Tim Tripcony  

Previous |  Main  | Next

Workaround for LotusScript event binding

Tim Tripcony  |     |  Tags:  lotusscript  |  Comments (0)
As a followup to last night's post, after receiving some helpful advice from both Peter Presnell and the Batman to my Robin, I found a workaround. I think it's crazy sexy cool.

To very briefly recap, here's the problem:
  • Under normal class inheritance circumstances, calling a class method will execute the code at the youngest level (i.e. child class vs. parent) where a method definition can be found.
  • When a class method binds an event to another method in the same class, it's binding the definition of that method within the same class. So if a class inherits from another that is binding events and does not override the method doing the binding, the event will be bound to the parent's copy of the target method, even if the child class overrides the bound method.
And here's the workaround:

Within the previously abstract definition of the event handler, we issue a call to itself, but with two subtle additions:
  1. We use the Me keyword to identify the method. Designer Help implies that this forces the method call to refer to a current class member, but that's not entirely accurate: it actually forces a reference to a current object member. In other words, even though the method being bound to the event is in a parent class, when it's executed it still knows it's inside the scope of an object typed to a child class, so calling Me.whatever executes the same method as defined in that object's class, not its parent class.
  2. We do a stack trace check to make sure that we don't cause infinite recursion. You see, if the bound method isn't overridden in the child class, Me.whatever only exists in the parent class, so it would keep calling itself over and over... stack overflow, Notes go boom.
For example:

Private Sub Inviewedit(Source As Notesuiview, Requesttype As Integer, Colprogname As Variant, Columnvalue As Variant, Continue As Variant)
    If Not(Me.isRecursive(Fulltrim(Split(Lsi_info(14), Chr(10))))) Then
        Call Me.inviewEdit(Source, Requesttype, Colprogname, Columnvalue, Continue)
    End If
End Sub


The isRecursive method is actually defined at the very top level:

Private Function isRecursive (stackTrace As Variant) As Boolean
    Dim stackCount As Integer        
    
    Let stackCount = Ubound(stackTrace)
    If (stackCount > 0) Then
        Let Me.isRecursive = (stackTrace(stackCount) = stackTrace(stackCount - 1))
    End If
End Function


The end result is a framework in which you can create a derived class that overrides only the events you wish to bind, then attaches to those events, either from within the class itself or via calls to its inherited attachEvent method:

Public Class ExampleDocumentBinder As DocumentEventBinder
    
    Public Sub New (Source As NotesUIDocument)
        Call Me.attachEvent("Querysave", Source)
    End Sub
    
    Private Sub Querysave(Source As Notesuidocument, Continue As Variant)
        Dim newEdit As String
        Dim editType As String
        
        If (Source.IsNewDoc) Then
            Let editType = "created"
        Else
            Let editType = "modified"
        End If
        Let newEdit = Cstr(Now) & " - Document " & editType & " by " & Me.getSession().commonUserName
        Call Source.Document.ReplaceItemValue("AuditTrail", Fulltrim(Split(newEdit & Chr(13) &_
        Join(Source.Document.GetItemValue("AuditTrail"), Chr(13)), Chr(13))))
    End Sub
    
End Class


When calling attachEvent, you can pass a single event name, a comma-delimited list of events, or an Array of event names. The second parameter is the object whose event you're binding; if you pass Nothing, it will use the object initially passed to the constructor. The entire framework (along with a few examples) is available for download.

By the way, you might have noticed that this workaround uses the infamous Lsi_info. This undocumented function is almost universally considered unsafe, but is generally acceptable to use in an unthreaded context... so you wouldn't want to use this technique in web agents that could be running simultaneously. But as you've no doubt also noticed, event binding is entirely specific to Notes UI contexts (with the exception of NotesXMLProcessor descendants... and I think we'll leave tackling SAX parser event binding for another day), so I'm not too nervous about using Lsi_info for this niche purpose. About an hour ago, Nathan mentioned he's been playing with CodeLock as a way to make this even safer, so you might be seeing further revision to this model post haste (On Event PostHaste From... tee hee, just kidding).

Comments

Previous |  Main  | Next
Skip to main content link. Accesskey S
IBM Lotus Connections Help Tools About

Tags

A tag is a keyword that is used to categorize an entry. To view the entries with a particular tag, click a tag name or enter a tag in the box.
The tag cloud indicates the frequency of tag use. Popular tags appear darkest. The slider control adjusts how many tags are displayed in the tag cloud.