我正在制作一个 WinForms 应用程序,其中包含一个使用 DataGridView
来处理简单数据操作的表单。为了确保准确输入,同时减少困惑(阅读:不使用 DataGridViewComboBoxColumn
),我有几个事件处理程序,它们临时将 DataGridViewTextBoxCell
转换为等效的 DataGridViewComboBoxCell
当引发编辑事件时(通常是单击可编辑单元格时),连接到已知为“干净”的值:
private void OnCellEndEdit(object sender, DataGridViewCellEventArgs e)
{
//construct a textbox cell and set to current value
DataGridViewTextBoxCell cell = new DataGridViewTextBoxCell();
cell.Value = dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
//color row if invalid or modified
UpdateRowStyle(dataGridView.Rows[e.RowIndex]);
//switch to the new cell and redraw
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex] = cell;
dataGridView.Refresh();
}
和
private void OnCellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
//construct a combobox cell, link to data, and set to current value
DataGridViewComboBoxCell cell = new DataGridViewComboBoxCell();
cell.DataSource = mDropDownValues[dataGridView.Columns[e.ColumnIndex].Name];
cell.Value = dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
//switch to the new cell and redraw
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex] = cell;
dataGridView.Refresh();
}
大多数情况下,这工作得很好 - 最后编辑的单元格将恢复为包含新选定数据的 DataGridViewTextBoxCell
,并且选择进行编辑的单元格将变为链接到的 DataGridViewComboBoxCell
mDropDownValues[]
字典中指定的数据。然而,当编辑行索引和列索引相等的单元格时,我遇到了麻烦。单元格无法在两种类型之间更改,从而在两个事件处理程序中的 dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex] = cell;
行上引发异常(处理 CellBeginEdit
,然后在处理CellEndEdit
时再次)。异常状态
"Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore function."
是什么原因导致此错误,为什么仅在沿 DataGridView
对角线编辑单元格时才会发生此错误?有什么方法可以实现此功能而不引发此异常吗?
最佳答案
您正在与 SetCurrentCellAddressCore() 中的以下语句进行斗争,为了可读性进行了编辑:
// Allow the code to be re-entrant only as a result of
// underlying data changing.
if (this.dataGridViewOper[DATAGRIDVIEWOPER_inCurrentCellChange] &&
(this.dataConnection == null || !this.dataConnection.ProcessingListChangedEvent))
{
throw new InvalidOperationException(SR.GetString(SR.DataGridView_SetCurrentCellAddressCoreNotReentrant));
}
DATAGRIDVIEWOPER_inCurrentCellChange 标志为 true。 DataGridView 有很多此类检查,毫无疑问是经过大量测试后添加的。它限制了在引发事件时您可以执行的操作数量,确保重入不会破坏控件的内部状态。
解决此类重入问题的通用解决方案是在事件引发且控件的内部状态再次稳定后执行操作。您可以使用 BeginInvoke() 方法优雅地执行此操作,它会在您的程序重新进入调度程序循环时运行。像这样:
private void OnCellEndEdit(object sender, DataGridViewCellEventArgs e)
{
this.BeginInvoke(new Action(() => {
//construct a textbox cell and set to current value
DataGridViewTextBoxCell cell = new DataGridViewTextBoxCell();
cell.Value = dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
//color row if invalid or modified
UpdateRowStyle(dataGridView.Rows[e.RowIndex]);
//switch to the new cell and redraw
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex] = cell;
dataGridView.Refresh();
}));
}
关于c# - 事件处理程序中的 "reentrant call to SetCurrentCellAddressCore"- 仅当单元格行索引和列索引相等时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27626158/