从构造函数或属性运行异步方法

时间:2016-06-28 12:21:43

标签: c# asynchronous mvvm

我正在使用MVVM和WPF,现在我从我的viewmodel类的构造函数中调用async进程,如下所示:  Task.Run(() => this.MyMetho(someParam)).Wait(); 这个问题是屏幕冻结它直到任务结束。

另一种方法是在ViewModel中创建LoadDataMethod并从UserControl_Loaded的事件处理程序中的视图中调用它

private async void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    VMRep vm = (VMRep)this.DataContext;
    await vm.LoadDataMethod();
}

这种方式效果更好,但我想有一种更好的方法来为视图加载异步数据。

感谢您的评论

3 个答案:

答案 0 :(得分:1)

您可以创建异步工厂方法,并使您的构造函数成为私有或受保护的

public static async bool Create() {
    var control = new UserControl();
    return await LoadDataMethod();
}

答案 1 :(得分:1)

  

我想有更好的方法来加载View的异步数据

关键是要意识到所有ViewModel必须立即初始化 。如果您考虑一下,将它们异步初始化是没有意义的,因为当WPF构建您的VM时,它必须立即显示它。从下载完成后不到10秒。

所以,转移一下你的想法,答案会变得更加清晰。您的VM需要立即初始化,但您还没有要显示的数据。因此,适当的做法是立即初始化为一种“加载...”状态,并启动下载数据。当数据到达时,您更新 VM以显示数据。

可以按照你拥有它的方式去做:

private async void UserControl_Loaded(object sender, RoutedEventArgs e)
{
  VMRep vm = (VMRep)this.DataContext;
  await vm.LoadDataMethod();
}

但这并没有为View提供一种干净的方法来检测数据是否正在加载或已完成加载。我写了一个data-bindable Task<T> wrapper(更新版本here)来帮助解决这种情况。它可以像这样使用:

public MyViewModel()
{
  MyData = NotifyTask.Create(LoadDataAsync());
}

public NotifyTask<TMyData> MyData { get; }

然后您的View可以数据绑定到MyData.Result以获取数据,以及其他属性(例如MyData.IsNotCompleted)来显示/隐藏“加载”指示符。

答案 2 :(得分:0)

好吧,既然我不确切知道你想要完成什么,我会尽力给你一个关于Lazy的简要解释

   private Lazy<Task<string>> getInfo;

在这种情况下,我会在您的情况下持有Lazy<Task<string>>的字段Lazy<Task<VMRep>>。我正在使用这个字段,所以你可以在课堂上调用这个懒惰的initialzier。

   public Laziness()
   {
     this.getInfo = new Lazy<Task<string>>(async () => await this.GetInfo());
   }

在构造函数中,我将值赋给惰性字段。在这种情况下使用方法GetInfo()

   public string GetLazyInfo
   {
     get
     {
        return this.getInfo.Value.Result;
     }
   }

使用公共属性公开getInfo字段。并从惰性内部的任务返回结果。

   private async Task<string> GetInfo()
   {
     await Task.Run(async () => await Task.Delay(5000));
     return await Task.Run(() => "test");
   }

最后是你的魔法可以发生的方法。