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

在异步Task中使用ObservableCollection的AddRange方法时遭遇NotSupportedException

解决异步Task中操作ObservableCollection的AddRange抛出NotSupportedException的问题

兄弟,你碰到的这个问题核心原因其实很明确,咱们拆解来看:

首先,.NET默认的ObservableCollection<T>根本没有内置的AddRange方法——如果你是自己写了扩展方法实现这个功能,那问题的关键不在方法本身,而是你在Task.Run开启的**后台线程(非UI线程)**里直接修改了绑定到UI的集合。ObservableCollection是线程不安全的,它只能在创建它的线程(也就是UI线程)上进行修改操作,跨线程修改就会抛出NotSupportedException。

另外你更新Status属性的操作如果是绑定到UI的,同样要注意必须在UI线程执行,否则也可能引发绑定异常。

下面给你两种常见UI框架下的解决方案:

方案1:WPF/Windows Forms场景

用Dispatcher将操作调度回UI线程:

private ObservableCollection<CoronavirusCountry> _data = new ObservableCollection<CoronavirusCountry>();
public ObservableCollection<CoronavirusCountry> data { get => _data; set => SetProperty(ref _data, value); }

Task.Run(async()=>{
    APIService service = new APIService();
    // 先在后台线程完成数据请求,避免阻塞UI
    var newData = await service.GetTopCases();
    
    // 切换到UI线程更新集合和状态
    Application.Current.Dispatcher.Invoke(() => {
        data.AddRange(newData);
        Status = "Updated " + DateTime.Now;
    });
});

方案2:MAUI/Blazor WebAssembly场景

用MainThread切换到UI线程:

private ObservableCollection<CoronavirusCountry> _data = new ObservableCollection<CoronavirusCountry>();
public ObservableCollection<CoronavirusCountry> data { get => _data; set => SetProperty(ref _data, value); }

Task.Run(async()=>{
    APIService service = new APIService();
    var newData = await service.GetTopCases();
    
    // 异步调度到UI线程执行更新
    await MainThread.InvokeOnMainThreadAsync(() => {
        data.AddRange(newData);
        Status = "Updated " + DateTime.Now;
    });
});

补充:如果你的AddRange是自定义扩展方法

记得要实现高效的集合变更通知(一次性触发事件,而非循环触发单个Add的通知),示例如下:

public static void AddRange<T>(this ObservableCollection<T> collection, IEnumerable<T> items)
{
    if (collection == null) throw new ArgumentNullException(nameof(collection));
    if (items == null) throw new ArgumentNullException(nameof(items));

    // 先批量添加到内部集合
    foreach (var item in items)
    {
        collection.Items.Add(item);
    }
    
    // 一次性触发集合变更通知,减少UI刷新次数
    collection.TriggerCollectionChanged(items.ToList());
}

// 辅助方法:调用ObservableCollection的保护方法触发事件
private static void TriggerCollectionChanged<T>(this ObservableCollection<T> collection, List<T> addedItems)
{
    var eventHandler = typeof(ObservableCollection<T>)
        .GetProperty("CollectionChanged", BindingFlags.NonPublic | BindingFlags.Instance)?
        .GetValue(collection) as NotifyCollectionChangedEventHandler;
    
    eventHandler?.Invoke(collection, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, addedItems));
}

最后再提醒一句:所有绑定到UI的属性、集合的修改操作,都必须在UI线程执行,这是UI框架的基本线程安全规则,别偷懒哦😉

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 15:18:14