1

上下文:Visual Studo 2012/C# 5.0

我有一个带有三个文本框控件的 .NET Windows 窗体:firstNameTextBoxlastNameTextBoxageTextBox,以及一个简单的自定义类

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

我想将客户自定义类的实例的属性绑定到我的 Windows 窗体控件。所以我写:

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"));
}

这很好用。然后我通过使用匿名类型稍微更改代码:

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"));

}

这也很有效,尽管在这种情况下我只有单向绑定。然后我进一步更改我的代码:

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"));
}

我收到运行时错误:

'无法绑定到 DataSource 上的属性或列 FirstName。参数名称:dataMember'

问题:如何将具有一组动态自定义属性的 System.Dynamic.ExpandoObject(或 System.Dynamic.DynamicObject)实例绑定到 Windows 窗体(文本框)控件集?

注 1:具有聚合/容器辅助类的解决方案对我来说是可以的。

注意 2:我花了几个小时在谷歌上搜索并尝试应用不同的技术(包括我在 StackOverflow 上找到的技术),但我失败了。

这是基于 Hans Passant 提示的“优雅”解决方案:

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);
}
4

1 回答 1

3

数据绑定使用反射,它在 ExpandoObject 上效果不佳,因为它的“属性”实际上不是底层对象的属性。ExpandoObject 实现 IDictionary,但只能轻松绑定到列表控件,如 ListBox。

这并非完全不可能,您必须显式实现 Binding.Format 和 Parse 事件。像这样:

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);

这行得通,但当然不会获得任何优雅分数。

于 2013-03-13T03:25:32.987 回答