.Net Runtime Library for Delphi
Handling and Raising Events

Events in the .NET Framework are based on the delegate model. The delegate model follows the observer design pattern, which enables a subscriber to register with, and receive notifications from, a provider. An event sender pushes a notification that an event has happened, and an event receiver receives that notification and defines a response to it.

An event is a message sent by an object to signal the occurrence of an action. The object that raises the event is called the event sender . The event sender doesn't know which object or method will receive (handle) the events it raises. The event is typically a member of the event sender. The .NET Framework follows a naming pattern of ending all event data classes with EventArgs.

Example of standard .Net framework event delegate:

//Does not return anything public delegate void StateChangeHandler (Object sender, StateChangeEventArgs e); //Return Boolean public delegate bool StateChangeHandler (Object sender, StateChangeEventArgs e);

A delegate is a type that holds a reference to a method. A delegate is declared with a signature that shows the return type and parameters for the methods it references, and can hold references only to methods that match its signature. A delegate is thus equivalent to a function pointer or a callback in Delphi. The Runtime Library provides the following delegates or function pointers to support the c# standard delegates such as the one above.

//Does not return anything TClrEventHandler = procedure(ASender: _ClrObject; AEventArgs: _ClrEventArgs); stdcall; //The value returned is stored in the last parameter TClrEventHandlerR = procedure(ASender: _ClrObject; AEventArgs: _ClrEventArgs; out ReturnValue: _ClrObject); stdcall;
Use the TClrEventHandler delegate for all events that do not return type value and take takes two parameters (an object for the source of the event and an object for event data). Use the TClrEventHandlerR delegate for all events that return type value and take three parameters (an object for the source of the event, an object for event data and the object for the return value). You can create your own function pointer or delegate in delphi to register a c# event whose signature does not match the standard .Net event delegate. For Example, if a C# event delegate looks like this:
public delegate void CounterChangehandler(int Counter, int Total);
In order to hook up thios event in delphi using the runtime library, you need to create a function pointer which matches the signature and ends with a stdcall convertion call.
TCounterChangehandler = procedure(Counter, Total: Integer); stdcall;
For more information and example, see Raise and Consume Events .

Data that is associated with an event can be provided through an event data class. The Runtime Library provides a ClrEventArgs interface that you can use in your applications. The ClrEventArgs.EventArgs property holds the .net framework Event Data.

To respond to an event, you define an event handler method in the event receiver. This method must match the signature of the delegate for the event you are handling. In the event handler, you perform the actions that are required when the event is raised, such as collecting user input after the user clicks a button. To receive notifications when the event occurs, your event handler method must subscribe to the event.

The following example shows an event handler method named c_ThresholdReached that matches the signature for the TClrEventHandler function pointer. The method subscribes to the ThresholdReached event.

program EventHandler; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Core; var Console: _Console; AThresholdReachedPtr: TClrEventHandler; ACounter: _Counter; //Method with the same signature as the Runtime Library Delegate/Function Pointer //Remember to include stdcall calling convertion. This allow parameters to be pass from right to left //Omitting this convertion will cause access violation when the managed code callback this event method procedure c_ThresholdReached(ASender: _ClrObject; AEventArgs: _ClrEventArgs); stdcall; begin Console.WriteLine_14('The threshold was reached.'); end; begin Console := CoConsole.CreateInstance; AThresholdReachedPtr:= c_ThresholdReached; ACounter := CoCounter.CreateInstance; //Add Event handler ACounter.AddThresholdReached(nil, @AThresholdReachedPtr); //Remove Event Handler ACounter.RemoveThresholdReached(@AThresholdReachedPtr); end.



How to: Raise and Consume Events

Contains examples of raising and consuming events.