head.WriteLine()

Montag, Oktober 02, 2006

Entwurfszeit-Attribute, Teil 4: Data Binding

War es in .NET 1.x relativ schwer die eigenen Komponenten und Geschäftsobjekte datenbindungsfähig zu machen, so ist dies in .NET 2.0 schon fast ein Kinderspiel.

Objektdatenquellen
Vielleicht wollen Sie Ihre Geschäftsobjekte zur Entwurfszeit an eine Oberfläche binden, wie sie dies von typisierten Datasets kennen. Hierzu erstellen Sie eine Klasse und versehen sie mit entsprechenden Eigenschaften.
Beispiel:

public class Person
{
    private string m_firstName;
    private string m_lastName;

    public Person() {}

    public string FirstName
    {
        get { return m_firstName; }
        set { m_firstName = value; }
    }

    public string LastName
    {
        get { return m_lastName; }
        set { m_lastName = value; }
    }
}

Jetzt bietet Ihnen Visual Studio 2005 über das neue Data Source Window die Möglichkeit, basierend auf einer Datenquelle eine entsprechende Oberfläche zu erstellen und diese zu binden. Hierzu erstellen Sie mit dem zugehörigen Wizard zunächst eine neue Datenquelle. Hierbei geben Sie als Datenquellentyp "Object Source" an und wählen die Person-Klasse aus. Wenn Sie nun den entsprechenden Eintrag aus dem Data Source Window auf eine Form ziehen, werden - je nach Einstellung - entweder ein Grid oder entsprechende Formularfelder eingefügt. Hierbei werden die Spaltentitel anhand der Eigenschaftennamen gewählt. Sollen hierbei jedoch nicht die meist englischen Eigenschaftennamen, sondern beispielsweise die entsprechenden deutschen Bezeichner verwendet werden, so können Sie dies über die Deklaration des DisplayName-Attributs in Ihrer Datenklasse steuern. Beispiel:

[DisplayName("Vorname")]
public string FirstName
{
    get { return m_firstName; }
    set { m_firstName = value; }
}

[DisplayName("Nachname")]
public string LastName
{
    get { return m_lastName; }
    set { m_lastName = value; }
}

Steuerelemente bindungsfähig machen
Um nun Ihre eigenen Steuerelemente bindungsfähig zu machen, ist im Idealfall keine Zusatzarbeit notwendig. Der Grund hierfür ist, dass die Control-Klasse das IBindingComponent-Interface implementiert, über das die entsprechenden Bindungsinformationen bereitgestellt werden. Wenn Sie nun direkt oder indirekt von Control ableiten und lediglich einen einzelnen Wert anzeigen, ist keine Zusatzarbeit notwenig.

Anders sieht es jedoch aus, wenn Ihr Steuerelement mehrere Werte oder Datenzeilen anzeigen soll. In diesem Fall müssen Sie entsprechende Eigenschaften für die Datenquelle bereitstellen.
  • DataSource
  • DataMember
  • DisplayMember
  • ValueMember
Die letzten beiden benötigen Sie jedoch nur, wenn Sie beispielsweise eine ComboBox oder ähnliches implementieren und hierbei auf zwei Datenquellen zugreifen wollen.

Um nun ein ähnliches Entwurfszeitverhalten für die Eigenschaften zu bieten, wie Sie dies beispielsweise vom DataGridView kennen, sollten Sie die folgenden Attribute notieren:

[RefreshProperties(RefreshProperties.Repaint)]
[AttributeProvider(typeof(IListSource))]
[DefaultValue(null)]
public object DataSource
{

}

[Editor("System.Windows.Forms.Design.DataMemberListEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
public string DataMember
{

}

Über die Bedeutung dieser Attribute finden Sie in einem älteren Blog-Eintrag mehr.

Unterstützung für das Data Source Window implementieren
Jetzt wäre es ja schön, wenn auch Ihr Steuerelement als Option im Data Source Window erscheinen und per Drag & Drop auf eine Form gebracht und gebunden werden könnte. Hierfür dekorieren Sie Ihre Steuerelementklasse - je nach Typ - mit den folgenden Attributen:
  • DefaultBindingProperty
  • ComplexBindingProperties
  • LookupBindingProperties
DefaultBindingProperty verwenden Sie, wenn Ihr Steuerelement lediglich einen einzelnen Wert abbildet. Hierbei verweist es auf die zu bindendene Eigenschaft. Beispiel:

[DefaultBindingProperty("Text")]

ComplexBindingProperties ist hingegen für die komplexe Bindung, sprich mehrere Werte bzw. Datenzeilen. Es verweist auf die Eigenschaften DataSource und DataMember.

[ComplexBindingProperties("DataSource", "DataMember")]

Bei ComboBox und co. verweist LookupBindingProperties auf die entsprechenden Eigenschaften der Wert- bzw. Lookup-Datenquelle.

[LookupBindingProperties(
"DataSource", "DisplayMember", "ValueMember", "LookupMember")]