microtronx 38 Posted November 10, 2020 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
Attila Kovacs 629 Posted November 10, 2020 (edited) TEventHandler<T> ? TObservable<T> ? Just my 2 cents, never used them, but it's a good base to start the conversation. Edited November 10, 2020 by Attila Kovacs 1 Share this post Link to post
Eugine Savin 4 Posted November 11, 2020 https://bitbucket.org/sglienke/spring4d/src/ffee3360a2e8cb9ae5311621a745bb9ed809870f/Source/Base/Spring.pas#lines-956 ? Share this post Link to post
microtronx 38 Posted November 11, 2020 1 hour ago, Eugine Savin said: https://bitbucket.org/sglienke/spring4d/src/ffee3360a2e8cb9ae5311621a745bb9ed809870f/Source/Base/Spring.pas#lines-956 ? I found spring4d but there was no demo or i've not seen any demo how to use that. How is Event<T> used? Share this post Link to post
Martin Wienold 35 Posted November 11, 2020 (edited) 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 November 11, 2020 by Martin Wienold 4 Share this post Link to post