2011-12-10 68 views
5

我一直在玩新的異步CTP和MVVM模式。我一直在轉換使用後臺工作人員的舊程序,並報告進度以更新模型中的集合。我把它轉換成類似這樣與MVVM異步Task.Run

TaskEx.Run(async() => 
{ 
    while (true) 
    { 
    // update ObservableCollection here 
    } 
    await TaskEx.Delay(500); 
}); 

在我看來,我綁定到我的視圖模型暴露出該觀察的集合。但是,收集更新時,我會收到以下異常

此類CollectionView不支持從與分派器線程不同的線程更改其SourceCollection。

我不確定什麼正確的方法拉回UI線程完成後,像這樣。

+0

作爲一個側面說明,有async'的'在Visual Studio 11開發者預覽版,您可以下載更新的版本。 – svick

回答

5

您不必使用Task.Run()或任何其他特殊方式運行異步方法,只需調用它們即可。而就你而言,這正是導致問題的原因。

給定函數是這樣的:

Action f = async() => 
{ 
    while (true) 
    { 
     // modify the observable collection here 
     await Task.Delay(500); 
    } 
}; 

調用它像這樣從UI線程上的一些方法來看,像一個事件處理程序:

f(); 

作品,正是因爲它應該。它執行循環的第一次迭代,然後返回。下一次迭代在UI線程上500 ms(或更多,如果UI線程繁忙)後執行。

在另一方面,如果你這樣稱呼它:

Task.Run(addNames); 

它不能正常工作。原因是async方法試圖在它們開始時的相同上下文中繼續(除非您明確指定)。第一個版本是在UI線程上啓動的,所以它繼續在UI線程上。第二個版本在ThreadPool線程上啓動(感謝Task.Run())並繼續在那裏。這就是爲什麼它會導致你的錯誤。

所有這些都是使用SynchronizationContext(如果有的話)完成的。

3

您在主UI線程上創建了ObservableCollection,並試圖在異步後臺線程上對其進行更新,而這在WPF中無法完成。

作爲替代方法,從後臺線程獲取結果,然後將它們添加到主UI線程上的ObservableCollection

通常我的後臺線程更新一個ObservableCollection會是這個樣子代碼:

private async void LoadItems() 
{ 
    Task<List<MyItem>> getItemsTask = Task.Factory.StartNew(GetItems); 

    foreach(MyItem item in await getItemsTask) 
     MyCollection.Add(item); 
} 

private List<MyItem> GetItems() 
{ 
    // Make database call to get items 
}