DelegateBinder – DataBinding mit Datenmanipulation

Geschrieben von Andi

Ich hatte mal irgendwann vor längerer Zeit die Idee, eine Klasse zu programmieren, mit der ich einfache GUI-Logik leicht implementieren kann, ohne unnötigen Code schreiben zu müssen. Ziel war es, Dinge wie z.B. “Aktiviere einen Button nur, wenn eine gültige/vorhandene Datei in einer TextBox eingegeben wurde” oder “Deaktiviere andere Controls, wenn eine CheckBox angehakt ist” und sonstige kleine Spielereien die man dann und wann in der GUI-Programmierung braucht, zu vereinfachen.
Bisher musste ich sowas immer auf die Weise erledigen, dass ich (im Falle des ersten Beispiels) eine Methode programmiert habe, die über die File.Exists-Methode geprüft hat, ob der String in der TextBox auf eine gültige Datei verweist. Anschließend musste ich das TextChanged-Ereignis an die Methode hängen, damit die Prüfung erneut ausgeführt wird, wenn der Benutzer den Text ändert. Das funktioniert zwar und ist nicht allzu schwer in der Umsetzung, der Designer nimmt einem den nervigen Event-Kram ja ab, aber was ich bei dieser Lösung unschön finde, ist, für einen Einzeiler extra eine Methode schreiben zu müssen. Also hab ich mich hingesetzt und mir eine Lösung überlegt, und rausgekommen ist der DelegateBinder.

Vorab schon einmal der C#-Code der Klasse:

using System;
using System.ComponentModel;
using System.Windows.Forms;

[ToolboxItem(false)]
public class DelegateBinder : Control
{
    public delegate object BindingDelegate(object value);

    private BindingDelegate _bindingDelegate;
    private object _bindingProperty;

    public object BindingProperty
    {
        get { return _bindingProperty; }
        set { _bindingProperty = _bindingDelegate(value); }
    }

    private DelegateBinder(BindingDelegate bindingDelegate)
    {
        _bindingDelegate = bindingDelegate;
    }

    public static void Bind(BindingDelegate bindingDelegate, Control target, string propertyName, object dataSource, string dataMember)
    {
        if (bindingDelegate == null)
            throw new ArgumentNullException("bindingDelegate");

        if (target == null)
            throw new ArgumentNullException("target");

        if (dataSource == null)
            throw new ArgumentNullException("dataSource");

        var binder = new DelegateBinder(bindingDelegate);
        target.Controls.Add(binder);
        binder.DataBindings.Add("BindingProperty", dataSource, dataMember);
        target.DataBindings.Add(propertyName, binder, "BindingProperty");
    }
}

Funktionsweise
Die Klasse DelegateBinder hat eine statische Methode Bind, die als Parameter einen Delegaten – der einen Object-Parameter erwartet und ein Object zurückgibt – und eine Referenz auf das Zielobjekt (das Control, dem das Binding hinzugefügt werden soll) empfängt. Weiterhin übergibt man der Bind-Methode wie beim normalen DataBinding-Konstruktor die Parameter für propertyName, dataSource und dataMember.
Der Trick bei dieser ganzen Sache ist nun folgender: In der Bind-Methode wird ein neues DelegateBinder-Objekt erzeugt. Das Objekt hat eine Eigenschaft BindingProperty, an welche ich den Member der DataSource (also die Eigenschaft des Objekts, von dem die Daten kommen) binde. Nun dreh ich den Spieß um und binde die BindingProperty dieses Objekts an das Ziel-Objekt, das die (veränderten) Daten enthält. Das eigentliche Konvertieren/Bearbeiten der Daten erfolgt durch den Delegaten, den man der Bind-Methode übergibt. Dieser wird im Setter der BindingProperty aufgerufen, also immer dann, wenn sich die Daten vom Control (oder welches Objekt auch immer) geändert haben. In dem Moment, in dem nun der Wert der Eigenschaft BindingProperty geändert wird, schlägt das DataBinding des eigentlichen Ziel-Controls/Objekts zu, das ja an das DelegateBinder-Objekt gebunden ist und erhält den nun geänderten Wert. Die eigentliche Datenmanipulation findet daher über den “Zwischenmann” statt, der zwischen der DataSource und dem eigentlichen Target zwischengeschaltet ist.

Anwendung
Die Beispiele von oben würde man folgendermaßen umsetzen:

DelegateBinder.Bind(x => File.Exists((string)x), button1, "Enabled", textBox1, "Text");
DelegateBinder.Bind(x => !(bool)x, textBox2, "Enabled", checkBox1, "Checked");
DelegateBinder.Bind(x => !(bool)x, listView1, "Enabled", checkBox1, "Checked");

Im angehängten Beispielprojekt sieht man das ganze in einem WinForms-Projekt in Aktion.

DelegateBinderSampleProject


 
 
 

2 Kommentare zu “DelegateBinder – DataBinding mit Datenmanipulation”

  1. Michael
    16. März 2010 um 12:49

    Welches angehängte Beispielprojekt?

  2. Andi
    17. März 2010 um 17:30

    Das war natürlich nur ein Test, ob hier überhaupt jemand mitliest. ;)

    Habe das Beispielprojekt nachgereicht. :)

Kommentar abgeben:

o_O >_< ;P ;) :zombie: :yawn: :upset: :ups: :thx: :rotwerd: :roll: :paranoid: :omfg: :ohmygod: :lol: :hm: :heul: :gnah: :evillaugh: :evileye: :eek: :cries: :crazy: :confused: :aww: :XD: :P :D :) :(

*