“事件处理程序中的可重入调用SetCurrentCellAddressCore” - 仅在单元格行和列索引相等的情况下

时间:2014-12-23 18:37:45

标签: c# winforms exception datagridview event-handling

我正在创建一个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对角线上的单元格时才会发生?有没有什么方法可以实现这个功能而不抛出这个异常?

1 个答案:

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