DevExpress GridView单元格合并事件重复触发问题及优化咨询
解决DevExpress GridView CellMerge事件重复触发导致重复求和的问题
问题根源
CellMerge事件会在网格绘制、滚动、刷新时多次触发,你原代码在事件内直接修改单元格值,导致每次触发都重复累加数值,同时重复执行冗余逻辑也会降低性能。正确的做法是:数据合并求和只执行一次,CellMerge仅负责判断单元格是否需要视觉合并。
解决方案步骤
- 提取通用逻辑,创建一次性处理合并求和的方法
- 在数据绑定完成后调用该方法,仅执行一次数据计算
- 修改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
相关产品推荐
相关产品推荐

