= Events = An event is a message sent by an object to signal the occurrence of an action. The object that raises (triggers) the event is called the event sender or event source.[[BR]] The object that receives the event and responds to it is called the event receiver or Listener An event is declared with a type corresponding to a method signature ('''sig''') Objects that have an interest in the event register to '''listen''' to the event[[BR]] (more specifically provide to the event a reference to one of their methods matching the [[BR]] event signature). When the event is '''raised''' (or fires) any and all objects that registered an interest in [[BR]] the event (listeners) get their (registered) method called with the arguments provided[[BR]] when raising the event. Objects may unregister a prior interest in an event by subsequently '''ignoring''' the event[[BR]] specifying the same method reference they previously listened with. On these constructs decoupled notification and handling can be built.[[BR]] All that is required is that an objects events of interest are exposed and[[BR]] the signature of the events are known to interested parties (or a registration interface is available) . == Grammar == {{{ #!cobra # specify the signature of an event sig SIG_TYPENAME(ARGS) as TYPE # declare an event event EVENT_NAME as SIG_TYPENAME #register handler/listener method for an event listen EVENT_NAME, ref METHODNAME #unregister handler/listener for an event ignore EVENT_NAME, ref METHODNAME # raise/fire an event raise EVENT_NAME, [sender,] arg [, arg ...] }}} == Platform == == Examples == This (large) example does it all.[[BR]] Declare Event arguments, declare signature and events[[BR]] Raise events in response to something happening, define receivers/listeners that are[[BR]] interested in the event ('something happening'), bind event senders and listeners together. (FWIW its the C# example at [http://msdn.microsoft.com/en-us/library/9aackb16%28v=VS.71%29.aspx Event Sample] converted to cobra.) {{{ #!cobra namespace EventSample # Data for the alarm event. Derives from System.EventArgs. class AlarmEventArgs inherits EventArgs var __snoozePressed as bool #is private #,readonly var _nrings as int is private #,readonly cue init(snoozePressed as bool, nrings as int) base.init __snoozePressed = snoozePressed _nrings = nrings # number of rings that the alarm clock has sounded when the alarm event is generated. get numRings from _nrings # indicates whether the snooze button is pressed on the alarm when the alarm event is generated. get snoozePressed from __snoozePressed # alarmText property that contains the wake-up message. get alarmText return if(__snoozePressed, 'Wake Up!!! Snooze time is over.', 'Wake Up!') # Delegate declaration. sig AlarmEventHandler(sender as Object, e as AlarmEventArgs ) # The Alarm class that raises the alarm event. class AlarmClock var _snoozePressed = false is private var _nrings = 0i32 # int32 is private var _stop = false is private # The Stop property indicates whether the alarm should be turned off. pro stop from _stop # The SnoozePressed property indicates whether the snooze # button is pressed on the alarm when the alarm event is generated. pro snoozePressed from var # The event member that is of type AlarmEventHandler. event alarm as AlarmEventHandler # The protected OnAlarm method raises the event by invoking the delegate. # The sender is always .this, the current instance of the class. def onAlarm(e as AlarmEventArgs) is protected # Invokes the delegate. raise .alarm, e # Alarm clock does not have a user interface. # To simulate the alarm mechanism it has a loop that raises the alarm event at every iteration # with a time delay of 300 milliseconds, if snooze is not pressed. # If snooze is pressed, the time delay is 1000 milliseconds. def start while true _nrings += 1 if _stop break else if _snoozePressed System.Threading.Thread.sleep(1000) e = AlarmEventArgs(_snoozePressed, _nrings) .onAlarm(e) else System.Threading.Thread.sleep(300) e = AlarmEventArgs(_snoozePressed, _nrings) .onAlarm(e) # The WakeMeUp class that has a method AlarmRang that handles the alarm event. class WakeMeUp def alarmRang(sender as Object, e as AlarmEventArgs) print e.alarmText if not e.snoozePressed if e.numRings % 10 == 0 print ' Let alarm ring? Enter Y' print ' Press Snooze? Enter N' print ' Stop Alarm? Enter Q' input = Console.readLine if input.equals('Y') or input.equals('y') return else if input.equals('N') or input.equals('n') (sender to AlarmClock).snoozePressed = true return else (sender to AlarmClock).stop = true return else print ' Let alarm ring? Enter Y' print ' Stop Alarm? Enter Q' input = Console.readLine if input.equals('y') or input.equals('y') return else (sender to AlarmClock).stop = true return # The driver class that hooks up the event handling method of # WakeMeUp to the alarm event of an Alarm object using a delegate. class AlarmDriver def main is shared # args = CobraCore.commandLineArgs w = WakeMeUp() # Instantiates the event receiver. clock = AlarmClock() # Instantiates the event source. # Wires the AlarmRang method to the Alarm event. listen clock.alarm, ref w.alarmRang # clock.alarm += new AlarmEventHandler(w.AlarmRang) clock.start }}} Perhaps more commonly the sigs, events and senders are already defined (in a library or framework)[[BR]] and we are only interested in registering for an event and reacting when the event is raised. Heres an example of that around some GUI components:[[BR]] The buttons and form have Keypress and !MouseClick events and associated machinery already defined for them.[[BR]] The example just sets up binding to the listener methods and 'does something' when the events fire [[BR]] (print some of the args fields in this case). {{{ #!cobra %% args -target:exe use System.Windows.Forms use System.Drawing class MyForm inherits Form cue init base.init b = Button() b.text="press me" .controls.add(b) listen b.mouseClick, ref .handleMouseClick listen b.keyPress, ref .handleKey listen .keyPress, ref .handleKey def handleClick(sender as Object, args as EventArgs) m = args to MouseEventArgs print 'btn=[m.button]' print "Locn=[m.location]" print m def handleMouseClick(sender as Object, m as MouseEventArgs) print 'btn =[m.button]' print 'mb=[Control.mouseButtons]' print 'delta =[m.delta]' print 'clicks =[m.clicks]' print "Locn =[m.location]" print m def handleKey(sender as Object, kp as KeyPressEventArgs) print 'KeyPressed', 'key=', kp.keyChar class Program def main is shared has STAThread Application.run(MyForm()) }}} == Notes == With reference to C# nomenclature * a cobra '''sig''' is roughly comparable to a C# delegate * An event is an event in both * 'wiring method to event' or 'instantiating an event delegate' is done in cobra via a '''listen''' statement * 'Invoking a delegate' is done in cobra via the '''raise''' statement. Declaration/execution flow is '''sig''' - '''event''' - '''listen''' - '''raise''' - '''(ignore)''' == See Also == [http://msdn.microsoft.com/en-us/library/edzehd2t%28v=VS.71%29.aspx Handling and raising events] in .Net Framework Developers Guide [wiki:LanguageTopics Back to LanguageTopics]