3

I'm trying to use the Spring4d framework for Delphi and I want to use the Multicast Events. While using the "normal" TNotifyEvent, it works and the handler will get called twice.

uses
  ...
  Spring,
  Spring.Events,
  Spring.Events.Base;

procedure TfrmMain.EventHandler1(Sender: TObject);
begin
  Log('called handler1');
end;

procedure TfrmMain.btnNotifyEventClick(Sender: TObject);
var
  MulticastEvent: TEvent<TNotifyEvent>;
begin
  MulticastEvent := TEvent<TNotifyEvent>.Create;
  try
    MulticastEvent.Add(EventHandler1);
    MulticastEvent.Add(EventHandler1);
    MulticastEvent.Add(EventHandler1);
    MulticastEvent.Remove(EventHandler1);
    MulticastEvent.Invoke;
  finally
    MulticastEvent.Free;
  end;
end;

But I can't figure out how to use these Multicast events with my own Event TSyncEvent. The EventHandler2 expects a string. So I want to call the Invoke-method with the text.

type
  TSyncEvent = procedure(Sender: TObject; const iMsg: string) of object;

procedure TfrmMain.EventHandler2(Sender: TObject; const iMsg: string);
begin
  Log('called handler2: '+iMsg);
end;

procedure TfrmMain.btnSyncEventClick(Sender: TObject);
var
  MulticastEvent: TEvent<TSyncEvent>;
begin
  MulticastEvent := TEvent<TSyncEvent>.Create;
  try
    MulticastEvent.Add(EventHandler2);
    MulticastEvent.Add(EventHandler2);
    MulticastEvent.Invoke('text for handler2');
  finally
    MulticastEvent.Free;
  end;
end;

This code does not compile with the error message "too many params for method Invoke". Unfortunately there is no example using the Multicast events in the framework or on the project page. I'm using Delphi 10.3.3 Community Edition.

Thank you.

ReneS
  • 33
  • 3
  • I don't use Spring4D so I can't answer specifically for that, but what you want should be easily achievable with standard Delphi. The error message indicates that you cannot pass a parameter to Invoke, so you need to derive a class from the `TEvent` class that support that. If you have source code for the `TEvent` class you should be able to extend it easily to replicate the `Invoke` function allowing it to accept a parameter and pass it on. You will probably find it easier to write this as a standard class inheriting from a generic rather than trying to keep it generic. – Rob Lambden Apr 16 '21 at 10:35
  • Thank you Rob. That is completely right. But my hope was, that there is a better approach coming from this framework - as Stefan pointed out :-) – ReneS Apr 16 '21 at 13:24

1 Answers1

6

You are not supposed to use the TEvent<T> class from Spring.Events.pas because it's an implementation detail and in fact, in 2.0 it will not even exist anymore because it was refactored.
Instead, use the record type Event<T> from Spring.pas. It does not need to be created nor destroyed because it does that automatically.

Once you change that in your code you will see that you are missing the Sender argument.
Press Ctrl+Shift+Space to see the parameters of Invoke - it has exactly the same signature of the type of T you are providing.

Fixed code:

procedure TfrmMain.btnSyncEventClick(Sender: TObject);
var
  MulticastEvent: Event<TSyncEvent>;
begin
  MulticastEvent.Add(EventHandler2);
  MulticastEvent.Add(EventHandler2);
  MulticastEvent.Invoke(Sender, 'text for handler2');
end;
Stefan Glienke
  • 20,860
  • 2
  • 48
  • 102