Laden...

DelegateBinder: DataBinding mit Übergabe eines Delegaten zur Datenmanipulation

Erstellt von userid12529 vor 14 Jahren Letzter Beitrag vor 14 Jahren 4.607 Views
U
userid12529 Themenstarter:in
208 Beiträge seit 2008
vor 14 Jahren
DelegateBinder: DataBinding mit Übergabe eines Delegaten zur Datenmanipulation

Vorwort:
Angeregt durch den Thread DataBinding: bool Wert invertieren, in dem der Threadersteller nach einem einfachen Weg fragt, einen Bool-Wert zu invertieren und an den geänderten Wert zu binden, hatte ich mich gefragt, ob man das nicht irgendwie über Lambda-Expression lösen könnte. So entstand dann die Idee des DelegateBinder.

Beschreibung:
Die Klasse DelegateBinder hat eine überladene 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, dataMember usw.

Die DelegateBinder-Klasse:

using System;
using System.Windows.Forms;

[System.ComponentModel.ToolboxItem(false)]
public class DelegateBinder : Control
{
    public delegate object Del(object value);
    private Del del;

    private object bindingProperty;
    public object BindingProperty
    {
        get { return bindingProperty; }
        set { bindingProperty = del(value); }
    }

    private DelegateBinder(Del del)
    {
        this.del = del;
    }

    public static void Bind(Del del, Control target, string propertyName, object dataSource, string dataMember)
    {
        Bind(del, target, propertyName, dataSource, dataMember, false, DataSourceUpdateMode.OnValidation, null, string.Empty, null);
    }

    public static void Bind(Del del, Control target, string propertyName, object dataSource, string dataMember, bool formattingEnabled)
    {
        Bind(del, target, propertyName, dataSource, dataMember, formattingEnabled, DataSourceUpdateMode.OnValidation, null, string.Empty, null);
    }

    public static void Bind(Del del, Control target, string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode)
    {
        Bind(del, target, propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, null, string.Empty, null);
    }

    public static void Bind(Del del, Control target, string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue)
    {
        Bind(del, target, propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, nullValue, string.Empty, null);
    }

    public static void Bind(Del del, Control target, string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString)
    {
        Bind(del, target, propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, nullValue, formatString, null);
    }

    public static void Bind(Del del, Control target, string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString, IFormatProvider formatInfo)
    {
        if (del == null)
            throw new ArgumentNullException("del");

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

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

        DelegateBinder delegateBinder = new DelegateBinder(del);
        delegateBinder.DataBindings.Add("BindingProperty", dataSource, dataMember);
        target.Controls.Add(delegateBinder);
        target.DataBindings.Add(propertyName, delegateBinder, "BindingProperty", formattingEnabled, dataSourceUpdateMode, nullValue, formatString, formatInfo);
    }
}

Beispielprojekt:
Im Angang gibts noch ein kleines Beispielprojekt, das verdeutlicht, was der DelegateBinder ermöglicht (benötigt aufgrund der Verwendung von Lambda Expressions .NET 3.5).

Update 26.07:
Die Bind-Methode wurde so geändert, dass sie kein Binding-Objekt mehr zurück gibt, sondern das Binding dem Target-Control selbst hinzufügt. Dadurch spart man sich ein bisschen Code beim Hinzufügen von Bindings und ich kann sicher gehen, dass das übergebene Target-Control auch das Control ist, dass das Binding erhält. (Beispielprojekt wurde ebenfalls aktualisiert.)

Update 05.08:
Beispielprojekt im Anhang aktualisiert.

Schlagwörter: DataBinding, Delegate, Lambda, Lambda Expression, Windows Forms

5.299 Beiträge seit 2008
vor 14 Jahren

Interessante Variante

Schade, dass du nirgends erläuterst, wies eiglich funzt.
Aber gräme dich nicht allzusehr darob - das machen eh die wenigsten (und jetzt weißichnich, welchen Smiley nehmen: 😉 oder 😜 ).

Stattdessen verbreiter ichmichmal, was ich denke, wies funzt:
Du erzeugst ein neues (Dummy-)Control mit einer Property, an die man alles binden kann. Der Setter der Property ruft den als Delegat übergebenen Converter auf, sodass der Getter nicht das zurückgibt, was der Setter settet, sondern den konvertierten Wert.
(Dassis eiglich eine schlimmer Verstoß gegen Design-Richtlinien, sone Property zu createn, aber hier zielführende Absicht. Das mit dem Verstoß erwähne ich nur, dass hofflich niemand je auf die Idee kommt, auch anderswo solche Properties einzusetzen)
An diese "konvertierende Allround-Property" des DummyControl bindest du die gegebene Datasource.
Zum Schluß erstellst du ein Binding, nicht an die eiglich angegebene DataSource, sondern die konvertierte Property des DummyControls wird als DataSource hergenommen.
Das DummyControl selbst hängste einfach in die ControlCollection des target-Controls (an welches eiglich gebunden werden sollte), damit nicht der GarbageCollector auf die Idee kommt, es wegzuräumen. Auch kümmert sich die ControlCollection löblicherweise ums disposen des DummiControls.

Ich trete das so breit, damit klar ist, dasses ressourcenmäßig eine ziemlich teure technik ist, das muss einem klar sein.
Ist auch nicht so wild, man wirds ja eh nur vereinzelt einsetzen.

