异步任务.使用MVVM运行
本文关键字:运行 MVVM 使用 任务 异步 | 更新日期: 2023-09-27 18:17:41
我一直在尝试新的异步CTP和MVVM模式。我一直在转换我的一个旧程序,它使用后台工作器和报告进度来更新我模型中的集合。我把它转换成如下格式
TaskEx.Run(async () =>
{
while (true)
{
// update ObservableCollection here
}
await TaskEx.Delay(500);
});
在我的视图中,我绑定到我的viewmodel,它公开了这个可观察集合。然而,当我的集合更新时,我得到以下异常
这种类型的CollectionView不支持从与Dispatcher线程不同的线程更改其SourceCollection。
我不确定什么是正确的方式拉回UI线程时这样做的
您不必使用Task.Run()
或任何其他特殊方式运行异步方法,只需调用它们。而在你的情况下,这正是导致问题的原因。
给定如下函数:
Action f = async () =>
{
while (true)
{
// modify the observable collection here
await Task.Delay(500);
}
};
从UI线程上运行的某个方法中像这样调用它,比如事件处理程序:
f();
完全按照它应该的方式工作。它执行循环的第一次迭代,然后返回。下一个迭代将在UI线程上的500毫秒(如果UI线程繁忙,则更长)后执行。
另一方面,如果你这样调用它:
Task.Run(addNames);
不能正常工作。这样做的原因是async
方法试图在它们启动时的相同上下文中继续运行(除非您显式地另行指定)。第一个版本是在UI线程上启动的,所以它在UI线程上继续。第二个版本开始于一个ThreadPool线程(多亏了Task.Run()
),并继续在那里。这就是为什么它会导致你的错误。
所有这些都是使用SynchronizationContext
完成的,如果存在的话。
您在主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
}
虽然您无法从第二个线程更新ObservableCollection
,但可以创建异步可观察集合。这允许您从任务内部或未创建集合的线程中更新集合。
我将张贴的例子,但我发现的信息在这里。它非常灵巧,我发现它是一个非常有用的例子。
http://www.thomaslevesque.com/2009/04/17/wpf-binding-to-an-asynchronous-collection/