AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte Data Binding
Thema durchsuchen
Ansicht
Themen-Optionen

Data Binding

Ein Thema von Stevie · begonnen am 28. Apr 2011 · letzter Beitrag vom 28. Apr 2017
 
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.039 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#1

Data Binding

  Alt 28. Apr 2011, 22:49
Wer schon mit .Net zu tun hatte, wird sie kennen und schätzen gelernt haben: Data Bindings.
Man kann dort nahezu alles aneinander binden. Sei es, um Listen von Objekten in Trees, Lists oder Grids darzustellen oder Eigenschaften von Objekten in Text-, Check- oder Comboboxen editierbar zu machen.
Oder sogar die Sichtbarkeit oder das Aussehen einzelner Controls zu beinflussen.

Wie das genau funktioniert, kann man in der MSDN nachlesen.

Ja und? In Delphi gibts DataSet, DataSource und diverse datensensitive Controls, um das zu bewerkstelligen!
Richtig, die Sache hat nur einen Haken: Man kann nicht einfach ein 08/15 Objekt daran hängen. Sicher, es gibt TSnapObjectDataset oder spezielle Controls, mit denen man das machen kann. Hat aber den entscheidenden Nachteil, dass man immer entweder besondere Controls oder Komponenten haben muss oder seine bindbaren Objekte von einer Basisklasse ableiten muss.

Ich hab mir mal einige Dinge von der .Net Implementierung abgeschaut und das ganze in Delphi mit folgenden Zielsetzung nachgebaut:
  • Standard Komponenten und Controls müssen unterstützt werden (z.B. TEdit)
  • wenig bis keine extra Implementierung für bindbare Objekte
  • minimaler Sourcecode, um Objekte aneinander zu binden

Ok, fangen wir an. Was brauchen wir?

Ein Binding braucht immer eine Source und ein Target (beides ein Objekt) und die Namen der zu bindenden Eigenschaften.
Für unser erstes Beispiel bauen wir uns eine einfache Klasse, die 2 Eigenschaften hat:

Delphi-Quellcode:
type
  TSettings = class
  private
    FCaption: string;
    FColor: TColor;
    procedure SetCaption(const Value: string);
    procedure SetColor(const Value: TColor);
  public
    property Caption: string read FCaption write SetCaption;
    property Color: TColor read FColor write SetColor;
  end;

implementation

procedure TSettings.SetCaption(const Value: string);
begin
  FCaption := Value;
end;

procedure TSettings.SetColor(const Value: TColor);
begin
  FColor := Value;
end;
Wir haben hier schonmal explizite Setter Methoden - die brauchen wir später noch. Aber für das erste Beispiel würde auch in direkter Zugriff auf die Feldvariable genügen.

So, was machen wir nun mit unserem TSettings Objekt? Wir erzeugen 2 Bindings, die auf den Titel und die Farbe unserer MainForm gehen.

Delphi-Quellcode:
procedure TMainForm.FormCreate(Sender: TObject);
begin
  FSettings := TSettings.Create;
  FSettings.Caption := 'Binding demo';
  FSettings.Color := clGray;
  TBinding.Create(FSettings, 'Caption', MainForm, 'Caption');
  TBinding.Create(FSettings, 'Color', MainForm, 'Color');
end;
Dazu genügt es, die Unit System.Bindings einzubinden. Auch um das Freigeben der Binding Objekte braucht man sich nicht kümmern solange mindestens eins der beiden verbundenen Objekte von TComponent abgeleitet ist (in unserem Fall ist es das MainForm).

Starten wir die Anwendung und sehen, was passiert. Titel und Farbe des MainForms ist entsprechend der Werte aus unserem TSettings Objekts gesetzt worden. Toll, oder?
Naja, da hätts auch das explizite Zuweisen der Werte getan... Klar, aber der eigentliche Clou der Bindings kommt erst noch!

Packen wir mal einen Button auf die Form und setzen dort die Eigenschaft unseres Settings Objekts:

Delphi-Quellcode:
procedure TMainForm.Button1Click(Sender: TObject);
begin
  FSettings.Caption := 'Current time: ' + DateTimeToStr(Now);
