【问题标题】:Async operations and UI update异步操作和 UI 更新
【发布时间】:2015-07-26 21:37:45
【问题描述】:

在由 caliburn micro 和 telerik 控件组成的 wpf 应用程序中,我有不同的屏幕,它们从远程服务加载数据,然后在 gridview /fills 组合框中显示数据。 我正在使用同步/等待运算符进行加载检索操作,但我几乎可以肯定它有一些瓶颈。 正在等待我让主 UI 线程等待与工作线程同步...考虑这个示例

Public class MyViewModel:Screen
{
  [omiss]

Public bool IsBusy {get;set;}  
 Public list<Foo> DropDownItems1 {get;set;}
Public  list<Foo2> DropDownItems2 {get;set;}

  Public async Void Load()
  {
    IsBusy =true;
     DropDownItems1 = await repository.LoadStates();
     DropDownItems2 = await repository.LoadInstitutes();
     IsBusy = false;
  }

}

在这种情况下,我已经加载了第一个任务,然后加载了第二个没有并行性......我该如何优化这个? 关于通过约定绑定到繁忙指示器的 IsBusy 属性如何正确设置? 谢谢

更新#1:

我是我真正的代码

public async Task InitCacheDataTables()
    {
        var taskPortolio = GetPortfolio();
        var taskInstitutes = GetInstitutes();
        var taskStatus = GetStatus();
        var taskCounterparts = GetCounterparts();
        var taskCrosses = GetCrosses();
        var taskCurrencies = GetCurrencies();
        var taskSigns = GetSigns();

        await TaskEx.WhenAll(new[] { taskPortolio, taskInstitutes, taskStatus, taskCounterparts, taskCrosses, taskCurrencies, taskSigns });
    }

任务在哪里

 private async Task GetPortfolio()
    {
        try
        {
            dynamicContainer.SetValue(UserContainerKeyHelper.Portfolios, await commonRepository.GetPortfoliosAsync());
        }
        catch (Exception ex)
        {
            errorHandler.HandleErrorAsync(ex);
        }
    }
    private async Task GetInstitutes()
    {
        try
        {
            dynamicContainer.SetValue(UserContainerKeyHelper.Institutes, await commonRepository.GetInstitutesAsync());
        }
        catch (Exception ex)
        {
            errorHandler.HandleErrorAsync(ex);
        }
    }

在调试时,我发现所有方法都在 MainThread 上执行……不应该在工作线程上吗?

【问题讨论】:

  • 如果您希望的优化是运行两个并行后台线程而不是一个?您可以使用System.Threading.Tasks.Task.WhenAll() 方法。 IsBusy 赋值看起来不错,但假设您的 ViewModel 实现了 INotifyPropertyChanged,则每次设置属性内容时都需要 onPropertyChanged("IsBusy") 之类的东西,以便通知 XAML“视图”
  • OT:将逻辑放在 try...finaly 块中,因此您始终将 IsBusy 设置为 false,如果发生异常则事件:IsBusy=True; try{....} finally {IsBusy=False;}

标签: c# wpf multithreading async-await caliburn.micro


【解决方案1】:

在这种情况下,我先加载了任务,然后加载了第二个任务,没有并行性……我该如何优化呢?

您需要并发,而不是并行。您可以使用Task.WhenAll 来等待它们,而不是依次等待每个任务:

public async Task LoadAsync()
{
     IsBusy = true;

     var firstDropDownItemsTask = repository.LoadStates();
     var secondDropDownItemsTask = repository.LoadInstitutes();

     await Task.WhenAll(DropDownItems1Task, DropDownItems2Task);

     DropDownItems1 = firstDropDownItemsTask.Result;
     DropDownItems2 = secondDropDownItemsTask.Result;

     IsBusy = false;
}

通过约定绑定到繁忙指示器的 IsBusy 属性如何正确设置?

通常,通过约定绑定的项目需要实现 INotifyPropertyChanged 才能更新已更新值的 xaml 绑定。

【讨论】:

  • 是的,它是通过 Caliburn Micro 约定绑定的,是的,它实现了 INotiftyPropertyChanged... 最好在 repo 中尝试捕获?如果 LoadStates 因 Task.WhenAll 失败会发生什么?
  • 这取决于您的设计决策。如果您在回购级别处理异常,请执行此操作。如果您在业务层处理异常,则需要将 LoadAsync 包装在 try-catch 中并在那里处理。
  • 但是如果 Task[] 中的某些东西失败了,那么它会停止其他线程,对吗?就我所见,它没有引发聚合异常
  • @advapi 您的回购查询中没有额外的线程。我建议你read the docs
  • 谢谢,我已经更新了主帖,因为我注意到一切都在 UI 线程上进行
猜你喜欢
  • 2018-09-30
  • 1970-01-01
  • 1970-01-01
  • 2019-11-07
  • 1970-01-01
  • 2014-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多