异步任务.使用 MVVM 运行

发布于 2024-12-20 11:41:54 字数 422 浏览 4 评论 0原文

我一直在尝试新的异步 CTP 和 MVVM 模式。我一直在转换我的一个旧程序,该程序使用后台工作人员并报告更新模型中集合的进度。我已将其转换为类似的内容

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

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

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

我不确定这样做时将其拉回 UI 线程的正确方法是什么。

I have been playing around with the new async CTP and MVVM patterns. I have been converting an old program of mine that was using a background worker and report progress to update a collection in my model. I have converted it to something like so

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

In my view I bind to my viewmodel which exposes this observable collection. However, when my collection updates I get the following Exception

This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.

I'm not sure what the correct way to pull the is back to the UI thread when done like this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

〃温暖了心ぐ 2024-12-27 11:41:54

您不必使用 Task.Run() 或任何其他特殊方式运行异步方法,只需调用它们即可。就您而言,这正是导致问题的原因。

给定这样的函数:

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

从 UI 线程上运行的某些方法(如事件处理程序)中像这样调用它:

f();

完全按照其应有的方式工作。它执行循环的第一次迭代,然后返回。下一次迭代在 UI 线程上 500 毫秒(或更长,如果 UI 线程繁忙)后执行。

另一方面,如果你这样称呼它:

Task.Run(addNames);

它就不能正常工作。原因是异步方法尝试在启动时的相同上下文中继续(除非您明确指定)。第一个版本是在 UI 线程上启动的,因此它在 UI 线程上继续。第二个版本在 ThreadPool 线程上启动(感谢 Task.Run())并在那里继续。这就是它导致你的错误的原因。

所有这些都是使用 SynchronizationContext,如果存在的话。

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.

变身佩奇 2024-12-27 11:41:54

您在主 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
}

You created an ObservableCollection on the main UI thread, and are trying to update it on an asynchronous background thread, which you cannot do in WPF.

As an alternative, get the results from a background thread, then add them to the ObservableCollection on the main UI thread.

Usually my code for updating an ObservableCollection on a background thread will look something like this:

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
}

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

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

http://www.thomaslevesque.com/ 2009/04/17/wpf-绑定到异步集合/

While it is true that you aren't able to update an ObservableCollection from a second thread, it is possible to create an asynchronous observable collection. This allows you to update the collection from within tasks, or on threads where the collection wasn't created.

I would post the example, but I found the information here. It's pretty slick, and I found it to be a very helpful example.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文