Defines an ABL class event, declares a class event prototype in an ABL interface, or overrides an abstract class event inherited from an ABL or .NET abstract super class. A class event is a member of the class in which it is defined. You can publish a non-abstract event from within the defining class definition using the built-in Publish( ) event method in response to a condition that you determine. You can subscribe a class method or internal procedure as a handler for any accessible event (abstract or non-abstract) using the built-in Subscribe( ) event method. This handler executes whenever the event is published. You can also unsubscribe any handler using the built-in Unsubscribe( ) event method. The following description begins with general syntax for defining a class event.
DEFINE [ PRIVATE|PROTECTED|PUBLIC ][ STATIC | ABSTRACT ][ OVERRIDE ] EVENT event-name signature-spec |
Use the following syntax to declare a class event prototype in an interface:
Use the following syntax to declare an abstract class event prototype:
Specifies the access mode for this event. For a class event, the access mode indicates what code can call the Subscribe( ) event method on the event.
A PRIVATE event can have a handler subscribed to it only by the defining class. An instance can subscribe a handler to a private event of another instance if both instances are of the same class. A PROTECTED event can have a handler subscribed to it by the defining class and any of its derived classes. An instance can subscribe a handler to a protected event of a second instance that is at the same level or higher in the class hierarchy.
A PUBLIC event can have a handler subscribed to it by:
Any piece of code can subscribe a handler to a PUBLIC static event. The default access mode is PUBLIC.
When declaring an interface event prototype, the access mode for the event must be PUBLIC (the default).
When defining an abstract event, the access mode for the event cannot be PRIVATE.
If this event is defined with the OVERRIDE option, the access mode cannot be more restrictive than the access mode defined for the overridden abstract ABL or .NET class event. ABL access modes correspond to the access levels of inherited .NET abstract events (in C#) as follows:
Defines an event that is a static member of the class type for which it is defined and that is scoped to the ABL session where it is referenced. ABL creates one copy of the specified class static event on first reference to the class type, and ABL creates only one such copy for any number of instances of the class that you create. You can subscribe a handler for an accessible static event in any piece of code. You can publish a static event only in an instance or static method that is defined within the same class definition where the static event is defined.
Without this option, ABL defines an instance event that is scoped to a single instance of the class where it is defined. ABL creates one copy of the specified instance event for each such class instance that you create. You can subscribe a handler for any public instance event (abstract or non-abstract) in any procedure, or in any instance or static method defined inside or outside of the class where the instance event is defined. Any static method can publish the public instance event only using an object reference to a class instance that defines the event as a member. If the referencing static method is defined in the same class as the public instance event, the class must instantiate itself in order to have access to an instance reference.
You can publish a non-abstract instance event only in a method that is defined within the same class definition where the instance event is defined. If the method is static, the instance event must also be public and you can only publish it using an object reference to an instance of the class. An instance method defined in the same class can also publish a public instance event using an object reference to an instance of the class.
For more information on the mechanism for subscribing handlers to static and instance class events, see the Subscribe( ) event method reference entry. Note that the same constraints on subscribing handlers for static and instance class events applies to unsubscribing the handlers. For more information, see the Unsubscribe( ) event method. For more information on the mechanism for publishing instance and static class events, see the Publish( ) event method reference entry.
The STATIC option is not valid when you:
Defines the event as an abstract instance member of the class type for which it is defined. The defining class type must also be abstract. If you define an abstract event, it has the following requirements:
You must specify the OVERRIDE option if an inherited abstract event has the same name and signature.
Any class definition for an instance event that includes the OVERRIDE option and does not include the ABSTRACT option defines an event implementation. If it also includes the ABSTRACT option, the inherited abstract event remains abstract.
This option is not valid either when you define a static event or when you declare an interface event prototype.
Specifies that this instance event overrides an abstract event inherited from an ABL or .NET class.
When you specify OVERRIDE, event-name must be identical to the name of the overridden abstract event, and signature-spec must specify a signature that is identical to the signature defined for the overridden event. In addition, the access mode must not be more restrictive than the access mode defined for the overridden event. When overriding a .NET event, the signature-spec must specify the same delegate that is defined for the .NET event. For more information, see the description of the signature-spec option.
If you specify the ABSTRACT option, your overriding event is also defined as abstract, and it must be implemented in a class derived from the defining class. Note that you do not have to override an inherited abstract event that you want to remain abstract as long as the inheriting class is also abstract. However, doing so allows you to specify a less restrictive access mode for the abstract event.
If you do not specify the ABSTRACT option, your overriding event implements the inherited abstract event.
This option is not valid:
Specifies the event name. This event name must be unique among all events, properties, and variable data members defined in the class hierarchy of the defining class, unless you specify the OVERRIDE option to override an inherited abstract event.
Specifies the signature for the Publish( ) event method and for any class method or internal procedure that executes as a handler when the event is published. You can define this signature using one of the two options in the following syntax:
Defines an ABL method signature for the event, including the return value and zero or more parameters. The return value is always VOID. No associated internal procedure or method event handler can return a value. The SIGNATURE keyword is optional for readability.
If this event implements an ABL interface event or overrides an inherited ABL abstract event (using the OVERRIDE option), the interface or inherited abstract event must also be defined with an ABL method signature that matches this signature. If the ABL interface or inherited ABL abstract event is defined with a .NET signature (dotNet-delegate-type), you must use the .NET signature option to define this event instead.
For more information on the syntax of parameter and on matching parameters to implement or override ABL class events, see the Parameter definition syntax reference entry.
Defines a .NET signature for the event as specified by a .NET delegate type (dotNet-delegate-type), for example, System.EventHandler. You can specify the delegate class name without a namespace (for example, EventHandler) with the presence of an appropriate USING statement. The DELEGATE or CLASS keyword is optional for readability. However the CLASS keyword, only, also disambiguates a delegate type name that might be identical to an ABL primitive type name. Note that ABL only supports .NET delegate types that conform to the .NET Framework convention for event handlers. This convention defines an event handler signature with a VOID return type and two input parameters, where the first parameter is a System.Object and the second parameter is a System.EventArgs or a .NET class derived from System.EventArgs. The .NET delegate type can also be a constructed generic type. For more information on .NET generic types, see the Data types reference entry.
You must use this option to define the ABL class event signature if the ABL event implements a .NET interface event or overrides an inherited .NET abstract event (using the OVERRIDE option). Also, the dotNet-delegate-type for the ABL event must be identical to the .NET delegate type used to define the .NET interface or abstract event.
You can use this option to define the signature for an ABL class event even if the event does not implement or override a .NET event. However, if this event implements an ABL interface event or overrides (using the OVERRIDE option) an inherited ABL abstract event that is, itself, defined with a .NET delegate, you must also define the signature for this event using an identical dotNet-delegate-type.
Note that you can identify the data types of .NET event parameters by looking up the delegate type defined for the event in the appropriate .NET event documentation.
The following sample class and procedure files define, publish, subscribe an event handler to, and unsubscribe an event handler from an ABL class event. The r-EventPublish sample class defines the public NewCustomer event and a PubNewCustomer( ) method to publish it.
r-EventPublish.cls
CLASS r-EventPublish: /* Define an event */ DEFINE PUBLIC EVENT NewCustomer SIGNATURE VOID ( INPUT pcCustName AS CHARACTER ). /* Code that publishes the event. */ METHOD PUBLIC VOID PubNewCustomer( ): DEFINE VARIABLE cCustName AS CHARACTER INITIAL "A Customer Name" NO-UNDO. NewCustomer:Publish( INPUT cCustName ) NO-ERROR. END METHOD. END CLASS. |
The r-EventSubscribe sample class defines and subscribes a NewCustomer( ) method as a handler for the event when it is instantiated, based on the object reference to the r-EventPublish class that is passed to the constructor. Note that the event handler also unsubscribes itself to the event after it executes.
r-EventSubscribe.cls
CLASS r-EventSubscribe: DEFINE VARIABLE rPubObj AS CLASS r-EventPublish NO-UNDO. CONSTRUCTOR PUBLIC r-EventSubscribe ( INPUT prPubObj AS CLASS r-EventPublish): ASSIGN rPubObj = prPubObj. rPubObj:NewCustomer:Subscribe( NewCustomer_Handler ) NO-ERROR. END CONSTRUCTOR. /* Method used as event handler */ METHOD PUBLIC VOID NewCustomer_Handler ( INPUT pcCustName AS CHARACTER ): MESSAGE "Subscriber received event NewCustomer" SKIP "CustName =" pcCustName VIEW-AS ALERT-BOX. rPubObj:NewCustomer:Unsubscribe( NewCustomer_Handler ) NO-ERROR. END METHOD. END CLASS. |
The r-EventPubSub.p sample procedure instantiates these classes. The procedure then displays a frame that includes a bNewCust button that when clicked runs an internal procedure, which in turn invokes the PubNewCustomer( ) method on the r-EventPublish object to publish the event. This demonstrates how the class defining an event can allow a client class or procedure to publish it by providing a public method for the purpose. Note that any subsequent attempt to click the button does not run the event handler, because the handler has unsubscribed itself.
r-EventPubSub.p
DEFINE VARIABLE rPubObj AS CLASS r-EventPublish NO-UNDO. DEFINE VARIABLE rSubObj AS CLASS r-EventSubScribe NO-UNDO. DEFINE BUTTONbNewCust LABEL "New Customer". DEFINE BUTTON bQuit LABEL "Quit". FORM bNewCust bQuit WITH FRAME aFrame. ON CHOOSE OF bNewCust RUN CallNewCust NO-ERROR. rPubObj = NEW r-EventPublish( ). rSubObj = NEW r-EventSubScribe( rPubObj ). ENABLE ALL WITH FRAME aFrame. WAIT-FOR CHOOSE OF bQuit OR WINDOW-CLOSE OF CURRENT-WINDOW. PROCEDURE CallNewCust: /* Call to publish */ rPubObj:PubNewCustomer( ) NO-ERROR. END PROCEDURE. |
For more examples of class event definitions, including static and abstract events, see the descriptions of r-CustObj.cls, r-CustObjStatic.cls, and r-CustObjAbstract.cls in the CLASS statement reference entry.