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

WPF中ListView高亮第15及以上索引行时抛出异常求助

解决ListView Ping服务器高亮时的异常问题

这个问题我之前帮人排查过,大概率是ListView的项回收/虚拟加载机制在搞鬼!你提到当计数器到15(也就是超过可视区域的项数)就抛异常,正好对应ListView的一个特性:当列表项超出当前可视范围时,它会回收那些不在屏幕上的项的UI元素,节省内存。这时候你直接通过索引去访问这些被回收的项,自然会因为对象不存在而抛出异常。

下面给你几个针对性的解决方案,从简单快速修复到长期规范实现都有:


方案1:数据绑定+ViewModel(推荐,长期维护更省心)

不管你用的是WinForms还是WPF,这都是最规范的做法,彻底避免直接操作UI元素的问题:

  • 先定义一个服务器实体类,把IP、名称、Ping结果这些数据封装起来,还要实现属性变更通知(比如WPF/WinForms通用的INotifyPropertyChanged接口):
    public class ServerInfo : INotifyPropertyChanged
    {
        private string _ipAddress;
        private string _serverName;
        private bool _isPingSuccess;
    
        public string IPAddress
        {
            get => _ipAddress;
            set { _ipAddress = value; OnPropertyChanged(); }
        }
    
        public string ServerName
        {
            get => _serverName;
            set { _serverName = value; OnPropertyChanged(); }
        }
    
        public bool IsPingSuccess
        {
            get => _isPingSuccess;
            set { _isPingSuccess = value; OnPropertyChanged(); }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        }
    }
    
  • 把所有服务器数据加载到一个可观察的集合里(WPF用ObservableCollection<ServerInfo>,WinForms用BindingList<ServerInfo>),作为ListView的数据源。
  • 给ListView的行设置样式绑定:把IsPingSuccess属性和背景色关联起来,成功时设为绿色,失败时设为红色。这样不管项是否在可视区域,只要IsPingSuccess的值变了,UI会自动更新对应的行样式。

方案2:WinForms原生ListView快速修复(不想改架构的话)

如果是WinForms且不想重构代码,可以从两个关键点入手:

2.1 绝对避免非UI线程操作UI

Ping操作一定要放在后台线程(比如用Task或者线程池),绝对不能在后台线程直接修改ListView的Item!必须用Invoke切换到UI线程,而且要先检查Item是否存在:

// 后台线程ping完成后,切换到UI线程更新
listView1.Invoke((Action)(() => {
    ListViewItem item = listView1.Items[index];
    if (item != null) { // 先确认项没有被回收
        item.BackColor = pingSuccess ? Color.Green : Color.Red;
    }
}));

2.2 处理虚拟模式(如果开启了的话)

如果你的ListView手动设置了VirtualMode = true,那你不能直接通过Items[index]访问非可视项,要维护一个后台数据列表,ping结果更新后,调用listView1.UpdateItems(index, 1)让ListView重新渲染对应项,而不是直接修改Item的样式。


额外优化建议

  • 不要一次性ping42台服务器,用Task.WhenAll控制并发数量(比如限制同时ping10台),避免网络拥堵或者UI卡顿。
  • WinForms原生ListView的绑定能力较弱,如果你经常做这类UI,可以考虑用第三方控件(比如DevExpress的GridControl),数据绑定和样式控制会更方便。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:09:34