加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

wpf – Async-await似乎使用UI线程

发布时间:2020-12-15 04:15:28 所属栏目:Java 来源:网络整理
导读:在视图模型中,我使用工厂: private async TaskBaseData InitializeAsync(){ await InstancesAsync(); await ProjectsAsync(); await AdminAsync(); return this;}public static async TaskBaseData CreateAsync(){ var ret = new BaseData(); return await
在视图模型中,我使用工厂:

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我得到一个不同的线程拥有该对象的错误.

编辑:使用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;
}

这工作正常,但我无法理解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类的所有属性和可观察集合更新.

在异步方法中,如果不需要返回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;
}

此外,无论何时返回等待,请再看看是否可以完全避免异步/等待:

public static Task<BaseData> CreateAsync()
{
  var ret = new BaseData();
  return ret.InitializeAsync();
}

最后,你应该强烈避免使用Dispatcher.您的Loaded事件可以简化为:

Loaded += async ()
{
  DataContext = await BasisGegevens.CreateAsync();
};

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读