Hier nochn Vorschlag, wiededie Verwendung noch vereinfachen kannst, nämlich indemde nicht nur das Binding zurückgibst, sondern das target auch gleich dran-bindest. Dann könnte der Aufruf zB. so aussehen:


         DelegateBinder.Bind(x => !(bool)x, sampleCheckBox, "Checked", sampleObject, "BoolProperty");
         //sampleCheckBox.DataBindings.Add(DelegateBinder.Bind(x => !(bool)x,
         //                                sampleCheckBox, "Checked", sampleObject, "BoolProperty"));

wäre also nurnoch eine statische Methode.

WPF hat glaub das standardmäßig, dass beim Databinding Converter zwischengeschaltet werden können.

Ich hab sowas ähnliches mal verzapft, aber in VB.Net, und auf einer niederen Ebene (also was ein Binding-Objekt so treibt, händisch geproggt). Kannstejamalgugge: PropertyNotifying

Der frühe Apfel fängt den Wurm.

U
userid12529 Themenstarter:in
208 Beiträge seit 2008
vor 14 Jahren

Hallo ErfinderDesRades,

Schade, dass du nirgends erläuterst, wies eiglich funzt.
Aber gräme dich nicht allzusehr darob - das machen eh die wenigsten (und jetzt weißichnich, welchen Smiley nehmen: 😉 oder 😜 ).

Ja da hast du Recht... Ich dachte aber dass der Code an sich nicht so komplex ist und leicht verständlich. Aber gut du hast natürlich Recht, besser wär's wenn ich's gemacht hätte, der Wissensstand der Leute geht hier ja teilweise sehr stark auseinander.

Stattdessen verbreiter ichmichmal, was ich denke, wies funzt:
Du erzeugst ein neues (Dummy-)Control mit einer Property, an die man alles binden kann. Der Setter der Property ruft den als Delegat übergebenen Converter auf, sodass der Getter nicht das zurückgibt, was der Setter settet, sondern den konvertierten Wert.
(Dassis eiglich eine schlimmer Verstoß gegen Design-Richtlinien, sone Property zu createn, aber hier zielführende Absicht. Das mit dem Verstoß erwähne ich nur, dass hofflich niemand je auf die Idee kommt, auch anderswo solche Properties einzusetzen)
An diese "konvertierende Allround-Property" des DummyControl bindest du die gegebene Datasource.
Zum Schluß erstellst du ein Binding, nicht an die eiglich angegebene DataSource, sondern die konvertierte Property des DummyControls wird als DataSource hergenommen.
Das DummyControl selbst hängste einfach in die ControlCollection des target-Controls (an welches eiglich gebunden werden sollte), damit nicht der GarbageCollector auf die Idee kommt, es wegzuräumen. Auch kümmert sich die ControlCollection löblicherweise ums disposen des DummiControls.

Genau so ist es gedacht/funktioniert es, gute Zusammenfassung. 😉

Ich trete das so breit, damit klar ist, dasses ressourcenmäßig eine ziemlich teure technik ist, das muss einem klar sein.
Ist auch nicht so wild, man wirds ja eh nur vereinzelt einsetzen.

Auch da hast du Recht (:P). Aber du sagst es ja selbst, so richtig ins Gewicht fallen wird es wohl in den wenigsten Fällen.

Hier nochn Vorschlag, wiededie Verwendung noch vereinfachen kannst, nämlich indemde nicht nur das Binding zurückgibst, sondern das target auch gleich dran-bindest. Dann könnte der Aufruf zB. so aussehen:

  
         DelegateBinder.Bind(x => !(bool)x, sampleCheckBox, "Checked", sampleObject, "BoolProperty");  
         //sampleCheckBox.DataBindings.Add(DelegateBinder.Bind(x => !(bool)x,  
         //                                sampleCheckBox, "Checked", sampleObject, "BoolProperty"));  
  

wäre also nurnoch eine statische Methode.

Genau diese Idee hatte ich auch, als ich noch eine Nacht drüber geschlafen hab, und auch sofort umgesetzt und den Beitrag aktualisiert (siehe Update 26.07 im ersten Post). Leider hatte herbivore (oder ein anderer Admin/Moderator, weiß ich nicht) das Beispielprojekt als Dateianhang hinzugefügt (war vorher ein Hyperlink) und dabei ist wohl noch das alte Projekt dringeblieben, was ich gar nicht bemerkt hatte. Ich hab das Beispielprojekt mal aktualisiert.

WPF hat glaub das standardmäßig, dass beim Databinding Converter zwischengeschaltet werden können.

Gut zu wissen. Mit WPF werde ich mich über kurz oder lang ohnehin beschäftigen müssen. 🙂

Ich hab sowas ähnliches mal verzapft, aber in VB.Net, und auf einer niederen Ebene (also was ein Binding-Objekt so treibt, händisch geproggt). Kannstejamalgugge:
>

Danke, werde ich mir auf jeden Fall auch mal anschauen! Meine ersten Realisierungsversuche der Idee gingen übrigens auch in die Richtung, das DataBinding händisch nachzuprogrammieren, bin dann aber letztlich daran gescheitert... Vielleicht werd ich ja aus deinem Code schlau. =)

Danke für deine Antwort und die Erläuterungen und Ideen.