一套零部件检测软件刚上线时,历史记录可能只有几千条。产线持续运行,尺寸测量、性能测试、质量判定不断写入,列表很快累积到 5 万条、50 万条。数据库能存下这些数据,但桌面端表格却越来越卡:初始化慢、滚动掉帧、内存占用往上蹿。
根子在于普通 Grid 把所有记录都实例化成表格对象。5 万行、10 列就是 50 万个单元格位置,每个单元格还要维护状态、颜色、格式和计算逻辑,开销随行数放大。BCGControlBar Pro 提供的 Virtual Grid,思路不是继续堆对象,而是让 Grid 只记录“有多少行”,等界面滚动到某个位置时,再通过回调向应用取数。这篇文章就来拆解它的用法、回调该写什么,以及选型前必须知道的边界。
检测记录 50 万行,普通 Grid 为什么扛不住?
在检测软件里,一行通常对应一条记录:零件编号、工序、测点、理论值、实测值、公差、时间、判定结果。列数虽然不多,单元格里经常还要加状态色、图标、条件格式。
BCGControlBar Pro 常规的 CBCGPGridCtrl 由行对象和单元格项构成。行数一上去,对象数量就会跟着涨:
- 5 万行 × 10 列 = 50 万个单元格位置
- 50 万行 × 10 列 = 500 万个单元格位置
如果每个单元格都带样式或图标,初始化时间、内存占用和刷新体验都会变差。
Virtual Grid 与普通 Grid 到底差在哪?
核心差别在于“数据由谁持有”:普通 Grid 由控件自己持有全部行和单元格对象;Virtual Grid 只保留一个逻辑行数,显示内容通过回调在需要时动态提供。
启用 Virtual Mode
↓
设置逻辑行数
↓
Grid 请求行列位置
↓
应用回调返回显示值
可以把数据库想象成仓库:普通 Grid 是提前把要展示的记录逐条搬上展台;Virtual Grid 则是先登记“仓库里有多少货”,等工程师滚动到某个位置时,再取出对应内容。
实现这两行代码就够了:
grid.EnableVirtualMode(GridCallback); // 注册取数回调
grid.SetVirtualRows(totalRows); // 设置逻辑行数
图1 BCGSoft 官方示例把虚拟行数设为 1 亿,说明 Virtual Mode 的逻辑行数可以配置得很大
| 对比维度 | 普通 Grid | Virtual Grid |
|---|---|---|
| 数据准备 | 应用创建并填充行、单元格 | 先设置逻辑行数 |
| 内容获取 | 控件持有已创建的 Grid 对象 | 控件按位置请求,应用回调返回值 |
| 更适合 | 数据量可控、直接操作行对象 | 大规模连续记录、按需显示 |
| 开发重点 | 行与单元格的创建维护 | 行号映射、缓存与回调效率 |
回调里该写什么?行号映射与缓存要注意什么
回调的本质是:Grid 告诉应用“我现在要显示第几行第几列”,应用返回对应值。因此回调里最关键的两件事是行号映射和数据缓存。
行号映射解决“Grid 看到的行号”与“数据记录实际索引”的对应关系。数据已按显示顺序排好,直接按行号取;支持排序或筛选时,回调里要先做一层映射。
数据缓存解决“不要每次取数都查一次数据库”。回调执行频率高,滚动、刷新、重绘都会触发,如果每个单元格都走一次慢查询,界面照样会卡。常见做法是按页预加载一批记录到内存,回调只从缓存里读。
注意: Virtual Grid 只优化了显示层的数据提供方式,不会自动优化数据库查询、网络传输、排序或筛选。回调里的慢查询是性能的第一杀手。
启用 Virtual Mode 前确认:数据总量与典型显示行数、是否支持排序/筛选、缓存策略、回调访问成本。
什么时候该用 Virtual Grid?三种方案怎么选
面对长列表,通常有三条路:
| 方案 | 适合场景 | 代价 |
|---|---|---|
| 限制单次查询或分页 | 业务天然按工单、日期、批次分段 | 需要重新设计查询和翻页交互 |
| 自建虚拟化机制 | 有极强的自定义需求 | 自己处理行号、缓存、刷新、状态同步 |
| BCGControlBar Pro Virtual Grid | 大规模连续记录,且已在用 BCGControlBar Pro | 回调和映射逻辑必须写对 |
连续滚动、定位和对比多的场景,Virtual Grid 值得优先纳入原型测试;业务天然分段时,分页可能更简单。