Events and Method Pointers

20.1 Method Pointers (of object)

A method pointer = code pointer + object pointer (TMethod). VCL/FMX events are single-cast (one handler per event).

type
  TNotifyEvent = procedure(Sender: TObject) of object;       // already declared in System.Classes
  TProgressEvent = procedure(Sender: TObject; Percent: Integer; var Cancel: Boolean) of object;

  TDownloader = class
  private
    FOnProgress: TProgressEvent;
    FOnComplete: TNotifyEvent;
  public
    procedure Run;
    property OnProgress: TProgressEvent read FOnProgress write FOnProgress;
    property OnComplete: TNotifyEvent read FOnComplete write FOnComplete;
  end;

procedure TDownloader.Run;
var
  Cancel: Boolean;
begin
  Cancel := False;
  for var I := 1 to 100 do
  begin
    if Assigned(FOnProgress) then FOnProgress(Self, I, Cancel);    // fire only if assigned
    if Cancel then Exit;
  end;
  if Assigned(FOnComplete) then FOnComplete(Self);
end;

// Subscriber (a form method)
procedure TMainForm.HandleProgress(Sender: TObject; Percent: Integer; var Cancel: Boolean);
begin
  ProgressBar1.Position := Percent;
end;

Downloader.OnProgress := HandleProgress;     // assign the handler

20.2 Multicast Events

Implement a list of handlers (TList<TNotifyEvent>), or use the Spring4D Event<T> / IEvent<T> multicast events, or System.Messaging.TMessageManager (publish/subscribe).

uses System.Messaging;
type TOrderPlacedMessage = class(TMessage<Integer>);
var SubId := TMessageManager.DefaultManager.SubscribeToMessage(TOrderPlacedMessage,
  procedure(const Sender: TObject; const M: TMessage)
  begin
    Writeln('Order placed: ', TOrderPlacedMessage(M).Value);
  end);
TMessageManager.DefaultManager.SendMessage(nil, TOrderPlacedMessage.Create(42));
TMessageManager.DefaultManager.Unsubscribe(TOrderPlacedMessage, SubId);