在视图模型中,我使用工厂:
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();
}
Run Code Online (Sandbox Code Playgroud)
等待的方法相当明确,例如
var instances = await TaskEx.Run(new Func<List<string>>(() => Agent.GetInstances()));
Run Code Online (Sandbox Code Playgroud)
在wpf视图中,我想在构造函数中设置DataContext:
Loaded += delegate
{
Dispatcher.Invoke(new Action(async () => { DataContext = await BasisGegevens.CreateAsync(); }));
};
Run Code Online (Sandbox Code Playgroud)
虽然它有效,但我感到相当不舒服,因为UI线程在任何地方都可以使用,也可以在等待完成后的回调之后使用.我错过了什么?
另外我不明白如何使用工厂模式,DataContext因为没有Invoke上面我得到一个不同的线程拥有该对象的错误.
编辑:使用Cleary先生的想法我得到:
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;
}
Run Code Online (Sandbox Code Playgroud)
这工作正常,除了我无法理解如何ConfigureAwait(false)工作.
在方法内部,InstancesAsync()我有等待的任务:
var instances = await TaskEx.Run(new Func<List<string>>(() => Agent.GetInstances()));
在等待repsonse之后,我返回UI线程 - 我从没想过会发生这种情况!
注意ProjectsAsync()并且AdminAsync()行为相同,尽管它们是在工作者(或背景)线程上开始的!
我认为它ConfigureAwait(true)具有在调用线程中返回的效果(在我的情况下是UI线程).我测试过它就是这样.
为什么我也看到这个ConfigureAwait(false):因为嵌套await,请参阅注释.
我认为将ViewModel视为具有UI线程关联性是最有用的.将其视为逻辑UI,即使它不是实际的 UI.因此,应该在UI线程上完成ViewModel类的所有属性和可观察集合更新.
在您的async方法中,如果您不需要返回UI线程,则可以使用ConfigureAwait(false)以避免在UI线程上恢复.例如,如果您的各种初始化方法是独立的,您可以执行以下操作:
private async Task<BaseData> InitializeAsync()
{
// Start all methods on the UI thread.
var instancesTask = InstancesAsync();
var projectsTask = ProjectsAsync();
var adminTask = AdminAsync();
// Await for them all to complete, and resume this method on a background thread.
await Task.WhenAll(instancesTask, projectsTask, adminTask).ConfigureAwait(false);
return this;
}
Run Code Online (Sandbox Code Playgroud)
此外,只要你有return await,再看看你是否可以完全避免async/ await完全:
public static Task<BaseData> CreateAsync()
{
var ret = new BaseData();
return ret.InitializeAsync();
}
Run Code Online (Sandbox Code Playgroud)
最后,你应该强烈避免Dispatcher.您的Loaded活动可以简化为:
Loaded += async ()
{
DataContext = await BasisGegevens.CreateAsync();
};
Run Code Online (Sandbox Code Playgroud)