end;
Da tut sich erstmal nix, aber wir sind auch noch nicht fertig. Gehen wir zurück zu unserer TSettings Klasse und passen sie etwas an.
Wir leiten sie mal von einem Basis Objekt ab, welches ein Interface implementiert - und zwar INotifyPropertyChanged. Auch das ist wieder brav von .Net abgekupfert.
Aha, nun brauchen wir also unsere Setter Methoden für die Eigenschaften.

So sieht unserer modifizierte Klasse nun aus:

Delphi-Quellcode:
type
  TSettings = class(TPropertyChangedBase)
  private
    FCaption: string;
    FColor: TColor;
    procedure SetCaption(const Value: string);
    procedure SetColor(const Value: TColor);
  public
    property Caption: string read FCaption write SetCaption;
    property Color: TColor read FColor write SetColor;
  end;

implementation

procedure TSettings.SetCaption(const Value: string);
begin
  FCaption := Value;
  DoPropertyChanged('Caption');
end;

procedure TSettings.SetColor(const Value: TColor);
begin
  FColor := Value;
  DoPropertyChanged('Color');
end;
Tadaa, und auf Knopfdruck wird nun auch der Titel unserer MainForm geändert. Naja, ganz putzig, aber so richtig rocken tut's noch nicht, oder?

Na gut, werfen wir mal ein TEdit auf die Form und binden es ebenfalls im Konstruktor des MainForms an die Caption Eigenschaft unseres TSettings Objekts:

Delphi-Quellcode:
...
TBinding.Create(FSettings, 'Caption', Edit3, 'Text');
Toll, nun steht der Titel des Forms auch im Edit drin... und wenn ich dort drin änder passiert nix!
Stimmt, es fehlt noch was. Als letzte Unit (genauer gesagt nach den Units, in denen die Controls drin sind, an die ich binden möchte) im uses des Interface Teils des Forms muss die Unit System.Bindings.Controls.
Dort befinden sich einige Ableitungen von Standard VCL Controls mit dem gleichen Namen, welche das INotifyPropertyChanged Interface implementieren. Und dadurch, dass sie als letzte (oder zumindest nach den entsprechenden Units steht) werden beim Erstellen des Forms Objekte von den abgeleiteten Klassen erstellt. Das heißt im Klartext, es müssen keine speziellen Controls oder Komponenten auf der Form verbaut werden, damit man das Data Binding nutzen kann.

Starten wir mal die Anwendung und tippern ein wenig im Edit rum. Wow, der Titel des Forms ändert sich!

Um es nochmal zu betonen:
  • keine speziellen Controls nötig (nur das Subclassing von Controls, die man Binding fähig machen möchte)
  • keine speziellen Events nötig
  • als read-once Source können direkte Ableitungen von TObject benutzt werden (lediglich für die Benachrichtigung von Eigenschaftsänderungen ist das Interface nötig)
  • minimaler Sourcecode, um Objekte, Komponenten und Controls zu verbinden.

Im angehangenden Beispiel sind noch einige weitere Bindings und Controls auf der Form, mit welchen man einige Eigenschaften verändern kann.
Das ganze wurde unter Delphi XE entwickelt. Delphi 2010 könnte auch funktionieren, aber da waren die Generics noch ein wenig verbuggt. Alle Versionen darunter sind leider nicht unterstützt. Das liegt am regen Gebrauch von Generics und neuer RTTI.

Außerdem findet ihr in den benötigten Units noch weitere Dinge wie zum Beispiel Multicast Events oder den NotificationHandler, der dafür zuständig ist, dass die TBinding Objekte ohne Zutun freigegeben werden.

In Planung und teilweise schon realisiert sind Bindings für Listen in dementsprechenden Controls (z.B. ListBox)

Anregungen, Kritik und Fragen sind herzlich willkommen und sehr erwünscht.


P.S.: Crosspost bei Delphi-Forum

Update 18.06.2011:
  • Source der Library aktualisiert (enthält den kompletten Code meiner DSharp Library)
  • aktuelle Samples für data binding hinzugefügt

Update 10.04.2012:
  • veraltete Archive entfernt (aktuelle und supportete Version im svn Repository)
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie (10. Apr 2012 um 20:05 Uhr) Grund: Anhang von späteren Beitrag angehängt
  Mit Zitat antworten Zitat
 


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 03:00 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 by Thomas Breitkreuz