devexpress gridcontrol 通过 SetRowCellValue先触发筛选数据变化,再触发CellValueChanged值。如果通过CellValueChanged事件去更新数据,那么获取的e参数所对应的行的信息已发生变化,造成更新数据的错误。

// 当调用 SetRowCellValue 时
gridView.SetRowCellValue(rowHandle, column, newValue);

// 内部执行顺序:
// 1. 更新数据源中的值
// 2. 立即触发数据变更,可能导致筛选状态变化
// 3. 如果新值影响筛选条件,行可能会隐藏/显示
// 筛选相关事件可能先触发:
gridView.RowFilterChanged    // 如果筛选条件变化
gridView.CustomRowFilter     // 自定义筛选逻辑

// 然后是单元格值变化事件:
gridView.CellValueChanged    // 最后触发

如果不是使用SetRowCellValue方法修改值,测试的CellValueChanged事件可以正常获取e以及cell值。例如通过复制粘贴或者直接修改,则不会出错(可能官方已经考虑了?)。

使用 BeginUpdate 可以延迟事件触发,但是不会变更触发顺序

gridView1.BeginUpdate();
gridView1.SetRowCellValue(0, colName, "Value1");
gridView1.SetRowCellValue(1, colName, "Value2");
gridView1.EndUpdate(); // 所有事件在 EndUpdate 后批量触发

那么如何解决数据写入界面和写入数据库的问题?
由于CellValueChanged事件包含了数据的写入,而数据值无论通过修改绑定的DataSource的值还是通过SetRowCellValue方法,都是先触发筛选状态变化。
那么需要考虑这种情况采用单独的数据写入方式
例如:

// 如果需要确保特定执行顺序
private void UpdateCellSafely()
{
    // 暂时解除事件绑定,避免数据再次触发写入数据库事件。
    gridView1.CellValueChanged -= gridView1_CellValueChanged;

    try
    {
        gridView1.SetRowCellValue(rowHandle, column, value);//或者直接修改DataSource的值
        // 手动处理筛选逻辑
        HandleFilterManually();
        //这个时候,应该将值一次性写入和更新
    }
    finally
    {
        gridView1.CellValueChanged += gridView1_CellValueChanged;
    }
}

临时禁用筛选的方式并不适合,变更了筛选条件,那么这是的行关系已经发生变化了,数据按行获取的情况下,获取的值会直接产生偏移错误。

最后修改:2025 年 12 月 17 日
如果觉得我的文章对你有用,可以点一下赞赏