Context: Visual Studo 2012/C# 5.0

I have a .NET Windows Form with three textbox controls: firstNameTextBox, lastNameTextBox and ageTextBox, and a simple custom class

public class Customer
{
 public string FirstName { get; set; }
 public string LastName { get; set; }
 public int Age { get; set; }
}

and I'd like to bind the properties of an instance of Customer custom class to my Windows Forms controls. So I write:

private dynamic _customer;
private void Form_Load(object sender, EventArgs e)
{
    _customer = new Customer()
    {
        FirstName = "Andrew",
        LastName = "Chandler",
        Age = 23
    };
    this.firstNameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text",     _customer, "FirstName"));
    this.lastNameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text", _customer, "LastName"));
    this.ageTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text", _customer, "Age"));
}

and that works well. Then I slightly change the code by making it using an anonymous type:

private dynamic _customer;
private void Form_Load(object sender, EventArgs e)
{
    _customer = new 
    {
        FirstName = "Andrew",
        LastName = "Chandler",
        Age = 23
    };
    this.firstNameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text", _customer, "FirstName"));
    this.lastNameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text", _customer, "LastName"));
    this.ageTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text", _customer, "Age"));

}

and that also works rather well, although in this case I do have only one-way binding. Then I change my code even more:

private dynamic _customer;
private void Form_Load(object sender, EventArgs e)
{   
    _customer = new ExpandoObject();
    _customer.FirstName = "Andrew";
    _customer.LastName = "Chandler";
    _customer.Age = 23;

     this.firstNameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text", _customer, "FirstName"));
     this.lastNameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text", _customer, "LastName"));
     this.ageTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text", _customer, "Age"));
}

and I'm getting runtime error:

'Cannot bind to the property or column FirstName on the DataSource. Parameter name: dataMember'

Question: How can I bind an instance of System.Dynamic.ExpandoObject (or System.Dynamic.DynamicObject) having a set of dynamic custom properties to a Windows Forms set of (textbox) controls?

Note 1: A solution with an aggregating/container helper class would be OK for me.

Note 2: I have spent a few hours googling and trying to apply different techniques (including the ones I have found here on StackOverflow) but I have failed.

Here is an 'Elegant' solution based on Hans Passant hint:

private dynamic _customer;
private void Form_Load(object sender, EventArgs e)
{
    _customer = new ExpandoObject();
    _customer.FirstName = "Andrew";
    _customer.LastName = "Chandler";
    _customer.Age = 23;

    bindExpandoField(this, "FirstNameTextBox", "Text", _customer, "FirstName");
    bindExpandoField(this, "lastNameTextBox", "Text", _customer, "LastName");
    bindExpandoField(this, "ageTextBox", "Text", _customer, "Age");
}


private void bindExpandoField(
      Control hostControl,
      string targetControlName,
      string targetPropertyName,
      dynamic expandoObject,
      string sourcePropertyName)
{
    Control targetControl = hostControl.Controls[targetControlName];
    var IDict = (IDictionary<string, object>)expandoObject;
    var bind = new Binding(targetPropertyName, expandoObject, null);
    bind.Format += (o, c) => c.Value = IDict[sourcePropertyName];
    bind.Parse += (o, c) => IDict[sourcePropertyName] = c.Value;
    targetControl.DataBindings.Add(bind);
}
有帮助吗?

解决方案

Data binding uses Reflection, that works poorly on ExpandoObject since its "properties" are not actually properties on the underlying object. ExpandoObject implements IDictionary but that only binds easily on a list control, like ListBox.

It is not entirely impossible, you have to explicitly implement the Binding.Format and Parse events. Like this:

dynamic bag = new ExpandoObject();
bag.foo = "bar";
var bind = new Binding("Text", bag, null);
bind.Format += (o, c) => c.Value = bag.foo;
bind.Parse += (o, c) => bag.foo = c.Value;
textBox1.DataBindings.Add(bind);

That works, but of course doesn't score any elegance points.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top