首先,我想谈谈正常绑定(使用标准属性,例如文本框的文本)。此处的示例网格只有2行(为简单起见)。假设我有一个包含2列(myDataTable)和2列(ID和Name)的表,一个DataGridView(myGrid)和一个TextBox(myTextBox)。以下是绑定数据的代码:
myGrid.DataSource = myDataTable;
myTextBox.DataBindings.Add("Text", myDataTable, "Name");
绑定数据后,当网格中的选择发生变化时,信息会自动更新到控件TextBox,例如,2行是:
ID | Name
1 .NET
2 Java
首先,网格中的选择位于索引0,myTextBox的Text是“.NET”,将选择移动到下一个位置(索引1处),myTextBox的Text是“Java”,一次又一次地移动,前进和后退,它可以正常工作。但是现在我有一个名为List的自定义属性的控件,这是List的类型并且是readonly。我想将它绑定到一个表的列(例如,Name),我做相同的绑定规则,但是在更新到数据源(myDataTable)之前添加一些自定义Parse来格式化正确的字符串,因为我的自定义属性是列表,而我的名称列是字符串的类型,这是绑定代码:
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当前在列名称中没有数据,如下所示:
ID | Name
1 <DBNull.Value> <--- current index
2 <DBNull.Value>
运行演示后,网格中的当前选择索引为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”),因此在移动之后,这是更新到第1行中Name列的单元格。我发现如何在将List属性更新为第0行的Name列中的单元格后重置该属性的值,以便当选择位于索引1时,它已经为空。我尝试将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();
};
但是在将值更新到数据源之前似乎是Clear,因此没有对数据源的值(而不是“.NET,Java”,它是一个DBNull.Value)。
然后我也尝试了这个:
bind.BindingComplete += (s,e) => {
if(e.BindingCompleteContext == BindingCompleteContext.DataSourceUpdate)
myCustomControl.List.Clear();
};
我想,它应该检查数据是否更新到数据源,List可以清除。我还尝试了一些标记在清除之前标记为true并在清除后将其重置为false,使用此标志来控制bind.Parse中的流动,但它什么也没做。
你有什么想法解决这个问题吗?非常感谢您的帮助!谢谢。
答案 0 :(得分:1)
我自己找到了解决方案。实际上我无论如何都无法重置List,这将在网格中的行之间切换时更新基础数据源。这里的关键思想是将DataSourceUpdateMode设置为DataSourceUpdateMode.Never,然后每当List即将更改时,将DataSourceUpdateMode转换为DataSourceUpdateMode.OnPropertyChanged。在Parse事件处理程序中,完成解析后,将DataSourceUpdateMode重置为DataSourceUpdateMode.Never。这非常有效。仅当用户通过键入或选择,...
更改控件的值(List)时,才会更新基础数据源以下是所有代码:
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有一个方法来更新/填充名为UpdateList()的List属性的新项目,我们必须在方法的最开始将DataSourceUpdateMode设置为OnPropetyChanged,如下所示:
public void UpdateList(){
if(DataBindings.Count > 0) DataBindings[0].DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
//The remaining code for populating/updating new items goes below
....
}
这就是全部,非常干净。希望这能帮助那些遇到同样情况的人。谢谢你!