我正在创建一个WinForms应用程序,其中包含一个使用DataGridView
来处理简单数据操作的表单。为了确保准确输入同时减轻混乱(阅读:不使用DataGridViewComboBoxColumn
),我有一些事件处理程序暂时将DataGridViewTextBoxCell
转换为与已知为&#34的值相关联的等效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[]
中指定的数据{1}}字典。但是,当编辑具有相等的行索引和列索引的单元格时,我遇到了麻烦。单元格在两种类型之间无法更改,在两个事件处理程序中的dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex] = cell;
行上抛出异常(处理CellBeginEdit
时一次,然后处理CellEndEdit
时再次)。例外情况
"操作无效,因为它导致对SetCurrentCellAddressCore函数的重入调用。"
导致此错误的原因是什么,为什么只在编辑DataGridView
对角线上的单元格时才会发生?有没有什么方法可以实现这个功能而不抛出这个异常?
答案 0 :(得分:6)
你正在与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();
}));
}