interface
uses
Messages,
System.Generics.Collections,
Winapi.Windows,
Vcl.Controls,
System.SyncObjs;
type
IMessageDistributor =
interface
procedure Subscribe(
const Msg : UINT;
const Listener : TWinControl);
overload;
procedure Subscribe(
const Msgs :
array of UINT;
const Listener : TWinControl);
overload;
procedure Unsubscribe(
const Msg : UINT;
const Listener : TWinControl);
overload;
procedure Unsubscribe(
const Msgs :
array of UINT;
const Listener : TWinControl);
overload;
function PostMessageToSubscribers(
const Msg : UINT;
const WParameter : WPARAM = 0;
const LParameter : LPARAM = 0) : Boolean;
end;
TMessageDistributor =
class(TInterfacedObject, IMessageDistributor)
strict private
type
TListenerList = TList<TWinControl>;
strict private
FMessageToListenerMapping : TDictionary<UINT, TListenerList>;
FCritcalSection : TCriticalSection;
public
constructor Create;
destructor Destroy;
override;
procedure Subscribe(
const Msg : UINT;
const Listener : TWinControl);
overload;
procedure Subscribe(
const Msgs :
array of UINT;
const Listener : TWinControl);
overload;
procedure Unsubscribe(
const Msg : UINT;
const Listener : TWinControl);
overload;
procedure Unsubscribe(
const Msgs :
array of UINT;
const Listener : TWinControl);
overload;
function PostMessageToSubscribers(
const Msg : UINT;
const WParameter : WPARAM = 0;
const LParameter : LPARAM = 0) : Boolean;
end;
function MessageDistributor : IMessageDistributor;
implementation
var
_MessageDistributor : IMessageDistributor;
function MessageDistributor : IMessageDistributor;
begin
if not Assigned(_MessageDistributor)
then
begin
_MessageDistributor := TMessageDistributor.Create;
end;
Result := _MessageDistributor;
end;
{ TMessageDistributor }
constructor TMessageDistributor.Create;
begin
FCritcalSection := TCriticalSection.Create;
FMessageToListenerMapping := TObjectDictionary<UINT, TListenerList>.Create([doOwnsValues]);
end;
destructor TMessageDistributor.Destroy;
begin
FMessageToListenerMapping.Free;
FCritcalSection.Free;
inherited;
end;
function TMessageDistributor.PostMessageToSubscribers(
const Msg : UINT;
const WParameter : WPARAM = 0;
const LParameter : LPARAM = 0) : Boolean;
var
Listeners : TListenerList;
Listener : TWinControl;
begin
Result := False;
FCritcalSection.Enter;
try
if FMessageToListenerMapping.TryGetValue(Msg, Listeners)
then
begin
for Listener
in Listeners
do
begin
if Assigned(Listener)
then
begin
Result := PostMessage(Listener.Handle, Msg, WParameter, LParameter);
end;
end;
end;
finally
FCritcalSection.Leave;
end;
end;
procedure TMessageDistributor.Subscribe(
const Msgs :
array of UINT;
const Listener : TWinControl);
var
I : Integer;
begin
for I := Low(Msgs)
to High(Msgs)
do
begin
Subscribe(Msgs[I], Listener);
end;
end;
procedure TMessageDistributor.Unsubscribe(
const Msgs :
array of UINT;
const Listener : TWinControl);
var
I : Integer;
begin
for I := Low(Msgs)
to High(Msgs)
do
begin
Unsubscribe(Msgs[I], Listener);
end;
end;
procedure TMessageDistributor.Subscribe(
const Msg : UINT;
const Listener : TWinControl);
var
Listeners : TListenerList;
begin
if FMessageToListenerMapping.TryGetValue(Msg, Listeners)
then
begin
if Assigned(Listeners)
then
begin
if not Listeners.
Contains(Listener)
then
Listeners.Add(Listener);
end;
end
else
begin
Listeners := TListenerList.Create;
Listeners.Add(Listener);
FMessageToListenerMapping.Add(Msg, Listeners);
end;
end;
procedure TMessageDistributor.Unsubscribe(
const Msg : UINT;
const Listener : TWinControl);
var
Listeners : TListenerList;
begin
if FMessageToListenerMapping.TryGetValue(Msg, Listeners)
then
begin
if Assigned(Listeners)
then
begin
Listeners.Remove(Listener);
end;
end;
end;