.Net Runtime Library for Delphi
Close
How to: Raise and Consume Events

The examples in this topic show how to work with events. They include examples of the TClrEventHandler and TClrEventHandlerR standard function pointers. There are examples which does not use the Clr Standard function pointers. A new function pointer will be created whose signature matches the signature of the eventhander method defined in c#.

The examples use concepts described in the Handling and Raising Events article.

Example 1

The first example shows how to raise and consume an event that doesn't have data. It contains a class named Counter that has an event named ThresholdReached. This event is raised when a counter value equals or exceeds a threshold value. The TClrEventHandler function pointer is associated with the event, because no event data is provided.

Assuming you have a C# class as shown below which is compiled to Counter.dll.

C#
namespace CounterEventhandler { public class Counter { private int threshold; private int total; public Counter(int passedThreshold) { threshold = passedThreshold; } public void Add(int x) { total += x; if (total >= threshold) { OnThresholdReached(EventArgs.Empty); } } protected virtual void OnThresholdReached(EventArgs e) { EventHandler handler = ThresholdReached; if (handler != null) { handler(this, e); } } public event EventHandler ThresholdReached; } }






























Delphi
program ExampleApp; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Host.Helper, CNClrLib.Core; //Delphi Implementation of the C# Class above type TCounter = class(TClrBaseObject) private FOnThresholdReached : TClrEventHandler; procedure SetThresholdReached(Value : TClrEventHandler); public constructor Create(passedThreshold: Integer); destructor Destroy; override; procedure Add(x: Integer); property OnThresholdReached: TClrEventHandler read FOnThresholdReached write SetThresholdReached; end; { TCounter } procedure TCounter.Add(x: Integer); begin InvokeMethod('Add', 'System.Int32', [x]); end; constructor TCounter.Create(passedThreshold: Integer); begin inherited Create('CounterEventhandler.Counter', [passedThreshold]); end; destructor TCounter.Destroy; begin inherited; end; procedure TCounter.SetThresholdReached(Value: TClrEventHandler); begin if @FOnThresholdReached <> nil then UnRegisterEventCallBack('ThresholdReached', @FOnThresholdReached); FOnThresholdReached := Value; if @FOnThresholdReached <> nil then RegisterEventCallBack('ThresholdReached', @FOnThresholdReached) end; var Console: _Console; Counter: TCounter; procedure c_ThresholdReached(ASender: _ClrObject; AEventArgs: _ClrEventArgs); stdcall; begin Console.WriteLine_14('The threshold was reached.'); Abort; end; begin Console := CoConsole.CreateInstance; TClrAssembly.LoadFrom('Counter.dll'); Counter := TCounter.Create(CoRandom.CreateInstance.Next_2(10)); Counter.OnThresholdReached := c_ThresholdReached; Console.WriteLine_14('press ''a'' key to increase total'); while TClrCharHelper.ToChar(Console.ReadKey_1(True).KeyChar) = 'a' do begin Console.WriteLine_14('adding one'); Counter.Add(1); end; end.




































































 

Example 2

The next example shows how to raise and consume an event that provides data. The TClrEventHandler function pointer is associated with the event, and an instance of a custom event data object is provided.

Assuming you have a C# class as shown below which is compiled to Counter.dll.

C#
namespace CounterEventhandler { class Counter { private int threshold; private int total; public Counter(int passedThreshold) { threshold = passedThreshold; } public void Add(int x) { total += x; if (total >= threshold) { ThresholdReachedEventArgs args = new ThresholdReachedEventArgs(); args.Threshold = threshold; args.TimeReached = DateTime.Now; OnThresholdReached(args); } } protected virtual void OnThresholdReached(ThresholdReachedEventArgs e) { EventHandler<ThresholdReachedEventArgs> handler = ThresholdReached; if (handler != null) { handler(this, e); } } public event ThresholdReached(Object Sender, ThresholdReachedEventArgs e); } public class ThresholdReachedEventArgs : EventArgs { public int Threshold { get; set; } public DateTime TimeReached { get; set; } } }






























Delphi
program ExampleApp1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Host.Helper, CNClrLib.Core; //Delphi Implementation of the C# Class above type TCounter = class(TClrBaseObject) private FOnThresholdReached : TClrEventHandler; procedure SetThresholdReached(Value : TClrEventHandler); public constructor Create(passedThreshold: Integer); destructor Destroy; override; procedure Add(x: Integer); property OnThresholdReached: TClrEventHandler read FOnThresholdReached write SetThresholdReached; end; { TCounter } procedure TCounter.Add(x: Integer); begin InvokeMethod('Add', 'System.Int32', [x]); end; constructor TCounter.Create(passedThreshold: Integer); begin inherited Create('CounterEventhandler.Counter', [passedThreshold]); end; destructor TCounter.Destroy; begin inherited; end; procedure TCounter.SetThresholdReached(Value: TClrEventHandler); begin if @FOnThresholdReached <> nil then UnRegisterEventCallBack('ThresholdReached', @FOnThresholdReached); FOnThresholdReached := Value; if @FOnThresholdReached <> nil then RegisterEventCallBack('ThresholdReached', @FOnThresholdReached) end; var Console: _Console; Counter: TCounter; procedure c_ThresholdReached(ASender: _ClrObject; AEventArgs: _ClrEventArgs); stdcall; var ThresholdReachedEventArgs: _ClrObject; Threshold: Integer; TimeReached: TDateTime; begin //NB: The C# ThresholdReachedEventArgs class object is stored _ClrEventArgs.EventArgs ThresholdReachedEventArgs:= AEventArgs.EventArgs.AsClrObject; Threshold := ThresholdReachedEventArgs.GetPropertyValue('Threshold'); TimeReached := ThresholdReachedEventArgs.GetPropertyValue('TimeReached'); Console.WriteLine_17('The threshold of {0} was reached at {1}.', Threshold, TimeReached); Abort; end; begin Console := CoConsole.CreateInstance; TClrAssembly.LoadFrom('Counter.dll'); Counter := TCounter.Create(CoRandom.CreateInstance.Next_2(10)); Counter.OnThresholdReached := c_ThresholdReached; Console.WriteLine_14('press ''a'' key to increase total'); while TClrCharHelper.ToChar(Console.ReadKey_1(True).KeyChar) = 'a' do begin Console.WriteLine_14('adding one'); Counter.Add(1); end; end.

















































































 

Example 3

The next example shows how to raise and consume an event that provides data. The TClrEventHandlerR function pointer is associated with theAssemblyResolve event.

Delphi
program ExampleApp2; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Core, CNClrLib.Core.Intf; const lookupPath = 'c:\otherbin\'; {Assuming the missing Dlls are located in this Folder} procedure AssemblyResolveHandler(ASender: _ClrObject; AEventArgs: _ClrEventArgs; out ReturnValue: _ClrObject); stdcall; var Args: _ResolveEventArgs; AsmName: _AssemblyName; AsmFileName: string; Asmbly: _Assembly; begin //Convert the AEventArgs.EventArgs to the original C# event Data which is ResolveEventArgs Args := CoResolveEventArgs.Wrap(AEventArgs.EventArgs); AsmName := CoAssemblyName.CreateInstance(Args.Name); AsmFileName:= lookupPath + AsmName.Name + '.dll'; if FileExists(AsmFileName) then begin //Load and Convert the Assembly to ClrObject and pass to the out parameter of the event handler; ReturnValue := TClrAssembly.LoadFrom(AsmFileName).AsClrObject; end else ReturnValue := nil; end; var Console: _Console; AssemblyResolve: TClrEventHandlerR; begin Console := CoConsole.CreateInstance; AssemblyResolve := AssemblyResolveHandler; TClrAppDomain.GetCurrentDomain.AddAssemblyResolve(nil, @AssemblyResolve); try //For this code example to run, you must provide the fully qualified assembly name TClrAppDomain.GetCurrentDomain.DefaultInterface.CreateInstanceAndUnwrap('MyAssembly, '+ 'version=1.2.3.4, culture=neutral, publicKeyToken=null', 'MyType'); except on E: Exception do Console.WriteLine_14(E.Message); end; Console.ReadKey; end.
























































 

Example 4

The next example shows how to raise and consume an event without using the standard Clr function Pointers (TClrEventHandlerR or TClrEventHandler). A new function pointer is created whose signature matches the signature of the eventhandler method in c#. Assuming you have a C# class as shown below which is compiled to Counter.dll.

C#
namespace CounterEventhandler { public class Counter { private int threshold; private int total; public Counter(int passedThreshold) { threshold = passedThreshold; } public void Add(int x) { total += x; if (total >= threshold) { OnThresholdReached(total, threshold); } } protected virtual void OnThresholdReached(int total, int threshold) { EventHandler handler = ThresholdReached; if (handler != null) { handler(this, e); } } public event Action<int,int> ThresholdReached; } }





















The following Delphi Code demonstrate how to register the event from the C# Class without using standard Clr function pointers and also how to unregister the event.
Delphi
program Register_UnRegisterEvents; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Host.Helper, CNClrLib.Core; type //Since i am not using the standard Clr Function Pointer (TClrEvenHandler or TClrEventhandlerR), //I am creating my own which will mimick the signature of the the C# event i want to register. TThresholdReached = procedure(total, threshold: Integer); stdcall; var Console: _Console; clrCounter: _ClrObject; ARandom: _Random; OnThresholdReached : TThresholdReached; procedure c_ThresholdReached(total, threshold: Integer); stdcall; begin Console.WriteLine_14('The threshold was reached.'); Abort; end; begin Console := CoConsole.CreateInstance; TClrAssembly.LoadFrom('Counter.dll'); ARandom := CoRandom.CreateInstance; clrCounter := CoClrObject.CreateInstance(TClrAssembly.GetType('CounterEventhandler.Counter'), TClrArrayHelper.ToObjectArray([ARandom.Next_2(10)])); //Register Event OnThresholdReached := c_ThresholdReached; clrCounter.RegisterEventCallBackDirect('ThresholdReached', TClrConvert.ToManagedPointer(@OnThresholdReached)); Console.WriteLine_14('press ''a'' key to increase total'); while TClrCharHelper.ToChar(Console.ReadKey_1(True).KeyChar) = 'a' do begin Console.WriteLine_14('adding one'); clrCounter.InvokeMethod_1('Add', 'System.Int32', TClrArrayHelper.ToObjectArray([1])); end; //UnRegister Event clrCounter.UnRegisterEventCallBackDirect('ThresholdReached', TClrConvert.ToManagedPointer(@OnThresholdReached)); end.