WinForm自定义绘制ListBox条目时频繁闪烁卡顿问题求解
问题根因
你当前遇到的卡顿闪烁完全由DrawItem事件的不合理逻辑导致:
- 绘制单条ListBox条目时,重复调用Excel COM接口读取
B1:B20范围,Excel交互本身耗时极高,且该操作会在ListBox每次重绘时被触发数百上千次 - 多余的20次循环逻辑会让同一个条目文字被重复绘制20次,完全属于无效操作
- 仅开启窗体双缓冲不生效,因为ListBox控件本身默认未开启双缓冲,且你逻辑的性能问题远大于绘制本身的闪烁问题
优化方案
第一步:提前缓存Excel数据
不要在绘制事件中操作Excel,在窗体加载、ListBox绑定数据的阶段一次性读取B列的数量值,存储到本地集合:
' 窗体级别变量,存储B列数量缓存 Dim ItemCountCache As New List(Of Integer)() ' 放在你填充ListBox的逻辑后面,一次性读取Excel数据 DataRange = WS.Range("B1:B20") ItemCountCache.Clear() For Each cell In DataRange ItemCountCache.Add(CInt(cell.Value)) Next
第二步:修复DrawItem逻辑
删除多余循环,直接读取对应索引的缓存判断颜色:
Private Sub P_List_LB_DrawItem(sender As Object, e As System.Windows.Forms.DrawItemEventArgs) Handles P_List_LB.DrawItem e.DrawBackground() ' 边界判断,避免索引溢出 If e.Index < 0 OrElse e.Index >= P_List_LB.Items.Count OrElse e.Index >= ItemCountCache.Count Then Exit Sub End If ' 直接读缓存判断颜色,不需要循环、不需要操作Excel Dim brush = If(ItemCountCache(e.Index) > 0, Brushes.Black, Brushes.Gray) e.Graphics.DrawString(P_List_LB.Items(e.Index).ToString(), e.Font, brush, e.Bounds.Location) ' 补充绘制焦点框,避免选中状态显示异常 e.DrawFocusRectangle() End Sub
第三步:给ListBox开启双缓冲(可选,进一步优化闪烁)
在窗体构造函数或者Load事件中添加以下代码,通过反射开启ListBox的双缓冲:
Dim flag As System.Reflection.BindingFlags = System.Reflection.BindingFlags.NonPublic Or System.Reflection.BindingFlags.Instance Dim method As System.Reflection.MethodInfo = GetType(Control).GetMethod("SetStyle", flag) Dim parameters As Object() = {ControlStyles.OptimizedDoubleBuffer Or ControlStyles.AllPaintingInWmPaint, True} method.Invoke(P_List_LB, parameters)
内容的提问来源于stack exchange,提问作者Patrick
相关产品推荐
相关产品推荐

