Qual é a melhor maneira de atualizar um ObservableCollection de outro thread?

Eu estou usando o BackgroundWorker para atualizar um ObservableCollection mas dá este erro:

“Esse tipo de CollectionView não suporta alterações em seu SourceCollection de um encadeamento diferente do encadeamento do Dispatcher.”

Qual é a melhor e mais elegante maneira de resolver isso, com o mínimo de trabalho. Eu não quero escrever código multi-threading baseado em bloqueio de baixo nível.

Já vi algumas soluções on-line, mas elas têm vários anos, portanto, não tenho certeza qual é o consenso mais recente para a solução desse problema.

Se MVVM

 public class MainWindowViewModel : ViewModel { private ICommand loadcommand; public ICommand LoadCommand { get { return loadcommand ?? (loadcommand = new RelayCommand(param => Load())); } } private ObservableCollection items; public ObservableCollection Items { get { if (items == null) { items = new ObservableCollection(); } 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()); } e.Result = null; }; bgworker.ProgressChanged += (s, e) => { List partialresult = (List)e.UserState; partialresult.ForEach(i => { Items.Add(i); }); }; bgworker.RunWorkerCompleted += (s, e) => { //do anything here }; bgworker.RunWorkerAsync(); } } 

Se você inicializar a coleção no construtor, ela estará no encadeamento do Aplicativo padrão.

Para invocar o thread principal, você pode fazer isso:

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

Você tem que converter o delegado anônimo como uma ação caso contrário ele fica confuso ¯ \ O_o / ¯

Se você estiver usando o CTP Async, então você pode fazer isso

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

Você está usando o BGW, ele foi projetado para resolver o seu problema. Mas você terá que usá-lo corretamente, atualize a coleção em um manipulador de events ProgressChanged ou RunWorkerCompleted. Se é isso que você está fazendo, você criou a instância do BGW no thread errado. Isso precisa ser feito no thread da interface do usuário.

Tente isto:

 this.Dispatcher.Invoke(DispatcherPriority.Background, new Action( () => { //Code })); 

Eu tive o mesmo problema ao recarregar um observableCollection de um evento (em DataReceived) gerado pela class de porta serial. Eu usei o MVVM; Eu tentei atualizar a coleção com o BackgroundWorker, mas levantou o “Este tipo de CollectionView não suporta alterações para seu SourceCollection de um segmento diferente do thread do Dispatcher.”. Eu tentei muitas outras soluções encontradas on-line, mas o único que resolveu o meu problema (imediatamente!) Foi usar uma coleção observável multi-threading (eu usei o deste post: Onde posso obter um CollectionView thread-safe? )