DataGridView批量更新数千单元格速度极慢问题求助
DataGridView批量更新性能优化方案
问题背景
我有一个约30000行、仅两列的DataGridView,仅允许编辑每行第一列单元格。用户编辑完该单元格后,需要将所有第一列值与原值匹配的行更新为新值,并给这些单元格应用黄色背景样式。
我在CellValueChanged事件中实现了逻辑,但操作数千行时耗时约10分钟。已尝试在循环前后暂停/恢复布局,无明显改善。所有行均为手动从列表添加,未使用数据绑定。
原实现代码:
private void SamplesTable_CellValueChanged(object sender, DataGridViewCellEventArgs e) { if (_isEditing) { return; } _isEditing = true; // 避免更新多个单元格时重复触发事件 foreach (DataGridViewRow row in SensorsTable.Rows) { // 只修改和触发事件的旧值匹配的单元格 if (!row.Cells[0].Value.ToString().Trim().Equals(_oldValue, StringComparison.OrdinalIgnoreCase)) { continue; } row.Cells[0].Value = newValue; row.Cells[0].Style = cellStyle; // cellStyle是预先定义的DataGridViewCellStyle,背景色为黄色 } _isEditing = false; }
优化方案
1. 用字典映射减少遍历次数
既然是手动添加行,提前维护一个字典,键为第一列值的标准化格式(比如Trim后转小写),值为对应行的集合。这样编辑后直接通过字典找到匹配行,不用遍历全部3万行:
// 全局字典,存储值到行集合的映射 private Dictionary<string, List<DataGridViewRow>> _valueRowMap = new Dictionary<string, List<DataGridViewRow>>(StringComparer.OrdinalIgnoreCase); // 添加行时同步更新字典 private void AddRowToGrid(DataGridViewRow row) { string key = row.Cells[0].Value.ToString().Trim(); if (!_valueRowMap.ContainsKey(key)) { _valueRowMap[key] = new List<DataGridViewRow>(); } _valueRowMap[key].Add(row); SensorsTable.Rows.Add(row); }
2. 批量操作时禁用更多DataGridView更新机制
仅暂停布局不够,操作期间临时关闭不必要的UI更新逻辑:
private void SamplesTable_CellValueChanged(object sender, DataGridViewCellEventArgs e) { if (_isEditing) return; _isEditing = true; // 保存原有设置 bool originalHeaderStyle = SensorsTable.EnableHeadersVisualStyles; bool originalRowHeaderVisible = SensorsTable.RowHeadersVisible; // 禁用不必要的UI更新 SensorsTable.SuspendLayout(); SensorsTable.ReadOnly = true; SensorsTable.EnableHeadersVisualStyles = false; SensorsTable.RowHeadersVisible = false; try { string oldKey = _oldValue.Trim(); if (_valueRowMap.TryGetValue(oldKey, out var targetRows)) { foreach (var row in targetRows) { row.Cells[0].Value = newValue; row.Cells[0].Style = _highlightStyle; } // 更新字典:移除旧键,把行添加到新键下 _valueRowMap.Remove(oldKey); string newKey = newValue.ToString().Trim(); if (!_valueRowMap.ContainsKey(newKey)) { _valueRowMap[newKey] = new List<DataGridViewRow>(); } _valueRowMap[newKey].AddRange(targetRows); } } finally { // 恢复原有设置 SensorsTable.RowHeadersVisible = originalRowHeaderVisible; SensorsTable.EnableHeadersVisualStyles = originalHeaderStyle; SensorsTable.ReadOnly = false; SensorsTable.ResumeLayout(); } _isEditing = false; }
3. 复用CellStyle对象
把高亮样式设为全局静态变量,避免每次创建新对象:
// 全局复用的高亮样式 private static readonly DataGridViewCellStyle _highlightStyle = new DataGridViewCellStyle { BackColor = Color.Yellow };
4. 一次性刷新UI
如果允许,修改完所有单元格后调用SensorsTable.Refresh()一次性刷新,替代每个单元格单独触发的UI更新。
内容的提问来源于stack exchange,提问作者pfinferno
相关产品推荐
相关产品推荐

