简体   繁体   English

从另一个线程更新ObservableCollection的最佳方法是什么?

[英]What's the best way to update an ObservableCollection from another thread?

I am using the BackgroundWorker to update an ObservableCollection but it gives this error: 我使用BackgroundWorker更新ObservableCollection但它给出了这个错误:

"This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread." “这种类型的CollectionView不支持从与Dispatcher线程不同的线程更改其SourceCollection 。”

What's the best and most elegant way to solve this, with the least amount of work. 用最少的工作量来解决这个问题的最佳和最优雅的方法是什么。 I don't want to write low level lock-based multi-threading code. 我不想写低级别的基于锁的多线程代码。

I have seen some solutions online but they are several years old, so not sure what the latest consensus is for the solution of this problem. 我在网上看到了一些解决方案,但它们已有几年的历史了,所以不确定解决这个问题的最新共识是什么。

If you initialize the collection in the constructor it will be on the default Application thread. 如果在构造函数中初始化集合,它将在默认的Application线程上。

To invoke the main thread you can do this: 要调用主线程,您可以执行以下操作:

Application.Current.Dispatcher.Invoke((Action)(() =>
    {
       //Do something here.
    }));

You have to cast the Anonymous delegate as an action otherwise it gets confused ¯\\O_o/¯ 你必须将Anonymous委托作为一个动作,否则会混淆¯\\ _O_o /¯

If you are using the Async CTP then you can do this 如果您使用的是Async CTP,则可以执行此操作

Application.Current.Dispatcher.InvokeAsync(()=>
    {
       //Do something here.
    });

If MVVM 如果是MVVM

public class MainWindowViewModel : ViewModel {

    private ICommand loadcommand;
    public ICommand LoadCommand { get { return loadcommand ?? (loadcommand = new RelayCommand(param => Load())); } }

    private ObservableCollection<ViewModel> items;
    public ObservableCollection<ViewModel> Items {
        get {
            if (items == null) {
                items = new ObservableCollection<ViewModel>();
            }
            return items;
        }
    }

    public void Load() {
        BackgroundWorker bgworker = new BackgroundWorker();
        bgworker.WorkerReportsProgress = true;
        bgworker.DoWork += (s, e) => {
            for(int i=0; i<10; i++) {
                System.Threading.Thread.Sleep(1000);
                bgworker.ReportProgress(i, new List<ViewModel>());
            }
            e.Result = null;
        };
        bgworker.ProgressChanged += (s, e) => {
            List<ViewModel> partialresult = (List<ViewModel>)e.UserState;
            partialresult.ForEach(i => {
                Items.Add(i);
            });
        };
        bgworker.RunWorkerCompleted += (s, e) => {
            //do anything here
        };
        bgworker.RunWorkerAsync();
    }
}

You are using BGW, it was designed to solve your problem. 您正在使用BGW,它旨在解决您的问题。 But you'll have to use it properly, update the collection in a ProgressChanged or RunWorkerCompleted event handler. 但是您必须正确使用它,在ProgressChanged或RunWorkerCompleted事件处理程序中更新集合。 If that's what you are doing then you created the BGW instance on the wrong thread. 如果这就是你正在做的事情,那么你就在错误的线程上创建了BGW实例。 It has to be done on the UI thread. 它必须在UI线程上完成。

Try This: 试试这个:

this.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
() =>
{

 //Code

}));

I had the same problem while reloading an observableCollection from an event (on DataReceived) raised by the serial port class. 从串行端口类引发的事件(在DataReceived上)重新加载observableCollection时,我遇到了同样的问题。 I used MVVM; 我用过MVVM; I tried to update the collection with the BackgroundWorker, but it raised the "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.". 我尝试使用BackgroundWorker更新集合,但它提出“这种类型的CollectionView不支持从与Dispatcher线程不同的线程更改其SourceCollection。”。 I tried many others solutions found online, but the only one that solved my problem (immediately!) was to use a multi-threading observable collection (I used the one in this post: Where do I get a thread-safe CollectionView? ) 我在网上尝试了很多其他的解决方案,但唯一一个解决了我的问题(立即!)是使用多线程可观察集合(我在这篇文章中使用了一个: 我在哪里获得一个线程安全的CollectionView?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM