优化向DataGridView批量添加数据的代码:AddRange使用疑问求解
针对DataGridView批量加万级行的性能优化方案
第一优先级优化:先抑制UI重绘开销
逐行加行慢的核心原因,是每调用一次Rows->Add()就会触发一次控件重绘、布局计算、事件通知的全流程,25000次循环等于产生了25000次无意义的UI渲染开销,这部分可以通过控件自带的批量更新开关直接砍掉:
// 批量操作前关闭重绘锁定 dgv->BeginUpdate(); try { // 所有加行、赋值的逻辑全部写在这个块内 } finally { // 操作完成后恢复重绘,一次性渲染所有内容 dgv->EndUpdate(); }
关于AddRange方法的正确用法
你之前对AddRange的认知存在几个常见误区,按步骤修正就能正常使用:
- 不需要手动对齐列:只要你的
IDColumn、ModColumn、RunColumn已经提前添加到dgv->Columns集合里,后续新建的DataGridViewRow实例不需要手动同步列配置,直接按列索引给单元格赋值即可,不会出现列不匹配的问题 - 不需要等AddRange调用后再填数据:完全可以先把所有行对象的单元格值全部填充完成,再一次性传给AddRange,比先Add再赋值的效率高很多
- 新建行实例的语法修正:C++/CLI下
DataGridViewRow是托管引用类型,不能像值类型那样直接声明,必须用gcnew创建实例,你之前写的DataGridViewRow Test;是无法正常工作的
对应修正后的示例代码:
// 已知总行数等于m_Items->Length,提前初始化对应长度的行集合数组 array<DataGridViewRow^>^ batchRows = gcnew array<DataGridViewRow^>(m_Items->Length); for (int i = 0; i < m_Items->Length; i++) { // 逐次创建独立的托管行实例 batchRows[i] = gcnew DataGridViewRow(); // 直接给对应单元格赋值,和你原来的赋值逻辑完全一致 batchRows[i]->Cells[this->IDColumn->Index]->Value = safe_cast<System::Object^>(0); batchRows[i]->Cells[this->ModColumn->Index]->Value = /* 替换为你原逻辑里的数据库取数 */; batchRows[i]->Cells[this->RunColumn->Index]->Value = /* 替换为你原逻辑里的数据库取数 */; } // 一次性把所有填充好的行批量添加到dgv中 dgv->Rows->AddRange(batchRows);
更高性能的可选优化(适配万级以上行规模)
如果你的行规模达到2.5万甚至更高,手动操作行集合的方式依然会占用较多UI线程资源,可以改用数据绑定模式彻底绕开逐行操作的开销:
- 提前关闭dgv的自动生成列:设置
dgv->AutoGenerateColumns = false,把已有的3个列的DataPropertyName属性绑定到对应数据实体的字段名上 - 准备一个和数据字段一一对应的简单托管实体类
- 把所有从数据库取出的数据实例放到
BindingList<T>集合中,最后直接给dgv->DataSource赋值这个集合
这个模式下,dgv只会在绑定数据源时触发一次全量渲染,整体耗时会比手动AddRange的方式再缩短70%以上,同时内存占用也会更低。
内容的提问来源于stack exchange,提问作者NeonGlow
相关产品推荐
相关产品推荐

