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

C++ Builder 2009虚拟TListView调用SubItems.Assign触发OnData无限更新

问题原因分析

1. Assign触发死循环的本质

虚拟模式下的TListView,OnData事件的核心作用是响应系统的显示行数据拉取请求,所有会触发控件重绘/更新的操作都会导致系统再次发起数据拉取请求,进而重新触发OnData事件。
TStrings::Assign 方法内部在清空原有内容、批量添加新内容的过程中,会向所属的ListView控件发送内容变更通知,控件收到通知后会触发重绘逻辑,再次进入OnData事件,最终形成死循环。这个行为是虚拟模式的固有设计,不是VCL的Bug,后续版本的VCL也保留了这个逻辑,因为虚拟模式的设计前提就是数据完全由外部维护,控件本身只负责显示,任何数据变更触发重绘都是符合设计预期的。

2. SubItems预分配空间的实现方案

虽然TStrings::Capacity是只读属性,但可以通过以下方案实现一次性预分配空间,避免分次扩容的性能损耗:
直接给SubItems的Count属性设置为你需要的子项总数,这一步会一次性分配足够容纳所有子项的内存空间,不会触发多次扩容,之后直接循环给每个索引的字符串赋值即可,性能远高于逐次Add:

int subCount = Cache.SubItems->Count;
Item->SubItems->BeginUpdate(); // 屏蔽操作过程中的通知,避免额外开销
Item->SubItems->Count = subCount; // 一次性分配空间,Capacity直接等于subCount
for (int x = 0; x < subCount; x++)
{
    Item->SubItems->Strings[x] = Cache.SubItems->Strings[x];
}
Item->SubItems->EndUpdate();

这个方案兼容性最好,适用于所有版本的VCL,完全符合你的优化需求,没有额外的内存重分配开销。

额外优化建议

  • OnData事件处理过程中尽量不要调用任何会修改控件状态的方法,所有数据操作尽量只做纯赋值,避免触发不必要的通知。
  • 如果你的子项数量固定,还可以在缓存中直接维护对应行的所有文本数组,赋值时直接内存拷贝对应字符串内容,进一步提升性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 00:57:00