head.WriteLine()

Dienstag, März 09, 2010

TT.DOM: Datenbindung

Wie hier bereits erwähnt, unterstützt Thinktecture.DataObjectModel (TT.DOM) die Entwicklung flexibler Datenklassen. In den folgenden Posts werde ich die wichtigsten Features des Frameworks vorstellen. Den Anfang mache ich mit dem Thema Datenbindung.
Damit ein Objekt optimal an die Oberfläche gebunden werden kann, sollte die entsprechende Klasse eine Reihe von Interfaces implementieren. Über diese kommuniziert die Datenbindungsinfrastruktur mit den gebundenen Objekten um z.B. Synchronisation, Transaktionssteuerung oder Eingabevalidierung zu realisieren. Die folgende Abbildung zeigt diese Kommunikation:
Neumann_Datenklassen2
  • INotifyPropertyChanged dient zur Synchronisation zwischen Datenquelle und Ziel. Auf diese Weise werden Änderungen, die programmatisch an den Objekten durchgeführt werden, an das gebundene Steuerelement gemeldet, sodass dieses die Anzeige entsprechend aktualisieren kann.
  • INotifyPropertyChanging dient zur Signalisierung von Änderungen, bevor diese durchgeführt werden. Dies Interface hat keine direkten Auswirkungen für die Bindung, ist jedoch für Change Tracking und Transaktionssteuerung wichtig.
  • IEditableObject stellt ein transaktionales Verhalten für die Datenbindung bereit. So können Sie beispielsweise mehrere Zellen in einem Grid geändert und per ESC wieder zurück gerollt werden.
  • IDataErrorInfo ist für die clientseitige Validierung zuständig. So kann der Benutzer bereits während der Eingabe auf fehlerhafte Werte aufmerksam gemacht werden.
Wie Sie sehen, gibt es eine Menge zu tun um eine Datenklassen für die Datenbindung zu optimieren.
Hier kommt TT.DOM ins Spiel. Es definiert die abstrakte Basisklasse DataObject, welche die oben genannten Interfaces implementiert. Sie können nun Ihre Datenklassen von DataObject ableiten und haben fast automatisch die entsprechenden Funktionalitäten. Das Einzige was Sie tun müssen, ist Änderungen an Ihren Properties an die Basisklasse zu melden.
public class Person : DataObject
{
  private string _name;
  public string Name
  {
    get { return _name; }
    set

      {
      base.OnPropertyChanging("Name");
      _name = value;
      base.OnPropertyChanged(“Name”); }
  }
}

Wollen Sie zusätzlich Validierungsregeln im Stile von IDataErrorInfo in der Datenklasse hinterlegen, überschreiben Sie zusätzlich den Indexer der Basisklasse und hinterlegen die Validierungsregeln nach folgendem Muster.
public class Person : DataObject
{
  ...
  public override string this[string columnName]
  {
    get
    {
      if ((columnName == "" || columnName == "Name") &&
          string.IsNullOrEmpty(this.FirstName))
      {
        return "\"Name\" ist ein Pflichtfeld!";
      }
      return string.Empty;
    }
  }
}

Auf diese Weise haben Sie Ihre Klasse ohne viel Aufwand mit Synchronisation, Transaktionssteuerung und Eingabevalidierung ausgestattet.
Wie Sie später noch sehen werden, bietet TT.DOM auch die Möglichkeit die Validierungsregeln programmatisch zur Laufzeit zu hinterlegen.

Listenbindung

Auch auf Listenebene müssen Sie für eine Synchronisation zwischen Datenquelle und Ziel sorgen. In Windows Forms und WPF können Sie hierfür das Interface IBindingList bzw. dessen Standardimplementierung BindingList<T> verwenden. Darüber hinaus stellt TT.DOM die Klasse DataObjectList<T> bereit. Diese leitet von BindingList<T> ab und stellt neben der Datenbindungsfunktionalität Einiges mehr zu Verfügung.
Um das Erstellen und Befüllen von DataObjectList<T> zu vereinfachen, stellt TT.DOM die Extension Method .ToDataObjectList() zu Verfügung. Sie kann auf alle Listen vom Typ IEnumerable angewendet werden.
List<Person> persons = service.GetPersons();
var list = persons.ToDataObjectList("Id");

Als Parameter wird der oder die Eigenschaften angegeben, die ein Objekt eindeutig identifizieren. Dies ist für eine spätere Synchronisation mit einem Middle Tier-Service notwendig, doch dazu  mehr in einem separaten Post ;)

Labels: