![]() |
Multicaster in Delphi 2009
Hi,
ich habe ein Problem mit Delphi 2009. Ich will einen Multicast delegate für einen TButton-Click bauen (beispielhaft, soll gegen später generisch mit jedem Event gehen). Die Idee ist folgende: Mittels eines Class helpers erweitere ich die Klasse TButton um zwei Methoden: AddEvent und RemoveEvent. In einem generischen Dictionary merke ich mir dann zu jedem verwendeten Button eine Liste mit registrierten Events. Wird mit AddEvent eines hinzugefügt, so hänge ich dieses Event in die Liste ein und bei remove soll das Event auch aus der Liste entfernt werden. (Ja, ich fake mittels des Dictionarys sozusagen ein Property zu dem Button dazu - class helper mit zusätzlichen Properties könnten mittels eines generischen Dictionaries auch so hinzubekommen sein). Das Hinzufügen und Ausführen der Events funktioniert auch schon, aber das Entfernen eines einmal registrierten Events schmeisst eine Zugriffsverletzung, und zwar genau an der Stelle an dem geprüft wird, ob das Event in der Liste ist. Kann man jemand drübergucken und mir sagen, warum ich das Event auf diese Art zwar in die Liste hinzufügen, aber nicht mer entfernen kann? Mir erscheint das etwas unlogisch und die Zugriffsverletzung passiert jedes mal an einer anderen Adresse, so dass ich gar nicht sagen kann wo die herkommt. Hier mal die komplette betreffende Unit:
Delphi-Quellcode:
unit UMulticaster;
interface uses Classes, StdCtrls; type TButtonMulticaster = class helper for TButton procedure AddEvent(event: TNotifyEvent); overload; procedure RemoveEvent(event: TNotifyEvent); overload; end; implementation uses SysUtils, Generics.Defaults, Generics.Collections; type eventList = TList<TNotifyEvent>; eventDictionary = TDictionary<TButton, eventList>; EventDispatcher = class private eventList: eventDictionary; public constructor Create; destructor Destroy; public procedure OnSomeButtonClick(sender: TObject); property Events: eventDictionary read eventList write eventList; end; var dispatcher: EventDispatcher; { EventDispatcher } constructor EventDispatcher.Create; begin eventList := eventDictionary.Create(); end; destructor EventDispatcher.Destroy; begin FreeAndNil(eventList); end; procedure EventDispatcher.OnSomeButtonClick(sender: TObject); var event: TNotifyEvent; begin for event in eventList.Items[TButton(sender)] do begin event(sender); end; end; { TButtonMulticaster } procedure TButtonMulticaster.AddEvent(event: TNotifyEvent); begin if not dispatcher.Events.ContainsKey(self) then begin dispatcher.Events.Add(self, eventList.Create()); self.OnClick := dispatcher.OnSomeButtonClick; end; dispatcher.Events[self].Add(event); end; procedure TButtonMulticaster.RemoveEvent(event: TNotifyEvent); var evList: eventList; begin if dispatcher.Events.ContainsKey(self) then begin evList := dispatcher.Events[self]; if evList.IndexOf(event) >= 0 then // HIER wird die Zugriffsverletzung ausgelöst evList.Remove(event); if dispatcher.Events[self].Count = 0 then begin dispatcher.Events.Remove(self); self.OnClick := nil; end; end; end; initialization begin dispatcher := EventDispatcher.Create(); end; finalization begin FreeAndNil(dispatcher); end; end. |
Re: Multicaster in Delphi 2009
Zitat:
Soll der Code der die class helper Lösung verwendet, eventuell mit fremdem Code kombiniert werden? Man kann nur einen class helper je Klasse definieren, andere Libraries könnten daher mit eigenem Code kollidieren. Delphi erzeugt afaik dann noch nicht einmal eine Warnung. |
Re: Multicaster in Delphi 2009
Versuch mal, beim eventList.Create() einen Comparer für TNotifyEvent zu übergeben. Der wird nämlich von IndexOf verwendet.
|
Re: Multicaster in Delphi 2009
geh jedes Element der Liste durch und prüfe so auf Gleichheit.
Ich vermute, dass Du das Event beim reinen hinschreiben sogar aufrufst, und das willst Du ja nicht. so geht es bei meinem Multicaster.
Delphi-Quellcode:
procedure TButtonMulticaster.RemoveEvent(event: TNotifyEvent);
var ... evList: eventList; for i := (eventList.Count - 1) downto 0 do begin ev := eventList.Items[i]; if (TMethod(ev).Code = TMethod(event).Code ) and (TMethod(ev).Data = TMethod(event).Data ) then begin eventList.Delete(i); // exit; end; // if end; // for end; |
Re: Multicaster in Delphi 2009
Zitat:
Grüße, Uli |
Re: Multicaster in Delphi 2009
Hier ist ein Artikel (mit Source) zu Multicast-Events von Allen Bauer:
The Oracle at Delphi: Multicast events using generics ![]() Generics in Delphi scheinen noch etwas verbesserungsbedürftig zu sein. Der Sourcecode zu diesem Artikel ist auch noch nicht komplett veröffentlicht, und im vorletzten Artikel werden auch einige Risiken angesprochen. |
Re: Multicaster in Delphi 2009
Ich hab ihn jetzt am laufen.
Muss noch ein paar Feinheiten anpassen, aber im Prinzip sollte er dann sogar für jedes beliebige Event gehen ;-) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:58 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz