![]() |
on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Der Titel ist eine Katastrophe, bessere Vorschläge erbeten :oops:
Konkretes Beispiel: Setze ich in meiner VCL-
Delphi-Quellcode:
die Property
TRadioGroup
Delphi-Quellcode:
um, so ergibt sich folgende Aufrufreihenfolge:
ItemIndex
Code:
Ich möchte nicht, dass das ganze Geraffel hintendran (onClick-Ereignishandler) ausgeführt wird, das ist doch nur dafür, wenn der Benutzer aktiv draufklickt und etwas ändern möchte.
TCustomRadioGroup.SetItemIndex() -> TControl.Click -> myRadioGroup.OnClick()
Wie gehe ich hier am besten vor? Ist meine Absicht falsch? Setze ich das
Delphi-Quellcode:
-Ereignis vorher auf
onClick
Delphi-Quellcode:
, ändere dann den
nil
Delphi-Quellcode:
und setze
ItemIndex
Delphi-Quellcode:
wieder zurück?
onClick
Ich habe schon gesehen, wie Leute die Tag-Property dafür benutzt haben, um zwischen "eigener" Änderung und Veranlassung durch den Benutzer zu unterscheiden, aber das erscheint mir irgendwie nicht richtig... |
AW: on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Ich mache das meistens so, dass im jeweiligen Formular eine globale boolsche Variable existiert. Die wird abgefragt wenn ein OnClick oder sonstwas ausgeführt wird. Bei Operationen, die keine Eventhandler auslösen sollen, wird die Variable vorher gesetzt und am Ende der Operation wieder zurückgesetzt.
|
AW: on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Zitat:
[edit] Oder evtl. ein ![]() ![]() |
AW: on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Ich versuche alles so zu designen, dass der Fall gar nicht eintritt, d.h. so, dass die Eventhandler auch nur das machen, was eine Folge der Auswahl ist. Und diese direkte Folge benötige ich dann auch, wenn ich den Wert per Quelltext selbst setze.
Ansonsten benutze ich auch private Felder um das zu steuern, da man anders als bei Verwendung von Tag dafür auch am Variablennamen sieht was der tut. Wer Tag dafür benutzt gehört geteert und gefedert. ;-) Das OnClick temporär zu entfernen halte ich auch nicht für sauber, da man dann in dem OnClick gar nichts davon merkt, dass es nicht immer greift und sich später vielleicht mal tot debuggt... das sollte schon auch dort unterschieden werden. |
AW: on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Danke für die Antworten :thumb:
Zitat:
Mein konkretes Beispiel:
Ich könnte einen "Änderungen absenden"-Button (oder so ähnlich machen). Oder damit leben, dass beim Setzen der TRadioGroup etwas so gesetzt wird, wie es schon ist. Oder den onEvent-Handler kurzzeitig ausklinken. Diese drei Möglichkeiten sehe ich :| |
AW: on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Ich umgehen das Problem meistens mit einem Integer-Property, bei dem ich im Setter nur dann etwas mache, wenn es sich ändert.
Nehmen wir z.B. ein einfaches Form mit einer RadioGroup und einem Label. Die Pas-Datei sieht dann so aus:
Delphi-Quellcode:
type
TForm238 = class(TForm) RadioGroup1: TRadioGroup; Label1: TLabel; procedure FormCreate(Sender: TObject); procedure RadioGroup1Click(Sender: TObject); private FSelectedIndex: Integer; procedure SetSelectedIndex(const Value: Integer); public property SelectedIndex: Integer read FSelectedIndex write SetSelectedIndex; end; ... procedure TForm238.FormCreate(Sender: TObject); begin FSelectedIndex := RadioGroup1.ItemIndex; end; procedure TForm238.RadioGroup1Click(Sender: TObject); begin SelectedIndex := RadioGroup1.ItemIndex; end; procedure TForm238.SetSelectedIndex(const Value: Integer); begin if FSelectedIndex <> Value then begin FSelectedIndex := Value; Label1.Caption := RadioGroup1.Items[FSelectedIndex]; RadioGroup1.ItemIndex := FSelectedIndex; end; end; |
AW: on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Das hatte ich natürlich zuallererst gemacht :-) - Erst schauen, ob ich es denn überhaupt erst ändern muss. Aber es bleibt ja immer noch der Fall dass
|
AW: on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Gerade schnell ausprobiert:
Delphi-Quellcode:
Aaaaaber: das geht dann an der Logik der Radiogroup komplett vorbei, d.h. der ItemIndex wird nicht aktualisiert usw.
procedure TFormTest.Button1Click(Sender: TObject);
var OldIndex: integer; begin OldIndex := Radiogroup1.ItemIndex; if OldIndex >= 0 then SendMessage(Radiogroup1.Buttons[OldIndex].Handle, BM_SETCHECK, BST_UNCHECKED, 0); SendMessage(Radiogroup1.Buttons[1].Handle, BM_SETCHECK, BST_CHECKED, 0); end; |
AW: on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Zitat:
|
AW: on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Ich halte das gesamte Thema für einen riesigen dicken Design-Fehler in der VCL. Solche Dinge müssen ein OnChange auslösen, aber um Himmels Willen doch kein OnClick! Wer sich auch immer was dabei gedacht hat. Die netten Endlosschleifchen, die man sich durch Ändern einer zunächst nicht unbedingt Klick-Relevanten Property in diversen Controls auf diese Weise einhandelt, stehen in keinem Verhältnis zu dem geringen Aufwand (eben ein Methodenaufruf mehr), wenn dann doch mit einer Änderung aus dem Programm heraus Dinge passieren sollen, die sonst nur beim echten Click stattfinden sollen. Über diesen Unfug ist bestimmt fast jeder angehende Delphianer nach spätestens 1 Jahr gestolpert.
Ich mache es bei Events, die gerade mal nicht feuern sollen bei dem was da kommt, halt wirklich dann einfach so, dass ich den Handler zwischen speicher, meinen Kram mache, und nachher wieder zurück. Mit ein wenig Resourcenschutzblöcken kann man zumindest auch dann noch verhindern, dass einem Exceptions ein Control ohne Event-Handler hinterlassen. |
AW: on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Um auch mal meinen Mist dazu zu geben, obwohl schon alles gesagt ist
Zitat:
"in der Logik"
Delphi-Quellcode:
"in der GUI"
//Feststellen, dass etwas in der GUI geändert werden muss
GUI.DoNotTriggerEvents := True; //Änderungen in der GUI vornehmen GUI.DoNotTriggerEvents := False;
Delphi-Quellcode:
private
FDoNotTriggerEvents : Boolean; public property DoNotTriggerEvents ... [...] if Assigned(OnRadioGroupClick) and (not FDoNotTriggerEvents) then OnRadioGroupClick(...); |
AW: on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Ich persönlich glaube, das diese Problematik nur dann* auftritt, wenn man das VM-Muster (Viewmodel) nicht umsetzt.
Wegen der -bei korrektem Design- 1:1 Zuordnung von VM-Property und GUI-Control sollte bzw. muß dann imho jede Änderung des Controlzustandes (z.B. Setzen vom ItemIndex) die entsprechende Kaskade von OnXXXX-Ereignisaufrufen nach sich ziehen. Zitat:
Delphi-Quellcode:
Einzige Ausnahme: Eine Double-Property verweigert gerne einmal den Endlosschleifenshowstopper
Procedure TMyViewModel.SetMyProperty (Const Value : TSomeType)
begin if Value = MyProperty Then exit; fMyProperty := Value; RaiseOnChaingeMyPropertyEvent; end;
Delphi-Quellcode:
wegen den bekannten Double-Gleichheits-Problematiken.
If Value = MyValue then Exit
Wie gesagt: Man kann sämtliche Fallstricke und Performancebremsen durch saubere Programmierung des Viewmodels eliminieren, meiner Meinung nach. Zitat:
Besser:
Delphi-Quellcode:
Man sollte i.A. auf Flags à la 'NotXXX' verzichten, weil das Hirn beim Lesen mit solchen Verneinungen meist nicht so gut klar kommt. Hier ist das allerdings ok, denn das Flag definiert die Ausnahme von der Regel. Vielleicht wäre jedoch 'SurpressTrigger' ein besserer Name (gleiche Bedeutung, keine Verneinung).
if Assigned(OnRadioGroupClick) and FTriggerEvents then // Logik umkehren
OnRadioGroupClick(...); // Oder if FDoNotTriggerEvents then exit; // Lesbarkeit erhöhen if Assigned(OnRadioGroupClick) then OnRadioGroupClick(...); |
AW: on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Zitat:
|
AW: on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Zitat:
|
AW: on[XYZ]-Methoden: Nicht aufrufen wenn Programmcode die Komponente ändert
Zitat:
Delphi-Quellcode:
und nicht
If Value=fMyProperty then...
Delphi-Quellcode:
, deshalb also der explizite Hinweis. Ich hätte den Hinweis auch auf Objekte erweitern können, aber das habe ich mir geschenkt. Da bei Double-Werten jedoch hin und wieder noch die Frage aufkommt, wieso '=' nicht funktioniert, habe ich das dann kurz und knapp angerissen. Bei Erwähnung von 'SameValue' hätte ich ausholen müssen, bei Weglassen meines knappen Zusatzes wäre ein ganz Schlauer auf die Idee gekommen, mich auf die Double-Problematik hinzuweisen, also habe ich wirklich gedacht, der kurze Hinweis reicht. Tut er wohl nicht.
If SameValue(fMyProperty,Value) then...
Zitat:
Oder meinst Du mit 'VCL-Entwicklern' Entwickler, die mit der VCL entwickeln? Wenn Sie unter deiner Leitung arbeiten, dann chleudere die Purchen su Poden. Arbeiten sie nicht mit/für Dich, dann... Pech gehabt und weiter den linken Schuh ausziehen (aka den Messias spielen). Leider gibt es hier in der DP kein Dojo, wo man sich mit solchen Implementierungen auseinandersetzen und robuste Pattern entwickeln kann. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:56 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