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

绑定CollectionView的ObservableCollection连续Add操作触发异常原因及解决

Collection was modified: enumeration operation may not execute 异常原因及解决方法

问题描述

我编写了如下C#代码:

private void UpdateItems(FocusedItemData data)
{
    items.Clear();

    var newItems = new List<ItemViewModel>();

    // (...)

    foreach (var item in newItems)
        items.Add(item);

    // (...)
}

其中items是绑定到CollectionView的ObservableCollection<ItemViewModel>。在调用第二次items.Add时,触发InvalidOperationException,错误信息为:

Collection was modified: enumeration operation may not execute.

异常原因

核心原因是绑定的CollectionView正在枚举ObservableCollection的过程中,集合结构被修改:

  • ObservableCollection每次执行Add/Clear都会触发CollectionChanged事件,绑定它的CollectionView会立即响应该事件,重新枚举集合以更新UI或执行过滤、排序逻辑。
  • 第一次Add触发事件后,CollectionView可能仍在遍历items集合,此时第二次Add直接改变了集合元素数量,导致正在进行的枚举操作失效,进而抛出该异常。

解决方法

方法1:用CollectionView的DeferRefresh批量更新

通过DeferRefresh()创建延迟更新范围,该范围内的所有集合修改只会触发一次CollectionView更新,避免中间的枚举冲突:

private void UpdateItems(FocusedItemData data)
{
    using (itemsView.DeferRefresh()) // itemsView为绑定的CollectionView实例
    {
        items.Clear();
        var newItems = new List<ItemViewModel>();

        // (...)

        foreach (var item in newItems)
            items.Add(item);
    }
}

方法2:直接替换ObservableCollection实例

如果items属性实现了INotifyPropertyChanged,可以直接替换整个集合实例,避免逐行修改带来的多次变更通知:

private void UpdateItems(FocusedItemData data)
{
    var newItems = new List<ItemViewModel>();

    // (...)

    items = new ObservableCollection<ItemViewModel>(newItems);
    OnPropertyChanged(nameof(items)); // 触发属性变更通知
}

方法3:为ObservableCollection实现AddRange扩展

自定义AddRange扩展方法,批量添加元素时仅触发一次CollectionChanged事件:

public static class ObservableCollectionExtensions
{
    public static void AddRange<T>(this ObservableCollection<T> collection, IEnumerable<T> items)
    {
        foreach (var item in items)
            collection.Items.Add(item);
        
        collection.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
}

使用方式:

private void UpdateItems(FocusedItemData data)
{
    items.Clear();
    var newItems = new List<ItemViewModel>();

    // (...)

    items.AddRange(newItems);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 19:32:47