Einzelnen Beitrag anzeigen

Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#10

AW: Trennung von Darstellung und Daten, Prinzipfrage konkret

  Alt 30. Mai 2011, 17:12
Ich würde der „Datenklasse“ (unten „Item“) sowie der Klasse „Test“ einfach ein Event OnChanged respektive OnItemChanged (oder so ähnlich) verpassen. „Test“ registriert automatisch für alle seine Items den OnChanged-Handler, und leitet die dort „abgefangenen“ Events dann über OnItemChanged nach außen weiter.
Delphi-Quellcode:
type
  TItem = class
  protected
    FOnChanged: TNotifyEvent;
    procedure SetValue(const AValue: integer);
  public
    property Value: integer read FValue write SetValue;
    property OnChanged: TNotifyEvent read FOnChanged write FOnChanged;
  end;

  // Typensichere Objektliste, oder unter neueren Versionen TList<Item>
  TItemList = class(TObjectList) {…} end;

  TOnItemChanged = procedure (Sender: TObject; Item: TItem) of object;

  TTest = class
  protected
    FList: TItemList;
    FOnItemChanged: TOnItemChanged;
    procedure HandleItemChanged(Sender: TObject);
  public
    property OnItemChanged: TOnItemChanged read FOnItemChanged write FOnItemChanged;
    property List: TItemList read FList;
    procedure LoadData;
  end;

implementation

procedure TItem.SetValue(const AValue: integer);
begin
  FValue := AValue;
  if Assigned(OnChanged) then
    OnChanged(self);
end;

procedure TTest.HandleItemChanged(Sender: TObject);
begin
  { …eventuell noch selbst irgendwas tun?… }
  if Assigned(OnItemChanged) then
    OnItemChanged(self, Sender as TItem);
end;

procedure TTest.LoadData;
var
  i: integer;
  function MakeItem(Value: integer): TItem
  begin
    Result := TItem.Create;
    // wichtig:
    Result.OnChanged := HandleItemChanged;
    Result.Value := Value;
  end;
begin
  for i := 0 to 42 do
    FList.Add(MakeItem(i));
end;
Delphi-Quellcode:
type
  TMyForm = class(TForm)
    {…}
    Listview: TListView;
  protected
    FTest: TTest;
    procedure HandleItemChanged(Sender: TObject; Item: TItem);
  end;

implementation

procedure HandleItemChanged(Sender: TObject; Item: TItem);
begin
  { … Listview neuzeichnen (bzw. nur das jeweilige Item) … }
end;

procedure TMyForm.FormCreate({…})
begin
  FTest := TTest.Create;
  FTest.OnItemChanged := HandleItemChanged;
end;
Das Beispiel habe ich hier nur eben hier im Beitragseditor runtergeschrieben. Es gibt natürlich noch ein paar Dinge, die man in einer echten Anwendung sauberer lösen könnte/müsste (z.B. sollte TItemList irgendein Ereignis bereitstellen, wenn neue Items hinzugefügt werden, damit deren OnChanged-Handler gleich automatisch belegt werden kann), aber es geht hier ja nur um das grobe Prinzip...

Wenn das GUI an mehreren Stellen gleichzeitig aktualisiert werden muss, musst du statt Events das Observer-Pattern implementieren (*hust* deshalb wären Multicast-Events toll *hust*).

Geändert von Namenloser (30. Mai 2011 um 17:16 Uhr)
  Mit Zitat antworten Zitat