1

首先,我想谈谈普通绑定(带有标准属性,例如文本框的文本)。这里的示例网格只有 2 行(为简单起见)。假设我有一个包含 2 列(ID 和名称)的 2 行表 (myDataTable)、一个 DataGridView (myGrid) 和一个 TextBox (myTextBox)。下面是绑定数据的代码:

myGrid.DataSource = myDataTable;
myTextBox.DataBindings.Add("Text", myDataTable, "Name");

绑定数据后,当网格中的选择发生变化时,信息会自动更新到控件TextBox中,例如2行是:

ID       |       Name
1                .NET
2                Java

一开始,grid 中的选择在索引 0,myTextBox 的 Text 是“.NET”,将选择移动到下一个位置(在索引 1),myTextBox 的 Text 是“Java”,一次又一次地移动,向前和向后,它可以按我的预期工作。但是现在我有一个带有一个名为 List 的自定义属性的控件,这是 List 的类型并且是只读的。我想将它绑定到表的列(例如,名称),我执行相同的绑定规则,但是在更新到数据源(myDataTable)之前添加一点自定义解析以格式化正确的字符串,因为我的自定义属性是类型列出我的名称列是字符串类型,这是绑定代码:

Binding bind = new Binding("List", myDataTable, "Name"){
   ControlUpdateMode = ControlUpdateMode.Never //Because my List property is readonly
};
//formating string data before updating to the datasource
bind.Parse += (s,e) => {
  List<string> data = (List<string>) e.Value;
  if(data.Count == 0) e.Value = DBNull.Value;
  else e.Value = string.Join(",",data.ToArray());//format as comma separated string
};
myCustomControl.DataBindings.Add(bind);

在这种情况下,假设 myDataTable 当前在 Name 列中没有数据,如下所示:

ID      |      Name
1           <DBNull.Value>   <--- current index
2           <DBNull.Value>

运行demo后,当前网格中的选择索引为0,我尝试改变myCustomControl属性List的值(Items,而不是引用),例如更新如下:

myCustomControl.List.Add(".NET");
myCustomControl.List.Add("Java");

然后,将网格中的选择移动到下一个位置(索引 1),值“.NET,Java”将更新到数据源中第 0 行的名称列,如下所示:

ID      |      Name
1             .NET,Java
2                             <----- current index

现在,如果我将选择移回索引 0,则第 1 行中 Name 列的值也会更新为“.NET,Java”,如下所示:

ID      |      Name
1             .NET,Java     <----- current index
2             .NET,Java

这不是我想要的。我的意思是应该通过控件 myCustomControl 更新该值。这是我想要的:

ID      |      Name
1             .NET,Java     <----- current index
2             

我可以理解,在从索引 1 移回索引 0 时,List 属性的值仍然是一个具有 2 个项目(“.NET”和“Java”)的 List,因此在移动之后,它被更新为cell at column Name in row 1. I'm finding how to reset that value of List property after it's updated to the cell at column Name in row 0 so that when the selection is at index 1, it's already empty. 我尝试将 Parse 事件处理程序更改为以下内容,但效果不佳:

bind.Parse += (s,e) => {
  List<string> data = (List<string>) e.Value;
  if(data.Count == 0) e.Value = DBNull.Value;
  else e.Value = string.Join(",",data.ToArray());//format as comma separated string
  //I think at here, the value has been already updated to the datasource
  //and I can perform the reset
  myCustomControl.List.Clear();
};

但似乎在值更新到数据源之前清除,因此没有更新到数据源的值(而不是“.NET,Java”,它是一个 DBNull.Value)。

然后我也试过这个:

bind.BindingComplete += (s,e) => {
   if(e.BindingCompleteContext == BindingCompleteContext.DataSourceUpdate)
      myCustomControl.List.Clear();
};

我想,它应该检查数据是否更新到数据源,列表可以清楚。我还尝试了一些标志在清除之前将其标记为真,并在清除后将其重置为假,使用此标志来控制 bind.Parse 中的流动,但它什么也没做。

你有解决这个问题的想法吗?您的帮助将不胜感激!谢谢你。

4

1 回答 1

1

我自己找到了解决方案。事实上,无论如何我都无法重置列表,这将在网格中的行之间切换时更新底层数据源。这里的关键思想是最初将 DataSourceUpdateMode 设置为 DataSourceUpdateMode.Never,然后每当 List 即将更改时,将 DataSourceUpdateMode 设置为 DataSourceUpdateMode.OnPropertyChanged。在 Parse 事件处理程序中,解析完成后,将 DataSourceUpdateMode 重置为 DataSourceUpdateMode.Never。这非常有效。仅当用户通过键入或选择更改控件的值(列表)时,才会更新基础数据源,...

这是所有代码:

Binding bind = new Binding("List", myDataTable, "Name"){
  ControlUpdateMode = ControlUpdateMode.Never, //Because my List property is readonly
  DataSourceUpdateMode = DataSourceUpdateMode.Never//This will be turned on when preparing to change the List's value
};
//formating string data before updating to the datasource
bind.Parse += (s,e) => {
  List<string> data = (List<string>) e.Value;
  if(data.Count == 0) e.Value = DBNull.Value;
  else e.Value = string.Join(",",data.ToArray());//format as comma separated string
  //At here reset the DataSourceUpdateMode to Never
  //We can also do this in BindingComplete event handler with BindingCompleteContext = BindingCompleteContext.DataSourceUpdate
  myCustomControl.DataBindings[0].DataSourceUpdateMode = DataSourceUpdateMode.Never;
};
myCustomControl.DataBindings.Add(bind);

myCustomControl 有一个方法来更新/填充 List 属性的新项目,称为 UpdateList(),我们必须在方法的最开始将 DataSourceUpdateMode 设置为 OnPropetyChanged,如下所示:

public void UpdateList(){
    if(DataBindings.Count > 0) DataBindings[0].DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
    //The remaining code for populating/updating new items goes below
    ....
}

仅此而已,非常干净。希望这会帮助遇到与我相同情况的人。谢谢!

于 2013-04-29T15:24:20.303 回答