AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

Ein Thema von norwegen60 · begonnen am 3. Apr 2021 · letzter Beitrag vom 5. Apr 2021
Antwort Antwort
Seite 2 von 2     12
norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
504 Beiträge
 
Delphi 12 Athens
 
#11

AW: Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

  Alt 4. Apr 2021, 08:53
Gestern war ich ja mal richtig optimistisch, dass ich da bald zu einer Lösung kommme, aber der Optimismus schwindet.
Vielleicht liegt es ja an Delphi XE
Das Positive: Mit dem neuen Konstrukt funktioniert es zunächst mal einwandfrei
  • Zugriff auf lNamen[i].Namen ist möglich
  • FChanged der Liste wird gesetzt sobald ich lNamen[i].Namen ändere

Dann aber die Fehler
1. Sobald ich das Programm Schließe, kommt weiterhin der EAccessViolation. Ohne TBaseObjectList<T>.Destructor gleich beim lNamenListFree, mit Destructor nach dem OnClose
2. Das Abfangen, ob lNamen Mitglied einer Liste, funktioniert nicht. Auch wenn ich FParentProject explizit auf NIL setze, geht er in den Message-Block
Delphi-Quellcode:
constructor TBase.Create;
begin
  FParentObject := nil;
end;

procedure TBase.SetChanged(const Value: Boolean);
var
  msg: TDispatchMessage;
begin
  if FChanged <> Value then
  begin
    FChanged := Value;
    if Value and (FParentObject <> nil) then // Geht in den Block auch wenn FParentObject = NIL
    begin
      msg.MsgID := cNotifyChanged;
      FParentObject.Dispatch(msg);
    end;
  end;
end;
3. Ganz seltsam wird es dann in folgenden Blöcken
Delphi-Quellcode:
procedure TForm15.btCreateListClick(Sender: TObject);
// *****************************************************************************************************************************************
// Simuliert Erstellung neuer Einträge
var
  i: Integer;
  lNamen: TNamen;
begin
  if (lNamenList = nil) then
    lNamenList := TNamenList.Create;

  for i := 0 to 5 do
  begin
    lNamen.Create;
    lNamenList.Add(lNamen);
    lNamen.ParentObject := lNamenList;
    lNamen.Namen := Format('Name%d', [i]);
    lNamen.Changed := False;
  end;
  lNamenList.Changed := False;

  laChanged.Caption := Format('lNamenList Count = %d, Changed = %d', [lNamenList.Count, Integer(lNamenList.Changed)]);
end;

procedure TForm15.btNameOnlyClick(Sender: TObject);
// *****************************************************************************************************************************************
// Simuliert StandAlone-Klasse, d.h. nicht in einer Liste
var
  lNamen: TNamen;
begin
  lNamen.Create;
  try
    lNamen.Namen := 'NameOnly';
  finally
    lNamen.Free;
  end;
end;

procedure TForm15.btNewNameClick(Sender: TObject);
// *****************************************************************************************************************************************
// Simuliert Hinzufügen eines Namens
var
  lNamen: TNamen;
begin
  lNamen.Create;
  lNamenList.Add(lNamen);
  lNamen.ParentObject := lNamenList;
  lNamen.Namen := Format('Name%d', [lNamenList.Count + 1]);

  laChanged.Caption := Format('lNamenList Count = %d, Changed = %d', [lNamenList.Count, Integer(lNamenList.Changed)]);
end;
  • btCreateListClick funktioniert einwandfrei auch bei mehrfachem Aufruf
  • btNameOnlyClick und btNewNameClick führen zu einem EAccessViolation in TNamen.Create. Dabei ist btNewNameClick doch genau gleich wie btCreateListClick mit dem einzigen Unterschied dass einmal 1 und einmal 6 neue Daten erstellt und in Liste eingefügt werden
Angehängte Dateien
Dateityp: 7z Source.7z (5,4 KB, 4x aufgerufen)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
10.926 Beiträge
 
Delphi 12 Athens
 
#12

AW: Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

  Alt 4. Apr 2021, 11:35
Wie lange programmierst du nun schon in Delphi und dann kommt immer noch sowas dabei heraus
Delphi-Quellcode:
var
  lNamen: TNamen;
begin
  lNamen.Create;
  try
    lNamen.Namen := 'NameOnly';
  finally
    lNamen.Free;
  end;
end;
Es heißt lNamen := TNamen.Create !!!!
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
504 Beiträge
 
Delphi 12 Athens
 
#13

AW: Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

  Alt 4. Apr 2021, 12:20
Oh Shit. Natürlich heißt es lNamen:= TNamen.Create; .
Ein kompletter Leichtsinnsfehler. Wunderlich, dass es in der For Schleife trotzdem funktioniert. Und danach per Copy&Paste weiterverbreitet.

Und schon funktioniert alles wie gewünscht.

Vielen Dank
  Mit Zitat antworten Zitat
norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
504 Beiträge
 
Delphi 12 Athens
 
#14

AW: Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

  Alt 4. Apr 2021, 13:21
Also zuerst noch mal vielen Dank. Damit kann ich die bestehende Klassenstruktur demnächst mal um einiges vereinfachen.

An einer Stelle hänge ich aber noch:
Wie kann ich erkennen dass das ParentObject meine TBaseObjectList ist? In meinem Konstrukt kann ParentObject die TBaseObjectList sein. Es könnte aber auch eine von TBase abgeleitete Klasse sein, eine unabhängige Klasse oder NIL

Kein Problem mit NIL und den "normalen" Klassen, aber die Typprüfung nach der Liste klappt nicht.

Folgendes läuft zwar, aber mir wäre es lieber, ich würde die Message wirklich nur an meine TBaseObjectList schicken
Delphi-Quellcode:
procedure TBase.SetChanged(const Value: Boolean);
var
  msg: TDispatchMessage;
begin
  if FChanged <> Value then
  begin
    FChanged := Value;
    if Value then
    begin
      if (FParentObject is TBase) then
        TBase(FParentObject).Changed := Value
      // else if (FParentObject is TObjectList<TBase>) then // funktioniert nicht, d.h. geht auch bei TObjectList nicht in den Block
      else if (FParentObject <> nil) then
      begin
        msg.MsgID := cNotifyChanged;
        FParentObject.Dispatch(msg);
      end;
    end;
  end;
end;
Das mit dem Dispatch war übrigens ein super Hinweis dessen Verwendung ich bisher gar nicht kannte.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
10.926 Beiträge
 
Delphi 12 Athens
 
#15

AW: Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

  Alt 4. Apr 2021, 14:14
ich würde die Message wirklich nur an meine TBaseObjectList schicken
Die Idee hinter der Message ist ja gerade, dass der Sender nicht weiß, ob und wie diese Message vom Empfänger behandelt wird. Die Default-Implementierung in TObject macht einfach gar nichts. Solange also deine alternativen ParentObject-Instanzen keine Message mit der Message-ID cNotifyChanged implementieren kannst du den Aufruf ruhig auf alles loslassen.

Der Grund für diesen Ansatz war ja gerade der, dass es keine brauchbare Möglichkeit gibt, zu prüfen ob ParentObject ein generische TBaseObjectList<T> ist oder nicht. Das war doch das eigentliche Problem in dem Eingangspost.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
504 Beiträge
 
Delphi 12 Athens
 
#16

AW: Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

  Alt 4. Apr 2021, 17:16
Alles klar.

Mein Hauptproblem war zuerst mal überhaupt eine BaseObjectList zu erzeugen die die Standardproperties enthält.
Ich war mir nicht sicher, ob das Senden der Message an alle nicht noch irgenwelche Zusatzlasten erzeugt

In dem Fall ist mein Problem vollumfänglich gelöst. Für mich eine sehr lehrreiche Lektion.
Vielen Dank für deine Geduld. Du bist einfach Spitze.
  Mit Zitat antworten Zitat
generic

Registriert seit: 24. Mär 2004
Ort: bei Hannover
2.415 Beiträge
 
Delphi XE5 Professional
 
#17

AW: Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

  Alt 5. Apr 2021, 16:07
Ich schmeiße hier mal eine andere Möglichkeit in den Raum.

Wenn ich programmiere, dann versuche ich nach SOLID zu programmieren.
Daher versuche ich meine Geschäftsobjekte nicht für andere Dinge zu erweitern.

"single responsibility principle"

Die Änderungserkennung ist für mich ein andere Geschäftsvorgang, weil dieses wird ggf. auch nicht in überall benötigt.

Meine Änderungserkennung ist mit den RTTI und Attributen umgesetzt:
https://youtu.be/pvi7-c6tGMo

Die Attribute müsste man in deinem Fall nicht einmal benutzen.

Alternativ zu meiner Umsetzung, werfe ich auch das Pattern UnitOfWork in den Raum.
Den Setter zu nutzen, halte ich allerdings für eine gute Lösung.
Man könnte alternativ einfach über einen BUS und ein Ereignis, die Änderung "global" zur Verfügung stellen.
Ha! - Video Idee - ich wollte sowieso mal den Delphi-BUS zeigen.


Die "Liste", welche du haben möchtest, hab ich auch umgesetzt. Es hat mir einfach zu stark in den Fingern gejuckt.
Das Video muss ich allerdings noch schneiden. Der Teil hatte kein Platz mehr in dem ersten, weil ich versuche zwischen 10-15 Minuten zu bleiben.
Ich denke das Video lade ich bis nächsten Montag in den Kanal.
Coding BOTT - Video Tutorials rund um das Programmieren - https://www.youtube.com/@codingbott
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:06 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz