Jump to content
microtronx

MultiCast NotifyEvents / DatasetNotifyEvents

Recommended Posts

After searching the internet a lot i've decided to create a new unit to be able to assign multiple afterscroll or afteropen events to one component ... very simple in runtime. 

Informations on https://www.delphipraxis.net/143341-event-multicast-problem-howto-sender-methodname.html helped me to create a basic unit.

 

Pls check it at https://github.com/MicrotronX/Multicast-Events

 

I know, there must be something better out there ... but for me this works very good ... 

PS: I cannot guarantee that the source code is free of bugs!

 

Example-Usage in a tDataset descant:

unit myMulticastEventDatasetUnit;
interface
uses System.Classes, Data.DB, mxEventsUnit;

type
	tmyMulticastEventDataset=class(tDataset)
	private
		function fmxevents_get:tmxevents;
	public
		fmxEvents:TmxEvents;
		constructor Create(AOwner:TComponent); override;
		destructor Destroy; override;
	published
		property mxEvents:TmxEvents read fmxevents_get;
	end;

implementation

constructor tmyMulticastEventDataset.Create(AOwner: TComponent);
begin
	inherited;
	fmxEvents:=nil;
end;

destructor tmyMulticastEventDataset.Destroy;
begin
	if assigned(fmxEvents) then fmxEvents.free;
	fmxEvents:=nil;
	inherited;
end;

function tmyMulticastEventDataset.fmxevents_get: tmxevents;
begin
	// we Create the tmxEvents only if there is a need
	if not assigned(fmxevents) then begin
		fmxEvents:=tmxEvents.create(self);
	end;
	result:=fmxevents;
end;
end.

 

If someone knows a way to inject this into tDataset itself, you're free to change the code!

 

Declarations for Examples:
  myDS:tmyMulticastEventDataset;
  procedure FirstAfterScrollEvent(vDataset:tDataset); 
  procedure SecondAfterScrollEvent(vDataset:tDataset); 
  
Example-Usage for registering a AfterScroll Event:
  myDS.mxEvents.Event('AfterScroll').AddDatasetNotifyEvent('uniquenameforevent1',  FirstAfterScrollEvent) ;
  myDS.mxEvents.Event('AfterScroll').AddDatasetNotifyEvent('uniquenameforevent2',  SecondAfterScrollEvent) ;

Example-usage for disabling a already registered AfterScroll Event:
  myMCDS1.mxEvents.Event('AfterScroll').Disable('uniquenameforevent1') ;
  myMCDS1.mxEvents.Event('AfterScroll').Disable('uniquenameforevent2') ;

 

Share this post


Link to post

TEventHandler<T> ?

TObservable<T> ?

 

Just my 2 cents, never used them, but it's a good base to start the conversation.

Edited by Attila Kovacs
  • Thanks 1

Share this post


Link to post

Here is an example for how to use the Spring4D multicast events:

type
  TEventSource = class
  private
    // record type here
    // for the generic parameter T you can use any Event type you used before,
    //  for this example I just use TNotifyEvent
    fOnChanged: Event<TNotifyEvent>; 
    // getter for the property
    procedure GetOnChanged: IEvent<TNotifyEvent>; 
    // internal method to just trigger the OnChange event as shorthand
    procedure DoChanged;
  public
    property Number: Integer read fNumber write SetNumber;
    
    // event to which you subscribe to
    // interface type here
    property OnChanged: IEvent<TNotifyEvent> read GetOnChanged; 
  end;
  
procedure TEventSource.GetOnChanged: IEvent<TNotifyEvent>;
begin
  // the record type has implicit operators that will 
  //  lazy initialize its internals and return it as an interface reference
  // internaly in TEventSource, you should access the field member and
  //  not the property since the implicit operator does not need
  //  to run every time
  Resut := fOnChanged; 
end;

procedure TEventSource.DoChanged;
begin
  // CanInvoke only returns true if there are any listeners on the event
  // the parameters of Invoke will change depending on the generic parameter T 
  //  of the field member 
  if fOnChanged.CanInvoke then
    fOnChanged.Invoke(Self); 
end;

procedure TEventSource.SetNumber(const Value: Integer);
begin
  if fNumber <> Value then
  begin
    fNumber := Value;
    DoChanged;
  end;
end;
type
  TEventListener = class
  private
    fSource: TEventSource;
    
    procedure HandleChanged(Sender: TObject);
  public
    constructor Create;
    destructor Destroy; override;
    
    procedure Something;
  end;
  
constructor TEventListener.Create;
begin
  inherited;
  fSource := TEventSource.Create;
  // add an event handler to the multicast event
  fSource.OnChanged.Add(HandleChanged);
end;

destructor TEventListener.Destroy;
begin
  // remove the event handler from the multicast event
  // if the source has a longer lifetime than the listener, 
  //  you should always make sure to remove the handler.
  // if you do not, there will be a dangling pointer inside
  //  of the multicast event, pointing to your freed listener
  fSource.OnChanged.Remove(HandleChanged);
  fSource.Free;
  inherited;
end;

procedure TEventListener.HandleChanged(Sender: TObject);
begin
  
end;

procedure TEventListener.Something;
begin
  fSource.Number := 1;
end;

I'm sorry if there are any compile errors, I don't have access to a compiler at the moment.

Edited by Martin Wienold
  • Like 4

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×