WinRT async data load in constructor

匿名 (未验证) 提交于 2019-12-03 02:06:01

问题:

I want to load some data in the constructor of a ViewModel but due to WinRT's async nature I am forced to use async methods. Unfortunately I cannot have an async constructor so I am trying to use the asynchronous method as a synchronous method. I'm sure there is a much better way of loading data (async) on application load but my mind is drawing a blank at the moment.

I'm either looking for a way to fix my app using the line of thought i'm going down, or to fix this permanently using a more appropriate method.

The code is very simple (even missing the ViewModel) just to demonstrate the issue I'm facing.

public sealed partial class MainPage : Page {      public string Data { get; set; }      public DataService _dataService { get; set; }      public MainPage()     {         this.InitializeComponent();          _dataService = new DataService();         var t = _dataService.GetData();          Data = t.Result;     }      ///      /// Invoked when this page is about to be displayed in a Frame.     ///      /// Event data that describes how this page was reached.  The Parameter     /// property is typically used to configure the page.     protected override void OnNavigatedTo(NavigationEventArgs e)     {     }   }  public class DataService {     public async Task GetData()     {         //Force async         await Task.Delay(1);          return "Hello";     } } 

Kind Regards

回答1:

I wrote a recent blog post about async in constructors.

In short, I prefer an async factory method:

public sealed class MyViewModel : INotifyPropertyChanged {   private readonly DataService _service;    private MyViewModel(DataService service)   {     _service = service;   }    private async Task InitializeAsync()   {     var result = await _service.GetData(); // async initialization      Data = result; // update data-bound properties with the results   }    // Data triggers INotifyPropertyChanged on write   public string Data { get { ... } set { ... } }    public static async Task CreateAsync()   {     var ret = new MyViewModel();     await ret.InitializeAsync();     return ret;   } } 


回答2:

Forcing async methods to run synchronously usually leads to deadlocks, so I would not recommend that. The thing with view models is that they usually support change notifications through INotifyPropertyChanged PropertyChanged event, so there is no need to have all data available immediately. In fact if your data isn't hard-coded - you shouldn't expect to see the data immediately and you would most likely want to show a progress indicator while the data is loading. Thus...

In your constructor call an async initialization method without awaiting the result (since you can't await in a constructor) and in the initialization method when all data is available - assign it to property/properties that your view binds to, raise PropertyChanged event for these properties and hide the progress indicator by changing the view model property that controls its visibility.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!