绑定到 DataRowView 的 Winforms 控件更改行值但不更改 RowState

Posted

技术标签:

【中文标题】绑定到 DataRowView 的 Winforms 控件更改行值但不更改 RowState【英文标题】:Winforms Control Bound To DataRowView Changes Row Values But Not RowState 【发布时间】:2019-12-29 05:29:34 【问题描述】:

一个简单的 WinForms 应用程序,用于了解控件数据绑定。下面的代码来自名为 frmMain 并包含 TextBoxes txtFirstName 和 txtLastName,以及名为 nudRow 的数字向上/向下。编辑文本框中的文本并更改行,我注意到以前的 DataRow 在“建议”行版本中的值发生了更改(例如 _Tbl.Rows[3][1, DataRowVersion.Proposed]),但 RowState 仍然是 '不变”。我错过了什么会使“提议”变为“当前”并改变 RowState?注释掉的“DataSourceUpdateMode”没有任何区别。

我也很模糊为什么我需要继续重置 TextBox DataBindings 而不是仅在数值上/下值更改事件中设置 DataRowView (_CurRow)。

编辑:我想我很清楚我的问题是:为什么 RowState 没有改变?此外,是否有通常用于处理“建议”值和更改 RowState 的标准模式(验证或其他东西)?顺便说一句,我想知道为什么我必须重建数据绑定,而不是仅仅更改已经绑定的东西的值,但也许这需要是一个单独的问题。

EDIT2:查看有关 DataRowVersion.Proposed 的一些文档后,看起来我应该在我的数值上/下值更改事件中添加类似下面的代码。不幸的是,在帖子被搁置时,我无法回答自己的问题...

if (_CurRow.Row.HasVersion(DataRowVersion.Proposed))

  // Do validation stuff then
  if(isValid)
  
    _CurRow.Row.EndEdit();
  
  else
  
    _CurRow.Row.CancelEdit();
  

就个人而言,我会验证表单输入控件中的每个用户输入,但我现在知道,即使在控件中还原原始值也会在 DataRow 中创建一个建议的版本。

private DataRowView _CurRow = null;
private DataTable _Tbl = null;

private const string COL_NAME_ROW = "Row No.";
private const string COL_NAME_FIRST = "First Name";
private const string COL_NAME_LAST = "Last Name";

public frmMain()

  DataRow dr;

  InitializeComponent();
  _Tbl = new DataTable();
  _Tbl.Columns.Add(COL_NAME_ROW, typeof(int));
  _Tbl.Columns.Add(COL_NAME_FIRST, typeof(string));
  _Tbl.Columns.Add(COL_NAME_LAST, typeof(string));
  dr = _Tbl.NewRow();
  dr[COL_NAME_ROW] = 0;
  dr[COL_NAME_FIRST] = "Alan";
  dr[COL_NAME_LAST] = "Ladd";
  _Tbl.Rows.Add(dr);
  dr = _Tbl.NewRow();
  dr[COL_NAME_ROW] = 1;
  dr[COL_NAME_FIRST] = "Boris";
  dr[COL_NAME_LAST] = "Yeltsin";
  _Tbl.Rows.Add(dr);
  dr = _Tbl.NewRow();
  dr[COL_NAME_ROW] = 2;
  dr[COL_NAME_FIRST] = "Cab";
  dr[COL_NAME_LAST] = "Calloway";
  _Tbl.Rows.Add(dr);
  dr = _Tbl.NewRow();
  dr[COL_NAME_ROW] = 3;
  dr[COL_NAME_FIRST] = "David";
  dr[COL_NAME_LAST] = "Letterman";
  _Tbl.Rows.Add(dr);
  _Tbl.AcceptChanges();



private void frmMain_Shown(object sender, EventArgs e)

  _CurRow = _Tbl.DefaultView[0];
  this.txtFirstName.DataBindings.Add("Text", _CurRow, COL_NAME_FIRST); //,
  //false, DataSourceUpdateMode.OnPropertyChanged);
  this.txtLastName.DataBindings.Add("Text", _CurRow, COL_NAME_LAST); //,
  //false, DataSourceUpdateMode.OnPropertyChanged);
  //this.nudRow.DataBindings.Add("Value", _Tbl, COL_NAME_ROW);


private void nudRow_ValueChanged(object sender, EventArgs e)

  // Previous row has modified (proposed) data here, but unchanged RowState
  _CurRow = _Tbl.DefaultView[(int)this.nudRow.Value];
  this.txtFirstName.DataBindings.Clear();
  this.txtFirstName.DataBindings.Add("Text", _CurRow, COL_NAME_FIRST); //,
    //false, DataSourceUpdateMode.OnPropertyChanged);
  this.txtLastName.DataBindings.Clear();
  this.txtLastName.DataBindings.Add("Text", _CurRow, COL_NAME_LAST); //,
  //false, DataSourceUpdateMode.OnPropertyChanged);


