Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi TListView, OnChanging-Event wird mehrmals aufgerufen (https://www.delphipraxis.net/60243-tlistview-onchanging-event-wird-mehrmals-aufgerufen.html)

jgehlen 4. Jan 2006 13:37


TListView, OnChanging-Event wird mehrmals aufgerufen
 
Hi,

ich habe das Problem, dass das OnChanging-Event eines TListView mehrmals (3-4 mal, leider scheinbar nicht konstant) aufgerufen wird.

Ausgangssituation:
Ich will im OnChanging-Event eine Abfrage (MessageDlg) implementieren, ob der Eintrag, der verlassen werden soll gespeichert (Ja), nicht gespeichert (Nein) oder wieder zu diesem Eintrag zurückgekehrt werden soll (Abbrechen). Bei 'Abbrechen' setze ich AllowChange auf False.

Code:
Delphi-Quellcode:
 
procedure TForm1.ListView1Changing(Sender: TObject; Item: TListItem;
  Change: TItemChange; var AllowChange: Boolean);
begin
  AllowChange := True;
  // CheckBox1.Checked wird hier nur las Flag verwendet, ob sich in dem Eintrag etwas gändert hat
  If (Change = ctState) and CheckBox1.Checked then begin
    case MessageDlg('Änderungen speichern?',mtCustom,[mbYes,mbNo,mbCancel],0) of
      mrYes: begin
        // Speichern ...
        CheckBox1.Checked := False;
      end;
      mrNo: begin
        CheckBox1.Checked := False;
      end;
    else
      AllowChange := False;
    end;
  end;
Problem:
Da das das OnChanging-Event mehrmals durchlaufen wird wird bei der Auswahl von 'Abbrechen' im Dialog der Dialog bis zu vier mal angezeigt. Sehr unschön :( .

Irgendwer eine Idee?

Gruß
Jörg Gehlen

Lannes 4. Jan 2006 15:37

Re: TListView, OnChanging-Event wird mehrmals aufgerufen
 
Hallo,

nehme an das durch Aufruf des Dialogs erneut onChanging ausgelöst wird.
Wenn Du Die Checkbox in dem Else-Zweig der case-Anweisung auf False setzt,
dürfte der Dialog eigentlich nicht erneut aufgerufen werden.

Wie werden denn die Änderungen an der ListView durchgeführt?
Wenn nur die Caption geändert wird,
dann ist das Ereignis OnEdited ein besserer Ansatzpunkt.

jgehlen 4. Jan 2006 16:03

Re: TListView, OnChanging-Event wird mehrmals aufgerufen
 
Hallo,

Zitat:

Zitat von Lannes
nehme an das durch Aufruf des Dialogs erneut onChanging ausgelöst wird.
Wenn Du Die Checkbox in dem Else-Zweig der case-Anweisung auf False setzt,
dürfte der Dialog eigentlich nicht erneut aufgerufen werden.

Die Checkbox ist hier nur zur Vereinfachung aufgeführt. Würde ich die Checkbox im Else-Zweig auf false setzen, würde der Dialog auch nicht mehr angezeigt werden, wenn ich direkt danach wieder auf einen anderen Eintrag des ListView klicke.

Zitat:

Zitat von Lannes
Wie werden denn die Änderungen an der ListView durchgeführt?
Wenn nur die Caption geändert wird,
dann ist das Ereignis OnEdited ein besserer Ansatzpunkt.

Die Änderungen werden nicht im ListView vorgenommen, sondern das ListView dient nur zur Auswahl eines Eintrages, dessen Einstellungen dann aus einer Datenbank ausgelesen werden. Deshalb hilft mir das OnEdited-Event hier nicht weiter.

Zusammengefasst will ich folgendes Verhalten erreichen:
- Über das ListView wird ein Eintrag ausgewählt, die zugehörigen Daten werden geladen und ausserhalb des Listview dargestellt und auch dort editiert.
- Sind die Daten geändert worden und wird ein anderer Eintrag in dem ListView angeklickt, soll der Dialog ('Änderungen speichern?') erscheinen:
-> 'Ja'-Button: Daten werden gespeichert, neuer Eintrag wird selektiert, zugehörige Daten werden geladen
-> 'Nein'-Button: Daten werden nicht gespeichert, neuer Eintrag wird selektiert, zugehörige Daten werden geladen
-> 'Abbrechen'-Button: Momentan geladene und veränderte Daten werden nichrt verändert, der bisherig selektierte Eintrag bleibt im ListView selektiert

Gruß
Jörg Gehlen

Muetze1 4. Jan 2006 16:44

Re: TListView, OnChanging-Event wird mehrmals aufgerufen
 
Beachte auch, das das Event nochmals aufgerufen wird, wenn das neue Item selektiert wird, mit dem neuen Item wohlgemerkt...

jgehlen 4. Jan 2006 18:42

Re: TListView, OnChanging-Event wird mehrmals aufgerufen
 
Zitat:

Zitat von Muetze1
Beachte auch, das das Event nochmals aufgerufen wird, wenn das neue Item selektiert wird, mit dem neuen Item wohlgemerkt...

Wenn AllowChange := False dann wird das OnChanging-Event nur für den aktuell selektierten Eintrag ausgeführt (mehrmals :( ), und nicht für den "angeklickten" Eintrag.

Gruß
Jörg Gehlen

Muetze1 4. Jan 2006 21:02

Re: TListView, OnChanging-Event wird mehrmals aufgerufen
 
Zitat:

Zitat von jgehlen
Zitat:

Zitat von Muetze1
Beachte auch, das das Event nochmals aufgerufen wird, wenn das neue Item selektiert wird, mit dem neuen Item wohlgemerkt...

Wenn AllowChange := False dann wird das OnChanging-Event nur für den aktuell selektierten Eintrag ausgeführt (mehrmals :( ), und nicht für den "angeklickten" Eintrag.

Gruß
Jörg Gehlen

Das war eine allgemeine Bemerkung, und wenn du als Sonderbehandlung AllowChange auf False setzt, dann wird dein aktueller Eintrag erneut markiert und danach selektiert.

Lannes 4. Jan 2006 22:39

Re: TListView, OnChanging-Event wird mehrmals aufgerufen
 
Hallo,

anderer Vorschlag:
Bei z.B. Editfelder und auch andere Komponenten kann man im OnExit-Ereignis mit
ActiveControl die Komponente ermitteln die den Focus bekommen wird.
Klickt man nun in die ListView wird das Ereignis OnExit des Editfeldes vor dem Ereignis OnChanging der ListView ausgelöst.
Also die Speichern [Ja - Nein - Abbrechen]-Abfrage
ins OnExit des Edits integrieren und ein Flag fürs OnChanging-Ereignis der ListView setzen.

Im nachfolgenden Beispiel wird ListView.Tag als Flag genutzt:
Delphi-Quellcode:
procedure TForm1.Edit1Exit(Sender: TObject);
begin
  if ActiveControl = ListView1 then
    case MessageDlg('Änderungen speichern?',mtCustom,[mbYes,mbNo,mbCancel],0) of
      mrYes:    begin
                 Caption := 'Speichern';
                 ListView1.Tag := 0;
                 end;
      mrNo:     begin
                 Caption := 'Nicht Speichern';
                 ListView1.Tag := 0;
                 end;
      mrCancel: begin
                 Caption := 'Abgebrochen';
                 ActiveControl := Edit1;
                 ListView1.Tag := 1;
                 end;
    end;
end;

procedure TForm1.ListView1Changing(Sender: TObject; Item: TListItem;
  Change: TItemChange; var AllowChange: Boolean);
begin
  if ListView1.Tag = 1 then
    AllowChange := False
    else
    AllowChange := True;
end;

jgehlen 5. Jan 2006 13:00

Re: TListView, OnChanging-Event wird mehrmals aufgerufen
 
Hallo,

danke für den Tip , manchmal sieht man den Wald vor lauter Bäumen nicht ..

Zitat:

Zitat von Lannes
Bei z.B. Editfelder und auch andere Komponenten kann man im OnExit-Ereignis mit
ActiveControl die Komponente ermitteln die den Focus bekommen wird.
Klickt man nun in die ListView wird das Ereignis OnExit des Editfeldes vor dem Ereignis OnChanging der ListView ausgelöst.

Ich werde aber statt eines OnExit-Events das OnEnter-Event des ListView verwenden, macht in meiner Anwendung mehr Sinn (das ListView kann von vielen verschieden Controls aus angewählt werden).

Trotzdem ist das ganze doch nur ein Workaround, das eigentliche Problem, das mehrmalige Aufrufen des OnChanging-Events besteht weiterhin.

Gruß
Jörg Gehlen

Lannes 5. Jan 2006 13:26

Re: TListView, OnChanging-Event wird mehrmals aufgerufen
 
hallo,
Zitat:

Zitat von jgehlen
Trotzdem ist das ganze doch nur ein Workaround, das eigentliche Problem, das mehrmalige Aufrufen des OnChanging-Events besteht weiterhin.

das sehe ich anders.
Das Problem des mehrmaligen Aufrufs entsteht durch den Aufruf des Dialogs innerhalb der Ereignis-Behandlungs-Routine, da gehört der Dialog-Aufruf IMHO nicht hin. :wink:

jgehlen 5. Jan 2006 13:52

Re: TListView, OnChanging-Event wird mehrmals aufgerufen
 
Hallo,

Zitat:

Zitat von Lannes
Das Problem des mehrmaligen Aufrufs entsteht durch den Aufruf des Dialogs innerhalb der Ereignis-Behandlungs-Routine, da gehört der Dialog-Aufruf IMHO nicht hin. :wink:

Dem kann nicht so richtig folgen:
- Das Event wird auch ohne Dialog-Aufruf mehrmals aufgerufen (3 oder 4 mal).

Auch kann nicht erkennen warum der Dialog-Aufruf nicht in das OnChanging-Event gehört, ein OnExit- oder OnEnter-Event dafür aber okay sind. Meiner Ansicht nach ist gerade das OnChanging-Event (alleine vom Namen her) der richtige Platz zum Prüfen, ob man die Änderung wirklich vornehmen will.

Ich versuch nur zu verstehen ... :gruebel:

Gruß
Jörg Gehlen

marabu 5. Jan 2006 14:12

Re: TListView, OnChanging-Event wird mehrmals aufgerufen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Jörg.

Der mehrfache Eintritt in das Ereignis OnChanging() ist völlig korrekt. Durch deinen Dialog wird wegen dem Fokus Shift ein zusätzliches OnChanging() ausgelöst. Ohne deinen Dialog werden jeweils drei OnChange() und OnChanging() Ereignisse ausgelöst.

Abgesehen davon, dass ich grundsätzlich mit einer virtuellen ListView und einem modalen Bearbeitungs-Dialog arbeite, würde ich in deinem Fall anders vorgehen und dem Benutzer die Kontrolle über die Speicherung ganz überlassen. Siehe Demo.

Neujahrsgrüße vom marabu

jgehlen 5. Jan 2006 14:59

Re: TListView, OnChanging-Event wird mehrmals aufgerufen
 
Hallo,

Zitat:

Zitat von marabu
Der mehrfache Eintritt in das Ereignis OnChanging() ist völlig korrekt. Durch deinen Dialog wird wegen dem Fokus Shift ein zusätzliches OnChanging() ausgelöst. Ohne deinen Dialog werden jeweils drei OnChange() und OnChanging() Ereignisse ausgelöst.

Danke für die Aufklärung. Kommt der mehrfache Eintritt in das Ereignis OnChanging() dadurch, dass bei ctState die Eigenschaften Cut, Focused oder Selected nacheinander gepüft werden? Wenn ja, gibt es dann auch die Möglichkeit diese einzelnen Änderungen getrennt voneinander zu erlauben oder zu verbieten?

Zitat:

Zitat von marabu
Abgesehen davon, dass ich grundsätzlich mit einer virtuellen ListView und einem modalen Bearbeitungs-Dialog arbeite, würde ich in deinem Fall anders vorgehen und dem Benutzer die Kontrolle über die Speicherung ganz überlassen. Siehe Demo.

Der Workflow den Du vorschlägst entspricht leider nicht so ganz den Anforderungen in der Anwendung, deshalb werde ich wohl bei der Variante 'Dialog im OnEnter-Event des ListView' bleiben müssen.

Gruß
Jörg Gehlen

marabu 5. Jan 2006 15:44

Re: TListView, OnChanging-Event wird mehrmals aufgerufen
 
Zitat:

Zitat von jgehlen
Kommt der mehrfache Eintritt in das Ereignis OnChanging() dadurch, dass bei ctState die Eigenschaften Cut, Focused oder Selected nacheinander gepüft werden?

Zuerst wird dem fokusierten Item der Fokus entzogen. Beim zweiten Eintritt verliert dieses Item gerade die Selektion. Beim dritten und normalerweise letzten Eintritt wird (vermutlich) der Fokus auf das neue Item übertragen.

Zitat:

Zitat von jgehlen
gibt es dann auch die Möglichkeit diese einzelnen Änderungen getrennt voneinander zu erlauben oder zu verbieten?

Im Ereignis OnChanging()? Warum nicht? Du hast die Eigenschaften ListView.Selected und ListView.ItemFocused, sowie die Informationen aus deinem event handler. Damit kannst du leicht bestimmen, welche Aktion du unterbindest.

Zitat:

Zitat von jgehlen
Der Workflow den Du vorschlägst entspricht leider nicht so ganz den Anforderungen in der Anwendung, deshalb werde ich wohl bei der Variante 'Dialog im OnEnter-Event des ListView' bleiben müssen.

Wenn eine Änderung der Benutzerschnittstelle in deinen Augen sinnvoll ist, dann solltest du versuchen den Auftraggeber bzw. Projektleiter davon zu überzeugen.

Freundliche Grüße

marabu

jgehlen 5. Jan 2006 18:24

Re: TListView, OnChanging-Event wird mehrmals aufgerufen
 
Hallo,

Zitat:

Zitat von marabu
Wenn eine Änderung der Benutzerschnittstelle in deinen Augen sinnvoll ist, dann solltest du versuchen den Auftraggeber bzw. Projektleiter davon zu überzeugen.

Der Workflow ist okay für mich, ich will den Benutzer nicht zu sehr in einen Ablauf zwingen, sondern möglichst viele Freiheiten lassen. Vergleichbar Word, dort muss man ein Dokument auch nicht erst speichern bevor man es über das 'x'-BorderIcon schließen kann. Dann wird eben an dieser Stelle nachgefragt, ob gespeichert, verworfen oder zum Dokument zurückgekehrt werden soll. Aber das ist hier doch zu sehr Off-Topic.

Trotzdem möchte ich allen :hi: hier nochmals danken. Dies ist meine erste Frage bei Delphi-PRAXIS und ich bin sehr angetan von der schnellen und kompetenten Hilfe.

Gruß
Jörg Gehlen


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:21 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