WinForms Binding-Fehler während der Kompilierung erkennen / Bindings refaktorisierbar machen

Written on August 08, 2010

Bei der WinForms-Entwicklung werden Bindings wie folgt definiert:

public interface IPersonViewModel { 
    string Name { get; set; } 
}

public partial class Form1 : Form, IPersonView { 
    private IPersonViewModel _viewModel;

    public void BindToViewModel(IPersonViewModel viewModel) { 
        _viewModel = viewModel; 

        Binding binding = new Binding(“Text”, _viewModel, “Name”);
        nameTextBox.Bindings.Add(binding);
    }
}

Das ganze funktioniert soweit problemlos.

Allerdings gibt es zwei "Schönheitsfehler":

  1. Hat man Tippfehler im Namen der Property (hier "Text") oder im Namen des DataMembers (hier "Name"), fällt das erst zur Laufzeit infolge einer Exception auf

  2. Refaktorisiert man das Model, bekommt das Binding davon nichts mit -- Resultat: siehe 1.

Mithilfe der folgenden ExtensionMethod kann man beide Probleme elegant umschiffen:

public static void SetBinding<TModel>(this Control control, Control childControl, 
                        Expression<Func<Control, object>> property, TModel model, 
                        Expression<Func<TModel, object>> dataMember) {

    Expression propertyBody = property.Body; 
    Expression dataMemberBody = dataMember.Body;

    if (ExpressionType.MemberAccess == propertyBody.NodeType && ExpressionType.MemberAccess == dataMemberBody.NodeType) { 
          MemberExpression propertyMemberExpression = propertyBody as MemberExpression; 
        MemberExpression dataMemberExpression = dataMemberBody as MemberExpression;

        Binding binding = new Binding(propertyMemberExpression.Member.Name, model, dataMemberExpression.Member.Name); 
        childControl.DataBindings.Add(binding); 
    } 

    if (ExpressionType.MemberAccess == propertyBody.NodeType && ExpressionType.Convert == dataMemberBody.NodeType) {

        MemberExpression propertyMemberExpression = propertyBody as MemberExpression;
        UnaryExpression unaryExpression = dataMemberBody as UnaryExpression;

        MemberExpression dataMemberExpression = unaryExpression.Operand as MemberExpression;

        Binding binding = new Binding(propertyMemberExpression.Member.Name, model, dataMemberExpression.Member.Name);
        childControl.DataBindings.Add(binding);
    }
}

Aufruf innerhalb der Form oder eines UserControls:

this.SetBinding<IPersonViewModel>(nameTextBox, textbox => textbox.Text, _viewModel, model => model.Name);

DotNetKicks-DE Image