You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DevExpress GridView单元格合并事件重复触发问题及优化咨询

解决DevExpress GridView CellMerge事件重复触发导致重复求和的问题

问题根源

CellMerge事件会在网格绘制、滚动、刷新时多次触发,你原代码在事件内直接修改单元格值,导致每次触发都重复累加数值,同时重复执行冗余逻辑也会降低性能。正确的做法是:数据合并求和只执行一次,CellMerge仅负责判断单元格是否需要视觉合并。

解决方案步骤

  1. 提取通用逻辑,创建一次性处理合并求和的方法
  2. 在数据绑定完成后调用该方法,仅执行一次数据计算
  3. 修改CellMerge事件,只做合并条件判断,不再修改数据

具体实现代码

1. 定义标志位与通用合并求和方法

// 标记数据是否已处理,避免重复执行
private bool _isDataProcessed = false;

private void MergeAndSumTargetColumns()
{
    GridView view = gridViewCompras;
    if (view.DataSource == null || _isDataProcessed) return;

    // 需要处理求和的目标列
    List<string> targetColumns = new List<string> { ColNecessidades1, ColNecessidades2, ColNecessidades6 };
    
    // 假设数据源为DataTable,若为实体类集合,逻辑类似
    DataTable dt = view.DataSource as DataTable;
    if (dt == null) return;

    // 按分组键(Referencia+Espessura+Acabamento)分组计算总和
    var groups = dt.AsEnumerable()
                   .GroupBy(row => new 
                   { 
                       Referencia = row[ColReferencia].ToString(),
                       Espessura = row[ColEspessura].ToString(),
                       Acabamento = row[ColAcabamento].ToString()
                   });

    foreach (var group in groups)
    {
        if (group.Count() <= 1) continue;

        // 取组内第一行作为合并后显示的行,累加其他行的数值
        DataRow firstRow = group.First();
        foreach (string col in targetColumns)
        {
            double total = group.Sum(row => Convert.ToDouble(row[col]));
            firstRow[col] = total.ToString();
        }

        // 标记组内其他行需要隐藏
        foreach (DataRow row in group.Skip(1))
        {
            row["IsMerged"] = true;
        }
    }

    view.RefreshData();
    _isDataProcessed = true;
}

2. 在DataBound事件中调用处理方法

数据绑定完成后一次性执行合并求和:

private void gridViewCompras_DataBound(object sender, EventArgs e)
{
    MergeAndSumTargetColumns();
}

3. 修改CellMerge事件,仅做合并判断

private void gridViewCompras_CellMerge(object sender, CellMergeEventArgs e)
{
    GridView view = sender as GridView;
    if (view == null) return;

    // 仅处理指定列的合并判断
    List<string> mergeColumns = new List<string> { ColNecessidades1, ColNecessidades2, ColNecessidades6 };
    if (!mergeColumns.Contains(e.Column.FieldName)) return;

    // 获取两行的分组匹配条件
    string ref1 = view.GetRowCellDisplayText(e.RowHandle1, ColReferencia);
    string ref2 = view.GetRowCellDisplayText(e.RowHandle2, ColReferencia);
    string esp1 = view.GetRowCellDisplayText(e.RowHandle1, ColEspessura);
    string esp2 = view.GetRowCellDisplayText(e.RowHandle2, ColEspessura);
    string acab1 = view.GetRowCellDisplayText(e.RowHandle1, ColAcabamento);
    string acab2 = view.GetRowCellDisplayText(e.RowHandle2, ColAcabamento);

    // 满足条件则允许合并
    if (ref1 == ref2 && esp1 == esp2 && acab1 == acab2)
    {
        e.Merge = true;
        e.Handled = true;
    }
}

4. 添加CustomRowFilter事件隐藏被合并的行

private void gridViewCompras_CustomRowFilter(object sender, DevExpress.XtraGrid.Views.Base.RowFilterEventArgs e)
{
    GridView view = sender as GridView;
    DataRow row = view.GetDataRow(e.RowHandle);
    if (row != null && row["IsMerged"] != DBNull.Value && (bool)row["IsMerged"])
    {
        e.Visible = false;
        e.Handled = true;
    }
}

注意事项

  • 若数据源为实体类集合,只需修改MergeAndSumTargetColumns中的分组逻辑,核心思路一致
  • 当需要重新绑定数据时,需提前重置_isDataProcessed = false,确保新数据能重新处理
  • 绝对避免在CellMerge事件中修改单元格或数据源,这是触发重复问题的核心原因

内容的提问来源于stack exchange,提问作者Sowaryu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 18:24:53