6

我一直在玩新的异步 CTP 和 MVVM 模式。我一直在转换我的一个旧程序,它使用后台工作程序并报告进度以更新我的模型中的集合。我已将其转换为类似的东西

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

在我看来,我绑定到我的视图模型,它公开了这个可观察的集合。但是,当我的收藏更新时,我得到以下异常

这种类型的 CollectionView 不支持从不同于 Dispatcher 线程的线程更改其 SourceCollection。

我不确定当这样完成时,拉回 UI 线程的正确方法是什么。

4

3 回答 3

6

You don't have to run async methods using Task.Run(), or any other special means, just call them. And in your case, that's exactly what is causing the problem.

Given function like this:

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

Calling it like this from some method run on the UI thread, like an event handler:

f();

works exactly as it should. It executes the first iteration of the cycle and then returns. The next iteration is executed after 500 ms (or more, if the UI thread is busy) on the UI thread.

On the other hand, if you call it like this:

Task.Run(addNames);

it doesn't work correctly. The reason for this is that async methods try to continue in the same context as they were started (unless you explicitly specify otherwise). The first version was started on the UI thread, so it continued on the UI thread. The second version started on a ThreadPool thread (thanks to Task.Run()) and continued there too. Which is why it caused your error.

All this is done using SynchronizationContext, if one is present.

于 2011-12-11T01:25:32.383 回答
4

您在ObservableCollection主 UI 线程上创建了一个,并试图在异步后台线程上对其进行更新,而这在 WPF 中是无法做到的。

作为替代方案,从后台线程获取结果,然后将它们添加到ObservableCollection主 UI 线程上。

通常,我在后台线程上更新 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
}
于 2011-12-14T19:42:12.073 回答
3

虽然您确实无法ObservableCollection从第二个线程更新 an,但可以创建异步 observable 集合。这允许您从任务内或在未创建集合的线程上更新集合。

我会发布示例,但我在这里找到了信息。它非常漂亮,我发现它是一个非常有用的例子。

http://www.thomaslevesque.com/2009/04/17/wpf-binding-to-an-asynchronous-collection/

于 2012-03-02T18:43:03.100 回答