Filed Under Delphi

Multicast Delegates

visits: 1648 | score: 5 posted by sysrpl on Wednesday December 29, 2010 10:50 AM posted byon Wednesday December 29, 2010 10:50 AM

type TSomeForm = class(TForm) private FOnChange: TDelegate<TNotifyEvent>; end;

begin FOnChange.Add(ChangeHandlerOne); FOnChange.Add(ChangeHandlerTwo); end;

procedure TSomeForm.ChangeHandlerOne(Sender: TObject); begin ShowMessage('Change event handler one fired'); end;

procedure TSomeForm.DoChange; var Event: TNotifyEvent; begin for Event in FOnChange do Event(Self); end;

type IDelegate<T> = interface procedure Add(const Handler: T); procedure Remove(const Handler: T); end;

... private FOnChange: TDelegate<TNotifyEvent>; function GetOnChange: IDelegate<TNotifyEvent>; public property OnChange: IDelegate<TNotifyEvent> read GetOnChange; ... function TSomeForm.GetOnChange: IDelegate<TNotifyEvent>; begin Result := FOnChange; end;

type TNotifyDelegate = TDelegate<TNotifyEvent>; INotifyDelegate = IDelegate<TNotifyEvent>;

type TSomeForm = class(TForm) private FOnChange: TNotifyDelegate; function GetOnChange: INotifyDelegate; protected procedure DoChange; virtual; public property OnChange: INotifyDelegate read GetOnChange; end; implementation procedure TSomeForm.DoChange; var Event: TNotifyEvent; begin for Event in FOnChange do Event(Self); end; function TSomeForm.GetOnChange: INotifyDelegate; begin Result := FOnChange; end;

begin // Add OnChange handler SomeForm.OnChange.Add(SomeFormChanged); // Remove OnChange handler SomeForm.OnChange.Remove(SomeFormChanged); end;

unit Delegates; interface uses Generics.Collections; { IDelegate<T> } type IDelegate<T> = interface ['{ADBC29C1-4F3D-4E4C-9A79-C805E8B9BD92}'] procedure Add(const Handler: T); procedure Remove(const Handler: T); end; { IDelegateContainer<T> } IDelegateContainer<T> = interface ['{ED255F00-3112-4315-9E25-3C1B3064C932}'] function GetDelegate: IDelegate<T> ; function GetEnumerator: TEnumerator<T>; property Delegate: IDelegate<T> read GetDelegate; property Enumerator: TEnumerator<T> read GetEnumerator; end; { TDelegateImpl<T> } TDelegateImpl<T> = class(TInterfacedObject, IDelegate<T>) private FList: TList<T>; protected { IDelegate<T> } procedure Add(const Event: T); procedure Remove(const Event: T); public constructor Create(List: TList<T>); end; { TDelegateContainerImpl<T> } TDelegateContainerImpl<T> = class(TInterfacedObject, IDelegateContainer<T>) private FDelegate: IDelegate<T>; FList: TList<T>; protected { IDelegateContainer<T> } function GetDelegate: IDelegate<T>; function GetEnumerator: TEnumerator<T>; public destructor Destroy; override; end; { TDelegate<T> } TDelegate<T> = record private FContainer: IDelegateContainer<T>; function GetContainer: IDelegateContainer<T>; public class operator Implicit(var Delegate: TDelegate<T>): IDelegate<T>; function GetEnumerator: TEnumerator<T>; procedure Add(const Handler: T); procedure Remove(const Handler: T); end; { Example usage: TNotifyDelegate = TDelegate<TNotifyEvent>; INotifyDelegate = IDelegate<TNotifyEvent>; } implementation { TDelegateImpl<T> } constructor TDelegateImpl<T>.Create(List: TList<T>); begin inherited Create; FList := List; end; { TDelegateImpl<T>.IDelegate<T> } procedure TDelegateImpl<T>.Add(const Event: T); begin if FList.IndexOf(Event) < 0 then FList.Add(Event); end; procedure TDelegateImpl<T>.Remove(const Event: T); begin if FList.IndexOf(Event) > -1 then FList.Remove(Event); end; { TDelegateContainerImpl<T> } destructor TDelegateContainerImpl<T>.Destroy; begin FList.Free; inherited Destroy; end; { TDelegateContainerImpl<T>.IDelegateContainer<T> } function TDelegateContainerImpl<T>.GetDelegate: IDelegate<T>; begin if FList = nil then FList := TList<T>.Create; if FDelegate = nil then FDelegate := TDelegateImpl<T>.Create(FList); Result := FDelegate; end; function TDelegateContainerImpl<T>.GetEnumerator: TEnumerator<T>; begin if FList = nil then FList := TList<T>.Create; Result := FList.GetEnumerator; end; { TDelegate<T> } class operator TDelegate<T>.Implicit(var Delegate: TDelegate<T>): IDelegate<T>; begin Result := Delegate.GetContainer.Delegate; end; function TDelegate<T>.GetContainer: IDelegateContainer<T>; begin if FContainer = nil then FContainer := TDelegateContainerImpl<T>.Create; Result := FContainer; end; function TDelegate<T>.GetEnumerator: TEnumerator<T>; begin Result := GetContainer.GetEnumerator; end; procedure TDelegate<T>.Add(const Handler: T); begin GetContainer.Delegate.Add(Handler); end; procedure TDelegate<T>.Remove(const Handler: T); begin GetContainer.Delegate.Remove(Handler); end; end.

Rate this article