InvalidOperationException – 结束编辑单元格并移动到另一个单元格时

我制作了一个程序,我想手动更新数据网格视图。 – 我有一个通过清除它然后重新插入数据来刷新DGV的方法。 – 使用设计器,我为DGV的CellEndEdit创建了一个事件处理程序。 在事件处理程序内部,数据会更新并调用DGV的自定义刷新方法。

在运行程序时,每当我开始编辑单元格并通过选择另一个单元格结束它时,会抛出exception:

InvalidOperationException操作无效,因为它导致对SetCurrentCellAddressCore函数的可重入调用。

Visual C#的调试器标记清除数据的行:datagridview1.Rows.Clear();

如果您想重现该问题,请使用visual c#创建一个新的Windows窗体项目,在窗体上放置一个DataGridView对象,并粘贴Form1.cs的以下代码:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace Error___DataGridView_Updating___Cell_endedit { public partial class Form1 : Form { // Objects DataTable dt; DataColumn colID; DataColumn colName; DataColumn colInfo; // Constructor public Form1() { InitializeComponent(); Initialize_dt(); InsertSampleData_dt(); Initialize_dataGridView1(); } // Methods private void Initialize_dt() { dt = new DataTable(); // Building Columns // ID colID = new DataColumn(); colID.ColumnName = "ID"; colID.DataType = typeof(int); dt.Columns.Add(colID); // Name colName = new DataColumn(); colName.ColumnName = "Name"; colName.DataType = typeof(string); dt.Columns.Add(colName); //Info colInfo = new DataColumn(); colInfo.ColumnName = "Info"; colInfo.DataType = typeof(string); dt.Columns.Add(colInfo); } private void InsertSampleData_dt() { DataRow row; // 0 row = dt.NewRow(); row["ID"] = 100; row["Name"] = "AAAA"; row["Info"] = "First Record"; dt.Rows.Add(row); //1 row = dt.NewRow(); row["ID"] = 101; row["Name"] = "BBBB"; row["Info"] = "Second Record"; dt.Rows.Add(row); //2 row = dt.NewRow(); row["ID"] = 102; row["Name"] = "CCCC"; row["Info"] = "Third Record"; dt.Rows.Add(row); } private void Initialize_dataGridView1() { dataGridView1.AllowUserToAddRows = false; // Data Grid Definitions // Row Header dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing; dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders; // ColumnHeaders dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells; // Building Columns #region ID { DataGridViewColumn colSGID = new DataGridViewTextBoxColumn(); colSGID.Name = "ID"; colSGID.HeaderText = "#"; colSGID.ReadOnly = true; colSGID.Visible = false; colSGID.Resizable = DataGridViewTriState.False; dataGridView1.Columns.Add(colSGID); } #endregion #region Name { DataGridViewColumn colSGName = new DataGridViewTextBoxColumn(); colSGName.Name = "Name"; colSGName.HeaderText = "Name"; dataGridView1.Columns.Add(colSGName); } #endregion #region Info { DataGridViewColumn colSGSubject = new DataGridViewTextBoxColumn(); colSGSubject.Name = "Info"; colSGSubject.HeaderText = "Description"; dataGridView1.Columns.Add(colSGSubject); } #endregion Refresh_dataGridView1(); } private void Refresh_dataGridView1() { int index; dataGridView1.SuspendLayout(); dataGridView1.Rows.Clear(); //MessageBox.Show("Cleared Data. Rebuilding..."); foreach (DataRow row in dt.Rows) { index = dataGridView1.Rows.Add(new DataGridViewRow()); dataGridView1.Rows[index].Cells["ID"].Value = row["ID"]; dataGridView1.Rows[index].Cells["Name"].Value = row["Name"]; dataGridView1.Rows[index].Cells["Info"].Value = row["Info"]; //MessageBox.Show("row #" + index); } dataGridView1.ResumeLayout(); } //Event Handlers private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) { bool toUpdate = false; int id = (int)dataGridView1.Rows[e.RowIndex].Cells["ID"].Value; string columnName = dataGridView1.Columns[e.ColumnIndex].Name; string value = (string)dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value; if (value == null) { value = string.Empty; } switch (columnName) { case "Name": if (value == string.Empty) { MessageBox.Show("Name Can't Be Empty!"); } else { toUpdate = true; } break; case "Info": toUpdate = true; break; } if (toUpdate) { foreach(DataRow row in dt.Rows) { if ( (int)row["ID"] == id) { row[columnName] = value; } } Refresh_dataGridView1(); } } } } 

Bruce.Zhou在MSDN论坛上有一个答案。 我在这里发布了一个片段。 这里也是原帖的链接。

 private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) { ...................................................; if (toUpdate) { foreach(DataRow row in dt.Rows) { if ( (int)row["ID"] == id) { row[columnName] = value; } } this.BeginInvoke(new MethodInvoker(Refresh_dataGridView1)); } } 

使用此修复程序时,无论何时选择新单元格,都会选择它与第一个单元格(包括)之间的所有单元格。 我正在寻找一种只选择新细胞的方法。

我在最后一小时敲了敲我的头来解决这个问题。 这是我的解决方法:查看问题:当选择另一个单元格(或gridview中的任何控件)时,触发EndEdit。

在应用编辑之前应用以下检查:

 public void myGrid_EndEdit(object sender, DataGridViewCellEventArgs e) { if (!myGrid.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected) return; //...rest of your code to apply edit below... } 

这应该适用于正在编辑的任何单元格。(因此在失去焦点时不应用编辑;键入Enter就足以应用编辑)

我的工作是捕获CellMouseDown事件,如果操作是在编辑之外的单元格上,那么它会发出DataGridView.EndEdit()。 其他一切都按预期工作。