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

UWP:如何正确回收ListView中的项?

解决ListView异构数据回收时容器类型不匹配的问题

兄弟,这个坑我之前踩过!ListView的内置回收队列在异构列表+加载更多的场景下确实容易犯轴——因为它是栈结构(LIFO),你的“加载更多”容器每次被回收后都会顶在队列最前面,下次需要容器时第一个就给你这个不匹配的类型。下面给你拆解清楚怎么解决,包括微软文档里那个晦涩的relevantStorage到底是什么:

先搞懂微软示例里的relevantStorage

其实它就是你自己维护的「按容器类型分类的自定义回收池」。ListView的内置回收队列是不分类型的,管你是普通数据项还是加载更多项,回收了就往栈里扔,所以才会出现类型不匹配的问题。而自定义回收池就是把不同类型的容器分开存,要用的时候直接取对应类型的。

核心解决方案:拦截内置回收,用自定义池替代

要彻底解决,你需要在ChoosingItemContainer事件里做两件关键操作:

1. 拒绝不匹配的内置容器,并从回收队列移除

当ListView给你返回一个容器时,先判断它的类型和当前要展示的数据项是否匹配:

  • 如果不匹配,绝对不能用这个容器,立刻调用ListViewBase.RemoveItemContainerFromRecycleQueue(container)把它从内置队列里删掉——这一步是关键!不然它会一直待在栈顶,下次还是优先给你返回它。
  • 然后把这个不匹配的容器放到你自己的对应类型回收池里,以后还能复用。

给你一段实际可参考的伪代码:

// 自定义回收池:key是容器类型,value是该类型的可复用容器列表
private Dictionary<Type, List<ListViewItem>> _customRecyclePool = new Dictionary<Type, List<ListViewItem>>();

private void ListView_ChoosingItemContainer(ListViewBase sender, ChoosingItemContainerEventArgs args)
{
    // 第一步:确定当前数据项需要的容器类型
    Type targetContainerType = args.Item is LoadMoreItem 
        ? typeof(LoadMoreItemContainer) 
        : typeof(NormalDataItemContainer);

    // 第二步:检查内置返回的容器是否匹配,不匹配就踢出去
    if (args.ItemContainer != null && args.ItemContainer.GetType() != targetContainerType)
    {
        // 从ListView内置回收队列移除这个不匹配的容器
        sender.RemoveItemContainerFromRecycleQueue(args.ItemContainer);
        
        // 把它放到我们自己的对应类型回收池里
        if (!_customRecyclePool.ContainsKey(args.ItemContainer.GetType()))
        {
            _customRecyclePool[args.ItemContainer.GetType()] = new List<ListViewItem>();
        }
        _customRecyclePool[args.ItemContainer.GetType()].Add(args.ItemContainer);
        
        // 告诉ListView我们不用这个容器,让它重新找(或者我们自己提供)
        args.ItemContainer = null;
    }

    // 第三步:找匹配的容器——先看自定义池里有没有,没有就新建
    if (args.ItemContainer == null)
    {
        if (_customRecyclePool.TryGetValue(targetContainerType, out var availableContainers) && availableContainers.Count > 0)
        {
            args.ItemContainer = availableContainers[0];
            availableContainers.RemoveAt(0);
        }
        else
        {
            args.ItemContainer = Activator.CreateInstance(targetContainerType) as ListViewItem;
        }
        args.IsContainerPrepared = true;
    }

    // 最后绑定数据到容器(这里换成你自己的绑定逻辑)
    BindDataToContainer(args.Item, args.ItemContainer);
}

2. 处理容器回收,把容器导入自定义池

当ListView要回收容器时(比如项被滚出可视区域),你可以监听ContainerContentChanging事件的Phase == -1状态(代表容器即将被回收),把容器从ListView的内置队列转移到你的自定义池里。另外,记得在页面卸载时清理自定义池里的容器,避免内存泄漏。

为什么你的加载更多容器总是优先被返回?

因为ListView的内置回收队列是**后进先出(LIFO)**的栈结构,你的加载更多容器每次完成加载后被回收,都会被压到栈顶,下次需要容器时第一个就弹出它,自然就会持续出现类型不匹配的问题。而我们用RemoveItemContainerFromRecycleQueue把它从内置栈里移除,放到自己的对应类型池里,就不会再被错误分配给普通数据项了。

关键要点回顾

  • 别依赖ListView的内置回收队列处理异构容器,必须自己按类型分类管理回收池。
  • 遇到不匹配的容器时,一定要调用RemoveItemContainerFromRecycleQueue从内置队列移除,这是解决“持续返回错误容器”的核心。
  • 微软文档里的relevantStorage就是自定义回收池的代名词,本质就是按容器类型分组的可复用容器列表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:44:31