An event is a type member that consumers of the class can use to add, remove and optionally raise event handlers.
Events are always delegate types. From within the class, the event can be used like a plain delegate variable, but from the outside consumers can only add or remove handlers they know about.
Oxygene also provides a "raise" method that makes it possible to invoke an event externally.
By default, the variable and the accessor methods are compiler generated. Optionally, the member or add/remove/raise accessors can be stated explicitly.
type MyDelegate = delegate (Sender: Object; Args: EventArgs); MyInterface = interface event MyEvent: MyDelegate; event MyRaiseEvent: MyDelegate raise; end; MyClass = class(MyInterface) private fMember: MyDelegate; method AddExplicitEvent(param: MyDelegate); method RemoveExplicitEvent(param: MyDelegate); method RaiseExplicitEvent(sender: Object; Args: EventArgs); public event MyEvent: MyDelegate delegate fMember; event MyRaiseEvent: MyDelegate raise; // implicit field. Also works without the raise. event ExplcitEvent: MyDelegate add AddExplicitEvent remove RemoveExplicitEvent raise RaiseExplicitEvent; end; method MyClass.AddExplicitEvent(param: MyDelegate); begin fMember := MyDelegate(&Delegate.Combine(fMember, param)); end; method MyClass.RemoveExplicitEvent(param: MyDelegate); begin fMember := MyDelegate(&Delegate.Remove(fMember, param)); end; method MyClass.RaiseExplicitEvent(sender: Object; Args: EventArgs); begin if assigned(fMember) then fMember(sender, Args); end;
In cases where you want to provide your own logic for adding/removing delegates to and from the event, the following extended syntax can be used:
type TMyClass = class(...) private fMyEvent: EventHandler; method AddMyEvent(aValue: EventHandler); method RemoveMyEvent(aValue: EventHandler); public event MyEvent: EventHandler add AddMyEvent remove RemoveMyEvent; end;
With this syntax, the two specified add and remove methods must conform to the syntax above, they must be procedures and take only one parameter, the matching delegate type. If either is provided, both "add" and "remove" must be specified.
The raise keyword on an event can be used to allow external classes to invoke the event handler. If present, it creates an internal method called fire_EventHandlerName with the signature of the delegate. Inside this method, code is generated to check if the event is assigned and - if it is - invoke it.
It is also possible to provide a custom raise method implementation.
When the raise keyword is set on an event, all calls to the events inside the class will use the raise method (if raise is not specified (default), the invoke method on the fMyEvent will be called inline). Because of this, there is no need to check for nil when there is a raise keyword involved.
Like the add/remove accessors, it is possible to change the visiblity of the raise method, for example protecting it, so only subclasses can call it.
type MyEventTest = class private var f: EventHandler; method add_Event(e: EventHandler); method remove_Event(e: EventHandler);; method raise_Event(o: Object; e: EventArgs); public event ev1: EventHandler; event ev2: EventHandler raise; event ev2: EventHandler protected raise; // descendants can raise event ev3: EventHandler delegate f; event ev4: EventHandler delegate f raise; event ev5: EventHandler add add_event remove remove_event raise raise_event; // custom methods end;
When a non-private raise method is defined, the event can be invoked from outside the class, according to the visibility, through its name:
When consuming classes from languages that do not support using raise event invoking (such as C# and VB), the internal fire_myevent() method can be called directly.
When using a property with an implicit field (no add/remove/delegate keyword), you can apply attributes to the auto generated fields with the var: prefix. See Attribute Scopes for more information.