1

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);
}
asked Mar 13, 2013 at 2:24

1 Answer 1

3

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.

answered Mar 13, 2013 at 3:25

3 Comments

Actually your solution works well for me and it can be made elegant. Thanks a lot!
Hans, I have just posted solution based on your hint above, in the bottom part of my question body text. Thank you.
Hans, please have a look I have used your hint in C# 5.0 'Universal' WinForms TextBox Text 'Two-Way' Binder 'StackOverflow note'. Please comment on it if you find it interesting. Thank you.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.