8

我想在 ViewModel 的构造函数中加载一些数据,但由于 WinRT 的异步特性,我被迫使用异步方法。不幸的是,我不能有一个异步构造函数,所以我试图将异步方法用作同步方法。我确信有一种更好的方法可以在应用程序加载时加载数据(异步),但目前我的想法是一片空白。

我正在寻找一种方法来使用我正在下降的思路来修复我的应用程序,或者使用更合适的方法永久修复这个问题。

代码非常简单(甚至缺少 ViewModel)只是为了演示我面临的问题。

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;
    }

    /// <summary>
    /// Invoked when this page is about to be displayed in a Frame.
    /// </summary>
    /// <param name="e">Event data that describes how this page was reached.  The Parameter
    /// property is typically used to configure the page.</param>
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
    }


}

public class DataService
{
    public async Task<string> GetData()
    {
        //Force async
        await Task.Delay(1);

        return "Hello";
    }
}

亲切的问候

4

2 回答 2

9

我最近写了一篇关于asyncin constructors的博客文章。

简而言之,我更喜欢async工厂方法:

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<MyViewModel> CreateAsync()
  {
    var ret = new MyViewModel();
    await ret.InitializeAsync();
    return ret;
  }
}
于 2013-01-22T00:08:13.977 回答
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.

于 2013-01-22T00:17:09.557 回答