ListView.Items(0).Selected触发System.NullReferenceException问题排查
你遇到的MyListView.Items(0).Selected = True抛出空引用异常,即便前置条件检查了MyBooleanVariable为真、MyListView.Items.Count>0且SelectedItems.Count=0,依然可能存在以下几个潜在的空对象场景:
MyListView控件本身为Nothing:
虽然你检查了Items.Count,但如果控件未完成初始化(比如在窗体Load事件前执行代码)、控件已被Disposed,或者跨线程操作未通过Invoke切换到UI线程,都可能导致MyListView实例为null。比如异步加载数据时,用户已经关闭了包含该控件的窗体,但后台代码仍在执行。Items(0)对应的ListViewItem为Nothing:
理论上Items.Count>0时Items(0)必然存在,但多线程并发修改Items集合时会出现竞态条件——你检查完Count之后,另一个线程刚好移除了第一项,此时Items(0)就会返回null。比如后台线程在更新文件列表,刚好在你检查Count和设置选中之间删除了第一个条目。ListViewItem的Selected属性内部依赖空对象:
极少数情况下,ListViewItem的Selected属性内部会依赖控件的句柄(Handle)或其他内部对象,如果控件还未创建句柄(比如控件还没显示到界面上),设置Selected时可能触发空引用异常。
排查与修复建议
增加MyListView的null检查:
即便有前置检查,也在操作前显式判断:If MyListView IsNot Nothing AndAlso MyListView.Items.Count > 0 Then MyListView.Items(0).Selected = True End If锁定Items集合避免并发修改:
如果存在多线程操作ListView的场景,在检查和设置选中的代码块上加锁:SyncLock MyListView.Items.SyncRoot If MyListView.Items.Count > 0 AndAlso MyListView.SelectedItems.Count = 0 Then MyListView.Items(0).Selected = True End If End SyncLock确保在UI线程执行控件操作:
跨线程操作控件会导致不可预知的状态,用Invoke切换到UI线程:If MyListView.InvokeRequired Then MyListView.Invoke(Sub() If MyListView.Items.Count > 0 AndAlso MyListView.SelectedItems.Count = 0 Then MyListView.Items(0).Selected = True End If End Sub) Else If MyListView.Items.Count > 0 AndAlso MyListView.SelectedItems.Count = 0 Then MyListView.Items(0).Selected = True End If End If增加日志细化状态:
在异常可能发生的代码前后,记录关键对象的状态,方便下次异常时定位:Try Logger.WriteLine($"MyListView状态:{If(MyListView Is Nothing, "Null", "正常")}") If MyListView IsNot Nothing Then Logger.WriteLine($"Items.Count:{MyListView.Items.Count},Items(0)状态:{If(MyListView.Items.Count>0 AndAlso MyListView.Items(0) Is Nothing, "Null", "正常")}") End If MyListView.Items(0).Selected = True Catch ex As NullReferenceException Logger.WriteLine($"异常时状态:MyListView={MyListView Is Nothing}, Items.Count={If(MyListView IsNot Nothing, MyListView.Items.Count, -1)}, Items(0)={If(MyListView IsNot Nothing AndAlso MyListView.Items.Count>0, MyListView.Items(0) Is Nothing, True)}") Throw End Try
内容的提问来源于stack exchange,提问作者grimoiredark

