Class events
In ABL, class events are always defined as part of a class-based object definition, which can include one of the following object types:
ABL class events and .NET class events (also called .NET events) are very similar in concept, and OpenEdge allows you to manage both of them using the same ABL mechanism. Each class or interface can define any number of class events. Thus, class events are members of the class or interface for which they are defined, like methods, properties, and data members. Like any class member, a class event can be defined as either an instance or a static event, and an instance event can also be defined as abstract. A class event also has an access mode (private, protected, or public), which determines the application scope that can respond to the event.
A class event has a signature, similar to a method, that can define parameters for passing data in response to event notification. An ABL application receives notice of a class event when the object that defines the event publishes it. In an ABL application, you can subscribe one or more ABL class methods or internal procedures as event handlers, which execute when a given event is published. These event handlers must all be defined with a signature that is compatible with the event that they are subscribed to handle.
Class events provide similar features for class-based objects that named events provide for procedure-based objects, but using different mechanisms. You publish a named event using the PUBLISH statement and manage named event handler subscriptions using the SUBSCRIBE statement and UNSUBSCRIBE statement. However, you publish a class event using the Publish( ) event method and manage class event handler subscriptions using the Subscribe( ) event method and Unsubscribe( ) event method. Among the differences between the two types of events, a named event is defined when it is published and without a strongly-typed signature, while a class event must be defined before it is published and with a strongly-typed signature.
Defining class events
In ABL, you can define class events in a user-defined class or interface definition using the DEFINE EVENT statement. This statement defines all of the event options described in this section, including the signature for its event handlers.
In .NET, Common Language Specification (CLS)-compliant languages, such as C# or Visual Basic, have their own syntax to define events in a .NET class or interface. Similar to any other .NET class member, when you look up information about a .NET event in the .NET class library documentation, it typically describes the event member using syntax from one or more of these .NET languages. For example, C# provides the
event
keyword to declare an event in a class definition. In this way, the language-specific syntax for .NET events defines event options that are similar to the ABL DEFINE EVENT statement.For ABL class events, you define the strongly-typed handler signature in the DEFINE EVENT statement. For .NET events, the handler signature is specified using a .NET class type known as a delegate that is referenced in the event definition. Thus, using the same delegate type, .NET objects can conveniently define multiple events whose handlers use the same signature. For an ABL class event, you can define either an ABL method signature or you can reference a .NET delegate type to define a .NET signature for the event. Referencing a .NET delegate also allows you to implement a .NET interface event or an inherited .NET abstract event in an ABL class.
You can define any valid ABL method signature for an ABL class event. However, the mechanics of event handler execution might limit your choices in practice. Also, ABL requires any .NET delegate that you use to conform to .NET conventions for event handlers.
Defining event handlers
To use class events in your application, you must create one or more event handlers. A class event handler can be any class method or internal procedure whose signature is compatible with the signature defined for a given ABL or .NET class event. However, verification of the event handler signature occurs at a different point for method event handlers (at handler subscription compile time) than for internal procedure event handlers (at event publish run time). Note that all class event signatures include a VOID return type; therefore, any event handler method must also have a VOID return type.
For ABL class events, including ABL class events that implement inherited .NET abstract events, if you raise ERROR or throw an error object, the error is raised on the statement that executes the Publish( ) event method on the event as if you had called the event handler directly. For information on errors raised in handlers for .NET events, see the "Defining handlers for .NET events" section.
Defining multiple handlers for an event
If you need to subscribe more than one event handler for an ABL class event, when you publish the event, any OUTPUT or INPUT-OUTPUT parameter you define returns the value set by the final event handler to execute. In addition, any INPUT-OUTPUT parameter you define passes the value set by one event handler as input to the next event handler to execute. A similar effect occurs if you pass a handle or object reference as an INPUT parameter and your event handlers set the value of a public data member on the handle or class-based object. The returned value of the input object data element is the value set by the final handler to execute for the event. In addition, the order of execution for multiple handlers subscribed to a single event is not guaranteed, making it difficult or impossible to know exactly how parameter values returned from the
Publish( )
method have been set. So, if you use more than one handler for a given event, you need to use caution in defining and using the parameters for that event.Also, if you raise ERROR or throw an error object from any one of the handlers for the ABL class event, any event handler that has not already run when the error is raised does not run. Therefore, if you want all handlers to run for an event, regardless of error conditions, you must resolve all conditions within each handler and allow the handler to return successfully.
Defining handlers for .NET events
If you use a .NET delegate to define an ABL class event, or if you are defining an ABL method or internal procedure as a handler for a .NET event, you must define your event handler signature to match the delegate specified for the event. (In .NET, you implement event handlers by defining derivations of the specified delegate type.) For both ABL class events and .NET events, ABL only supports delegates whose signatures conform to the Microsoft .NET convention for event handler signatures. This signature convention provides for a VOID return type and two INPUT parameters, where the first parameter is a reference to a .NET
System.Object
that published the event, and the second parameter is a reference to a .NETSystem.EventArgs
(or a derived class) that provides event arguments as public members of the class.The signature for any ABL event handler defined for a .NET delegate must conform to this general syntax:
EventHandlerName
sender
args
Object reference to an event arguments class that contains public properties that provide arguments for the event. Note that for a .NET event,args
references an object that is created by .NET and added to the ABL session object chain when the event handler executes. Like any other locally scoped object reference, if you do not save the value before the event handler terminates, ABL automatically garbage collects this object at some point after the event handler returns.EventArgsClass
To identify the exact handler signature for a given .NET delegate, you must look up the delegate in the appropriate class library documentation or use the Class Browser of OpenEdge Architect to inspect the class. For .NET events supported on the built-in .NET classes provided by OpenEdge and described in the "Class and Interface Reference" section, each event reference entry described further on in this section indicates the delegate type associated with the event along with its matching event handler signature. Otherwise, to locate the delegate in .NET class library documentation, find the event you want to handle in the documentation for the class that publishes the event. The event definition includes a reference to its delegate type. The documentation for the specified delegate shows the .NET signature you must use for your event handler.
If you do not trap and handle an error raised within a handler for a .NET event, whether it is raised as the ERROR condition or thrown as an error object, the AVM does not throw an
Exception
back to .NET, but displays an error message on the default output device and continues processing as if no error had occurred. So, unlike handlers for ABL class events, if you subscribe multiple handlers for a .NET event, all the handlers execute regardless if one or more of them raises an error.Using class events
For any ABL class event, used by itself or to implement an interface or inherited abstract event, you must follow these general steps:
- Define the event using the DEFINE EVENT statement.
- Subscribe one or more handlers to the event using the Subscribe( ) event method. You can subscribe handlers to an event anywhere the event is accessible in an application.
- Publish the event for a given condition using the Publish( ) event method, which runs all subscribed event handlers for the event. You can publish the event only from within the class definition that implements a non-abstract definition for the event.
- Process any values returned from the Publish( ) method parameters.
At any point after subscribing event handlers, you can optionally unsubscribe any event handlers you no longer need using the Unsubscribe( ) event method. Thus, like named events for procedures, class events allow you to dynamically define and undefine alternate routines that execute in response to the event.
Note that similar to ABL class events, only the class that implements a non-abstract definition for a .NET event can publish it. This includes any ABL class that derives from and implements a .NET abstract class defining abstract events or that implements a .NET interface defining event prototypes.
However by convention, a .NET class that defines an event also typically defines a corresponding protected
On
EventName
( ) method that allows a derived class to publish the event, whereEventName
specifies the name of the .NET event and the signature defines aSystem.EventArgs
(or derivation) as input. If theOn
EventName
( ) method is overrideable (virtual
in C#), you can also override this method in an ABL derived class. If you do override this method, you must also invoke the super class implementation ofOn
EventName
( ) from within the overriding method (using the SUPER system reference) in order to ensure that all subscribed .NET delegates also respond to the event. For more information on overriding .NET methods, see the METHOD statement reference entry.To allow .NET events from .NET form and control objects to be published as part of the OpenEdge GUI for .NET, you must block to display the .NET forms and allow your subscribed event handlers to execute in response to any published events. To enable this .NET event handling, ABL provides WAIT-FOR statement syntax that blocks for both GUI for .NET events and ABL handle-based object events. For more information, see the WAIT-FOR statement (.NET and ABL) reference entry.
Otherwise, you can work with .NET events in exactly the same way as ABL class events.
Events and event methods reference
The following reference entries document both the events of built-in ABL classes and the built-in event methods for working with all class events. The ABL built-in classes also include a set of .NET objects defined by OpenEdge. For more information on all ABL built-in classes, see the "Class and Interface Reference" section. For information on class events defined for all other .NET objects, including the OpenEdge Ultra Controls for .NET, see the Microsoft, Infragistics®, or other third-party documentation provided for a given .NET object.
The reference entries for events that follow appear in alphabetical order by event name. Each reference entry includes the syntax required to define the signature for the event handler as a class-based method, with
EventHandlerName
used to indicate a name that you specify for the event handler. If you define the event handler as an internal procedure, define the same number of parameters in order by parameter mode and data type. If the event is a .NET event, the entry description also lists the name of the .NET delegate type defined for the event.
OpenEdge Release 10.2B
|