c# - 事件处理程序中的 "reentrant call to SetCurrentCellAddressCore"- 仅当单元格行索引和列索引相等时

标签 c# winforms exception datagridview event-handling

我正在制作一个 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/

相关文章:

c# - Visual Studio 解决方案无法编译,但项目可以

c# - 在 C# 中将一组成员标记为私有(private)/公共(public)

c# - 如何在 WPF ItemTemplate 中结合自动换行和动态字体大小

c# - 编写高度用户可扩展的 C# 应用程序的最佳实践

c# - .Net 形式焦点

c# - 当鼠标按下时 MouseHover 不触发

java - 我有一个 ConnectException 由于某种原因没有被捕获

c# - .NET Core 3 在舍入接近 0 的负数时返回 -0 字符串

java.util.ConcurrentModificationException 没有按预期抛出

c++ - 使用 CoInitialize 和 CoUninitialize 引发 C++ 异常