문제

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