【问题讨论】:

【参考方案1】:

编辑绑定控件会导致 DataRow 上的 BeginEdit 应使用 EndEdit 或 CancelEdit 关闭。下面的代码使用一种可能的解决方案进行了修改。

private DataRowView _CurRow = null;
private DataTable _Tbl = null;

private const string COL_NAME_ROW = "Row No.";
private const string COL_NAME_FIRST = "First Name";
private const string COL_NAME_LAST = "Last Name";

public frmMain()

  DataRow dr;

  InitializeComponent();
  _Tbl = new DataTable();
  _Tbl.Columns.Add(COL_NAME_ROW, typeof(int));
  _Tbl.Columns.Add(COL_NAME_FIRST, typeof(string));
  _Tbl.Columns.Add(COL_NAME_LAST, typeof(string));
  dr = _Tbl.NewRow();
  dr[COL_NAME_ROW] = 0;
  dr[COL_NAME_FIRST] = "Alan";
  dr[COL_NAME_LAST] = "Ladd";
  _Tbl.Rows.Add(dr);
  dr = _Tbl.NewRow();
  dr[COL_NAME_ROW] = 1;
  dr[COL_NAME_FIRST] = "Boris";
  dr[COL_NAME_LAST] = "Yeltsin";
  _Tbl.Rows.Add(dr);
  dr = _Tbl.NewRow();
  dr[COL_NAME_ROW] = 2;
  dr[COL_NAME_FIRST] = "Cab";
  dr[COL_NAME_LAST] = "Calloway";
  _Tbl.Rows.Add(dr);
  dr = _Tbl.NewRow();
  dr[COL_NAME_ROW] = 3;
  dr[COL_NAME_FIRST] = "David";
  dr[COL_NAME_LAST] = "Letterman";
  _Tbl.Rows.Add(dr);
  _Tbl.AcceptChanges();



private void frmMain_Shown(object sender, EventArgs e)

  _CurRow = _Tbl.DefaultView[0];
  this.txtFirstName.DataBindings.Add("Text", _CurRow, COL_NAME_FIRST); //,
  //false, DataSourceUpdateMode.OnPropertyChanged);
  this.txtLastName.DataBindings.Add("Text", _CurRow, COL_NAME_LAST); //,
  //false, DataSourceUpdateMode.OnPropertyChanged);
  //this.nudRow.DataBindings.Add("Value", _Tbl, COL_NAME_ROW);


private void nudRow_ValueChanged(object sender, EventArgs e)

  bool? hasChanged = null;
  // Previous row has modified (proposed) data here, but unchanged
  // RowState. Need to end or cancel the BeginEdit caused by
  // editing the bound control in order to update the RowState to
  // Modified and push Proposed value to Current (EndEdit) or
  // leave the RowState Unchanged (CancelEdit)
  hasChanged = this.RowHasChanged(_CurRow.Row);
  if (!hasChanged.HasValue)
  
    // Didn't have proposed version so no-op
  
  else if (hasChanged.Value)
  
    _CurRow.Row.EndEdit();
  
  else
  
    _CurRow.Row.CancelEdit();
  
  _CurRow = _Tbl.DefaultView[(int)this.nudRow.Value];
  this.txtFirstName.DataBindings.Clear();
  this.txtFirstName.DataBindings.Add("Text", _CurRow, COL_NAME_FIRST);
  this.txtLastName.DataBindings.Clear();
  this.txtLastName.DataBindings.Add("Text", _CurRow, COL_NAME_LAST);



// This is necessary because reverting values still causes
// row to have proposed version, but isn't a true change
private bool RowHasChanged(DataRow DataRowObj)

  bool retVal = false;

  if (!DataRowObj.HasVersion(DataRowVersion.Proposed)) return retVal;
  for (int ii = 0; ii < _CurRow.Row.ItemArray.Length; ii++)
  
    if (!object.Equals(
            _CurRow.Row[ii, DataRowVersion.Current],
            _CurRow.Row[ii, DataRowVersion.Proposed]))
    
      retVal = true;
      break;
    
  
  if (!retVal.HasValue) retVal = false;
  return retVal;


【讨论】:

以上是关于绑定到 DataRowView 的 Winforms 控件更改行值但不更改 RowState的主要内容,如果未能解决你的问题,请参考以下文章

绑定到 DataRowView 的 Winforms 控件更改行值但不更改 RowState

Combobox数据绑定显示system.data.datarowview

WinForm开发-界面控件到实体,实体到界面控件自动绑定

WinForm 绑定到嵌套对象上的属性

在 WinForm 中将 List<T> 绑定到 DataGridView

如何使用 C# 在 WinForm 中手动绑定到蓝牙低功耗设备?