【发布时间】:2013-11-18 16:39:57
【问题描述】:
在视图模型中我使用工厂:
private async Task<BaseData> InitializeAsync()
{
await InstancesAsync();
await ProjectsAsync();
await AdminAsync();
return this;
}
public static async Task<BaseData> CreateAsync()
{
var ret = new BaseData();
return await ret.InitializeAsync();
}
等待的方法相当简单,例如
var instances = await TaskEx.Run(new Func<List<string>>(() => Agent.GetInstances()));
在 wpf 视图中我想在构造函数中设置 DataContext:
Loaded += delegate
{
Dispatcher.Invoke(new Action(async () => { DataContext = await BasisGegevens.CreateAsync(); }));
};
虽然它可以工作,但我感觉很不舒服,因为 UI 线程无处不在,在等待完成时的回调之后也是如此。我错过了什么?
另外我不明白如何为DataContext 使用工厂模式,因为如果没有上面的Invoke,我会收到另一个线程拥有该对象的错误。
编辑:使用克利里先生的想法,我得到:
Loaded += async (object sender, RoutedEventArgs e) =>
{ DataContext = await BaseData.CreateAsync(); };
public static Task<BaseData> CreateAsync()
{
var ret = new BaseData();
return ret.InitializeAsync();
}
private async Task<BaseData> InitializeAsync()
{
// UI thread here
await InstancesAsync().ConfigureAwait(false);
// thread 'a' here
await ProjectsAsync().ConfigureAwait(false);
// thread 'a' sometimes 'b' here
await AdminAsync().ConfigureAwait(false);
// thread 'a' or 'b' here
return this;
}
这很好用,但我无法理解 ConfigureAwait(false) 的工作原理。
在方法InstancesAsync() 里面我有等待的任务:var instances = await TaskEx.Run(new Func<List<string>>(() => Agent.GetInstances()));
等待回复后,我返回 UI 线程 - 我没想到会发生这种情况!
请注意,ProjectsAsync() 和 AdminAsync() 的行为相同,尽管它们从工作(或后台)线程开始!
我认为ConfigureAwait(true) 具有在调用线程(在我的情况下为 UI 线程)中返回的效果。我对此进行了测试,确实如此。
为什么我也看到ConfigureAwait(false):因为嵌套等待,请参阅 cmets。
【问题讨论】:
-
您展示的代码中
Loaded事件的来源是什么?如果这是一个常规的FrameworkElement.Loaded事件,它应该在 UI 线程上触发。您是否在单独的线程上创建视图?这可能是因为您在非 UI 池线程上调用Agent.GetInstances()? -
Loaded 事件是一个常规的 FrameworkElement.Loaded 事件。我打算在 UI 线程上创建视图,这显然是错误的。 Agent.GetInstances() 在等待的任务中运行,我希望它在非 UI 池线程上,但事实并非如此。
-
TaskEx.Run确实使用单独的池线程来运行您的Func委托,这就是执行Agent.GetInstances()的地方。我建议您遵循斯蒂芬的回答,并确保 WPF UI 元素和 ViewModel 对象都是在同一个 UI 线程上创建的。添加一些日志记录 (System.Threading.Thread.CurrentThread.ManagedThreadId) 以查看您在哪个线程上以及在哪里。 -
ConfigureAwait(false)只影响特定的await,它对“内部”的awaits 没有影响。 -
@svick:当然,谢谢,我也查过了。
标签: wpf async-await