I'm making a usercontrol in which I would like to publish an event so that I can subscribe to it from a Form that uses it. Is it possible to add a .net event to a usercontrol so that it can be seen in the event list in the OpenEdge Architect?
I don't beleive so.
Hi,
actually (102A01) it is not possible to add user defined .NET events to a UserControl or else.
A possible workaround is to use the TextChanged Event of the UserControl which is not used normaly.
You may call the OnTextChanged Method from within the UserControl with a self composed
EventArgs Instance. In those lets say MyEventArgs you can define a property to see what has happened
in the UserControl.
Inside the Form you subscribe to THIS-OBJECT:UserControl:TextChanged:SUBSCRIBE(MyEventHandler)
Which is defined METHOD PRIVATE VOID MyEventHandler(INPUT sender AS System.Object, INPUT e AS MyEventArgs).
Hope that helps.
Marko
As Marko pointed out, it's not possible to create a "new" (additional) event in an ABL class.
Most .NET Events are accompanied by an OnEventName method which is protected. The method (usually) expects an System.EventArgs or a more specialiced type as the input parameter and raises the event which calls the event handlers at all subscribers. The subscribers will receive a reference to the object itself (sender) and the passed in System.EventArgs (usually e or args) as an input parameter.
As the method is protected only the Control itself or a class inheriting from the Control can execute this. From the standpoint of encapsulation this is reasonable.
The TextChanged event of the UserControl is a good candidate for abusing one of the existing events of the UserControl. AFAIK the Text property of the UserControl has no meaning; it's just inherited from the Control class. So I don't expect any unintended occurance of the TextChanged event.
Another way would be to use a callback. You create an Interface (lets say ISomethingHasHappenedSubscriber) that the Container needs to implement, let's say containing a public method "SomethingHasHappenedHandler". The UserControl can execute this method using
CAST(THIS-OBJECT:Parent, ISomethingHasHappenedSubscriber):SomethingHasHappenedHandler (THIS-OBJECT).
You may add additional parameters as required, but using a sender (THIS-OBJECT within the usercontrol) of type System.Object or System.Windows.Forms.Control is usually not a bad starting point as it is similar to what you'd expect from a real .NET event.
If you need more than one subscriber, use a collection pattern (maybe using temp-tables) in the UserControl to maintain a list of 0 to many possible subscribers.
Thanks for the replies. I think I can work with one of these solutions...
/* This is a workaround for the lack of event or delegate implementation in 10.2A */
DEFINE PUBLIC PROPERTY Subscriber AS System.Object NO-UNDO
GET.
SET.
IF Subscriber <> ? THEN
DO:
IF TYPE-OF(Subscriber, sys.MainForm) THEN
DO:
CAST(Subscriber, sys.MainForm):MyMethod().
END.
END.
You normally don't want to pass around object as a property, so you can call methods from that object. It's not a good OO practice. For the moment the above code is another option. Notice my comment about the 10.2A; I laid out the code so I can easily change it to a Delegate or full custom event implementation which ever 10.2B might support.
I'd rather use such an implementation around an Interface type.
Interface still doesn't eliminate the need for passing in object and type checking.
That's right. But it offeres a much looser coupeling and a starting point for multiple subscribers (of different types).
I'm not too keen about that coupling as the implementation is already hackish in my opinion which still has to be refactored in the future. Also the set of subscribers, I believe, will be limited and specific.