从视图模型的构造函数调用异步方法

Ale*_*lex 2 c# wpf asynchronous mvvm

我正在使用 Entity Framework 6 在 Visual Studio 2015 中构建 MVVM Light WPF 应用程序。该应用程序具有许多调用async初始化方法的视图模型。这是一个示例视图模型:

public class MyViewModel : MyViewModelBase
{
    public MyViewModel()
    {
        PopulateParameters();

        // Other code...
    }

    public ObservableCollection<ParametersViewModel> 
        Parameters { get; private set; } = 
            new ObservableCollection<ParametersViewModel>();

    private async void PopulateParameters()
    {
        var service = new MyDataService();
        Parameters.Clear();
        foreach(var parameter in await service.GetParameters())
            Parameters.Add(parameter);      
    }
    // Other methods and properties
}
Run Code Online (Sandbox Code Playgroud)

MyDataService课堂上,我有这样的方法:

public async Task<ParametersViewModel> GetParameters()
{
    using (var context = new MyEntities())
    {
        var query = (from param in context.Parameters
            select new ParametersViewModel
            {
                // Populate ParametersViewModel properties here...
            }
            );
        return await Task.Run(() => query);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,视图模型的构造函数正在调用async void方法PopulateParameters()。这是非常糟糕的编程,我想改变它。但是,我不确定如何。我无法将必要的数据注入到我的所有视图模型中;有些必须执行自己的初始化,其中大部分涉及对async方法的调用。

当从视图模型的构造函数调用异步方法时,如何更改上述代码以符合最佳实践?谢谢。

更新:确保您绑定到.Result从返回的值NotifyTask.Create()。我花了一段时间才弄清楚这一点。更多信息请参见:https://msdn.microsoft.com/en-us/magazine/dn605875.aspx

Ste*_*ary 5

我有一篇博客文章描述了“异步构造函数”的几种方法。

但在这种情况下,您真正​​想要的是异步数据绑定。使用NotifyTask我的Mvvm.Async 库中的类型将如下所示:

public NotifyTask<ObservableCollection<ParametersViewModel>>
    Parameters { get; private set { /* with notify, such as RaisePropertyChanged() */ } }

public MyViewModel()
{
  Parameters = NotifyTask.Create(() => GetParametersAsync(),
      new ObservableCollection<ParametersViewModel>());
  // Other code...
}

private async Task<ObservableCollection<ParametersViewModel>> GetParametersAsync()
{
  var service = new MyDataService();
  var result = new ObservableCollection<ParametersViewModel>();
  foreach(var parameter in await service.GetParameters())
      result.Add(parameter);
  return result;
}
Run Code Online (Sandbox Code Playgroud)

包装NotifyTask<T>器提供了多个数据可绑定属性,例如Result包含可观察集合、IsNotCompleted用于显示加载指示器和IsFaulted/ErrorMessage用于数据绑定错误条件(如果您愿意)。