【问题标题】:Binding custom property updates to the datasource abnormally?异常绑定自定义属性更新到数据源?
【发布时间】:2013-04-23 06:22:36
【问题描述】:

首先,我想谈谈普通绑定(带有标准属性,例如文本框的Text)。这里的示例网格只有 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 行的 Name 列,如下所示:

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,所以在移动之后,这是在第1行中的列名称上更新到小区1.我发现如何在第0行中将其更新到小区之后重置列表属性的值,以便选择在索引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();
};

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

那我也试过这个:

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

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

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

【问题讨论】:

    标签: c# data-binding binding datagridview


    【解决方案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 有一个名为 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
        ....
    }
    

    仅此而已,非常干净。希望这对遇到和我一样情况的人有所帮助。谢谢!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-29
      • 1970-01-01
      • 1970-01-01
      • 2016-06-08
      • 2011-07-31
      • 2011-06-22
      • 1970-01-01
      • 2014-09-08
      相关资源
      最近更新 更多