DataGridView 可编辑单元格输入在更新另一个单元格时被覆盖

本文关键字:单元格 另一个 覆盖 更新 编辑 输入 DataGridView | 更新日期: 2023-09-27 18:33:48

我有一个通过BindingSource绑定到DataTableDataGridView,我的网格有用户输入值的可编辑列,还有一些以编程方式实时更新的只读列(像股票行情一样思考)。 对于以编程方式更新的列,我正在更新DataTable中的值,然后由于数据绑定而更新 DataGridView 中的值。我遇到的问题是,当用户编辑一个单元格时,如果以编程方式更新另一个单元格,则用户在第一个单元格中输入的文本将被覆盖(在编辑之前重置为单元格的值)。

这对我来说似乎不是一个不寻常的情况,但我似乎无法让它正常工作。 有谁知道我可能做错了什么,或者可以指出我一个展示如何正确做到这一点的例子?

DataGridView 可编辑单元格输入在更新另一个单元格时被覆盖

发生这种情况

是因为当DataTable中的基础值更改时,将触发DataGridView.DataBindingComplete事件 - 重置绑定。

我的第一个建议是捕获此事件并检查CurrentCellEditedFormattedValue是否与Value不同 - 如果是,则设置Value。这有效 - 直到我检查第一行 - 这完全忽略了我的逻辑。

我能找到的唯一解决方案是改变程序化实时更新的发生方式。如果可能,只需更新DataGridView列,而不是更新DataTable列。这些更改将永久保存到源,但绑定不会重置 - 因此您当前的编辑单元格不会丢失任何更改。

foreach (DataRow row in this.table.Rows)
{
    row[1] = someNewValue;
}

foreach (DataGridViewRow row in this.dataGridView1.Rows)
{
    row.Cells[1].Value = someNewValue;
}

最后我解决了这个问题,所以我将在此处添加我的解决方案,以防它对其他人有所帮助。

我处理了DataGridViewCellBeginEditCellEndEditCurrentCellDirtyStateChanged事件,并添加了以下代码:

private void Grid_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
    ((DataRowView)((DataGridView)sender).Rows[e.RowIndex].DataBoundItem).BeginEdit();
}
private void Grid_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    // need this check for when the program is closed while a cell is in edit mode
    // otherwise an IndexOutOfRangeException occurs
    if (((BindingSource)((DataGridView)sender).DataSource).List.Count > e.RowIndex)
        ((DataRowView)((DataGridView)sender).Rows[e.RowIndex].DataBoundItem).EndEdit();
}
private void Grid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
    // commit changes to the table as soon as they are entered so they don't 
    // get overwritten when the DataTable is updated
    if (Grid.IsCurrentCellDirty)
        Grid.CommitEdit(DataGridViewDataErrorContexts.Commit);
}

我还发现DataGridView的 Esc 键功能不仅恢复了对当前处于编辑模式的单元格的更改,而且还恢复了直接在DataTable中设置值的更改(实时编程更新),因此我覆盖了DataGridView的 Esc 键功能,如下所示:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (CurrentCell != null && CurrentCell.IsInEditMode)
    {
        if (keyData == (Keys.Escape))
        {
            CurrentCell.Value = valueBeforeEdit;
            EditingControl.Text = valueBeforeEdit.ToString();
            EndEdit();
            return true;
        }
    }
    return base.ProcessCmdKey(ref msg, keyData);
}

其中valueBeforeEdit在编辑之前保存单元格的值(在DataGridViewCellBeginEdit事件处理程序中设置)。

相关文章: