SAS Object-Oriented Programming Concepts |
Events alert applications when there is a change of state. Events occur when a user action takes place (such as a mouse click), when an attribute value is changed, or when a user-defined condition occurs. Events are essentially generic messages that are sent to objects from the system or from SCL applications. These messages usually direct an object to perform some action such as running a method.
Event handlers are methods that listen for these messages and respond to them. Essentially, an event handler is a method that determines which method to execute after the event occurs.
SCL supports both system events and user-defined events.
System Events |
System events include user interface events (such as mouse clicks) as well as "attribute changed" events that occur when an attribute value is updated. SCL automatically defines system events for component attributes when those attributes are declared.
SCL can also automatically send system events for you when a component's attribute is changed. If you want "attribute changed" events to be sent automatically, specify SendEvent='Y' in the options list for the attribute.
If you want an action to be performed when the system event occurs, then you need to define the event handler that you want to be executed when the event occurs. You define event handlers for system events in the same way that you define them for user-defined events. See Defining Event Handlers for more information.
Defining and Sending Events |
You can create user-defined events through the Properties window in the Class Editor or with event declaration statements in CLASS blocks.
EVENT event-name</(event-options)>; |
Event names can be up to 256 characters long.
For the event options, you can specify the name of the method that handles the event and when an object should send the event. Events can be sent automatically either before (specify Send='Before') or after (Send='After') a method executes or they can be programmed manually ('Manual') with SCL. New events default to 'After'. You must specify a method name for events that are to be sent automatically.
After an event is defined, you can use the _sendEvent method to send the event:
object._sendEvent("event-name"<, event-handler-parameters>); |
Defining Event Handlers |
You can define event handlers with event handler declaration statements in CLASS blocks.
EVENTHANDLER event-handler-name</(event-handler-options)>; |
As part of the event handler options, you can specify the name of the event, the name of the method that handles the event, and the name of the object that generates the event (the sender). As the sender, you can specify '_SELF_' or '_ALL_'. When Sender='_SELF_', the event handler listens only to events from the class itself. When Sender='_ALL_', the event handler listens to events from any other class.
Using the _addEventHandler method, you can dynamically add a sender to trigger the event. For a complete description of _addEventHandler, refer to the SAS/AF online Help.
For more information about defining event handlers, see CLASS.
Example |
This example demonstrates how to define and use events and event handlers.
This example creates two classes. The first class defines one event, three event handlers, and the three methods that those handlers call. The second class defines one event handler that listens for the event from the first class, and also defines a method to execute when that event occurs. Lastly, there is separate code that exercises the events and event handlers in the two classes. It is assumed that both classes are stored in work.a.
The first class, EHclass1, defines a numerical attribute n, the event myEvent, and the event handler for this event, M2. When this class is instantiated, the system event name "n Changed" is automatically assigned to the attribute n and is registered with EHclass1. When the value of the attribute n is changed, the system automatically sends the "n Changed" event, and method M1 is executed.
Event handlers M2 and M3 and the corresponding methods are to demonstrate the response to the _sendEvent method, explained later in this example.
The methods are not defined in sequential order to help demonstrate that the order of definition has nothing to do with the order of execution.
class EHclass1; public num n; /* An attribute with a system event. */ event 'myEvent' / (method='M2'); eventhandler M1 / (sender = '_SELF_', event = 'n Changed'); eventhandler M3 / (sender = '*', event='myEvent'); eventhandler M2 / (sender = '_SELF_', event = 'myEvent'); M1: method a:list; put "M1: Event is triggered by changing attribute n."; endmethod; M3: method; put "M3: Event is triggered by _sendEvent / sender=*."; endmethod; M2: method; put "M2: Event is triggered by _sendEvent /sender=SELF."; endmethod; endclass;
The second class, EHclass2, defines the event handler and corresponding method, M4, that is also executed when myEvent is sent.
class EHclass2; /* Sender='*' means that the sender is determined at run time. */ eventhandler M4 / (sender = '*', event='myEvent'); M4: method; put "M4: Event myEvent is defined on another class"; put " that is triggered by _sendEvent / sender=*."; endmethod; endclass;
The following code uses the two classes. The system event "n Changed" is triggered when the value of the n attribute is modified. The user-defined event myEvent is triggered with the _sendEvent method.
import work.a.EHclass1.class; import work.a.EHclass2.class; init: /* Reverse the order of these two declarations to */ /* change the order of execution for '*' sender. */ dcl EHclass1 obj1 = _new_ EHclass1(); dcl EHclass2 obj2 = _new_ EHclass2(); /* Trigger the system event. */ obj1.n = 3; /* Trigger the user-defined event. */ obj1._sendEvent("myEvent"); return;
The order in which the event handlers for myEvent are executed is determined by the sender of the message. If the sender is _SELF_, the handling class, in this case EHclass1, has priority, and executes its method first.
If the sender is *, the handlers are executed in the order in which their defining classes were instantiated; the execution order is not defined by the order of the class definitions or method definitions.
In this example, M1 is executed first when the "n changed" event occurs. Event handler M2 is triggered by events from _SELF_, so when myEvent is sent, event handler M2 is executed first, followed by the event handler M3.
M4 is executed after M3 because M3 is on EHclass1, which was instantiate first. Reverse the order of the declarations of EHclass1 and EHclass2 to change the order in which M3 and M4 are executed.
As written above, without the reversed declarations, the output is:
M1: Event is triggered by changing attribute n. M2: Event is triggered by _sendEvent / sender=SELF. M3: Event is triggered by _sendEvent / sender=*. M4: Event myEvent is defined on another class that is triggered by _sendEvent / sender=*.
Event and Event Handler Metadata |
Events and event handlers are implemented and maintained with metadata. This metadata exists as a list that is stored with the class. You can query a class (or an event within a class) to view the event and event handler metadata. To list the metadata for an event, execute code similar to the following:
init: DCL num rc; DCL list metadata; DCL object obj; obj=loadclass('class-name'); rc=obj._getEvent('event-name', metadata); call putlist(metadata, '', 3); rc=obj._getEventHandler('_self_', 'event-handler-name', '_refresh', metadata); call putlist(metadata, '', 3); return;
Copyright © 2009 by SAS Institute Inc., Cary, NC, USA. All rights reserved.