C# &引用;可重入调用SetCurrentCellAddressCore“;事件处理程序中-仅当单元格行和列索引相等时

C# &引用;可重入调用SetCurrentCellAddressCore“;事件处理程序中-仅当单元格行和列索引相等时,c#,winforms,exception,datagridview,event-handling,C#,Winforms,Exception,Datagridview,Event Handling,我正在制作一个WinForms应用程序,其中包括一个使用DataGridView处理简单数据操作的表单。为了在减少混乱的同时确保准确输入(请阅读:不使用datagridviewcomboxcolumn),我有两个事件处理程序,可以临时将datagridviewcontextboxcell转换为等效的datagridviewcomboxcell连接到在引发编辑事件时已知为“干净”的值(通常在单击可编辑单元格时): 及 大多数情况下,这种方法都能很好地工作-最后一个编辑的单元格将恢复为包含新选择的数

我正在制作一个WinForms应用程序,其中包括一个使用
DataGridView
处理简单数据操作的表单。为了在减少混乱的同时确保准确输入(请阅读:不使用
datagridviewcomboxcolumn
),我有两个事件处理程序,可以临时将
datagridviewcontextboxcell
转换为等效的
datagridviewcomboxcell
连接到在引发编辑事件时已知为“干净”的值(通常在单击可编辑单元格时):

大多数情况下,这种方法都能很好地工作-最后一个编辑的单元格将恢复为包含新选择的数据的
DataGridViewTextBoxCell
,而选择编辑的单元格将成为链接到
mDropDownValues[]中指定的数据的
DataGridViewComboxCell
dictionary。但是,当编辑行索引和列索引相等的单元格时,我遇到了问题。该单元格无法在这两种类型之间进行更改,在
dataGridView上引发了异常。行[e.RowIndex]。单元格[e.ColumnIndex]=cell;
两个事件处理程序中的行(在处理
CellBeginEdit
时一次,然后在处理
CellEndEdit
时再次)。异常状态为

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


导致此错误的原因是什么?为什么只有在沿
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_InrurentCellChange标志为true。DataGridView有许多此类检查,无疑是在广泛测试后添加的。它限制了引发事件时可以执行的操作数量,确保重新进入不会损坏控件的内部状态

此类重入问题的通用解决方案是在事件引发且控件的内部状态再次稳定后,稍后执行该操作。使用BeginInvoke()方法可以优雅地执行此操作,当程序重新进入dispatcher循环时,它将运行。如下所示:

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();
    }));
}

使用.NET 4.5.1和Win7开发(如果这对您的答案有任何影响的话)。在
BeginInvoke()中包装事件处理程序的内容时
我在编辑对角线上的单元格时不再出现错误,但当选择编辑单元格时,单元格也不再切换到
DataGridViewComboxCell
s。我猜这与异步调用有关,但我不确定……有什么想法吗?嗯,没有,这很神秘,我没有重新编写。你没有给出任何建议nEdit()同样的处理,是吗?没有必要。是的,我做了。在删除
BeginInvoke()之后
OnCellBeginEdit的包装器,但是,我仍然得到调用处理程序的错误。这是可能的,我想,我不知道您到底要做什么才能将单元格置于编辑模式。我测试的那个,只是键入一个字符,在实践中没有什么意义。请用那个细节更新您的问题。我只是使用单击引发的编辑事件在单元格上。也添加到问题正文中。
        // 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));
        }
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();
    }));
}