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

遍历带复选框的虚拟ListView锯齿数组时触发非越界异常求助

虚拟ListView选中状态访问异常的解决方案

问题根源

虚拟模式(VirtualMode=true)下的ListView不会为所有项创建ListViewItem实例,仅会实例化当前可见的项。直接通过索引访问非可见项的属性(如Checked、Text)时,会触发ArgumentOutOfRangeException——因为这些项并未被ListView实际创建,看似数组长度足够,但对应的ListViewItem对象根本不存在。

解决思路

放弃通过ListViewItem实例获取选中状态,改为自己维护独立的数据源,全程用数据源管理项的文本和选中状态:

  • 用二维数组(或其他集合)存储每个文件夹下所有项的选中状态和文本内容
  • 在ListView的RetrieveVirtualItem事件中,将数据源的数据绑定到ListView项
  • 用户操作复选框时,在对应事件中更新数据源的状态
  • 遍历数据时直接读取自己维护的数据源,而非访问ListViewItem

修改后的代码示例

1. 维护独立数据源

// 全局或类级别的数据源:存储每个文件夹下项的文本和选中状态
string[][] itemTexts;
bool[][] itemCheckedStates;

// 初始化数据源(需与文件夹/项数量匹配)
itemTexts = new string[myListViewItems.Length][];
itemCheckedStates = new bool[myListViewItems.Length][];
for (int folder = 0; folder < myListViewItems.Length; folder++)
{
    int rowLength = rowLengths[folder];
    itemTexts[folder] = new string[rowLength];
    itemCheckedStates[folder] = new bool[rowLength];
    // 初始化文本(仅首次从原始数据读取,后续不再访问myListViewItems)
    for (int item = 0; item < rowLength; item++)
    {
        itemTexts[folder][item] = myListViewItems[folder][item].Text;
        itemCheckedStates[folder][item] = false; // 默认未选中
    }
}

2. 遍历数据源生成TagData

for (int folder = 0; folder < myListViewItems.Length; folder++)
{
    int rowLength = rowLengths[folder];
    programs[folder].Tags = new TagData[rowLength];

    for (int item = 0; item < rowLength; item++)
    {
        try
        {
            // 直接从自定义数据源读取,避免访问不存在的ListViewItem
            var text = itemTexts[folder][item];
            var isChecked = itemCheckedStates[folder][item];
            programs[folder].Tags[item] = new TagData(text, isChecked);
        }
        catch (Exception ex)
        {
            AddMessage($"myListViewTags[] = {myListViewItems.Length}. myListViewTags[][] = {myListViewItems[folder].Length}");
            AddMessage(ex.Message);
        }
    }
}

3. 绑定ListView虚拟项事件

// RetrieveVirtualItem事件:为可见项绑定数据源数据
private void listView_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
    int currentFolder = GetCurrentSelectedFolderIndex(); // 需实现此方法,获取TreeView当前选中的文件夹索引
    if (currentFolder >= 0 && e.ItemIndex < itemTexts[currentFolder].Length)
    {
        e.Item = new ListViewItem(itemTexts[currentFolder][e.ItemIndex]);
        e.Item.Checked = itemCheckedStates[currentFolder][e.ItemIndex];
    }
}

// ItemChecked事件:用户点击复选框时同步更新数据源
private void listView_ItemChecked(object sender, ItemCheckedEventArgs e)
{
    int currentFolder = GetCurrentSelectedFolderIndex();
    if (currentFolder >= 0 && e.Item.Index < itemCheckedStates[currentFolder].Length)
    {
        itemCheckedStates[currentFolder][e.Item.Index] = e.Item.Checked;
    }
}

关键注意事项

  • 必须确保rowLengths数组与数据源的维度完全匹配,避免索引错位
  • 切换TreeView文件夹时,需同步更新ListView的VirtualListSize为当前文件夹的项数量
  • 虚拟模式下绝对不要直接遍历所有ListViewItem实例,所有状态和数据都要通过自定义数据源管理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 08:53:12