【问题标题】:WinRT async data load in constructor构造函数中的 WinRT 异步数据加载
【发布时间】:2013-01-22 08:17:09
【问题描述】:

我想在 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";
    }
}

亲切的问候

【问题讨论】:

    标签: c# windows-runtime async-await


    【解决方案1】:

    我最近写了一篇关于 async in 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;
      }
    }
    

    【讨论】:

      【解决方案2】:

      强制异步方法同步运行通常会导致死锁,所以我不建议这样做。视图模型的问题是它们通常通过INotifyPropertyChangedPropertyChanged 事件支持更改通知,因此不需要立即获得所有数据。事实上,如果您的数据不是硬编码的 - 您不应该期望立即看到数据,并且您很可能希望在数据加载时显示进度指示器。于是……

      在您的构造函数中调用异步初始化方法而不等待结果(因为您不能在构造函数中等待)并且在所有数据可用时在初始化方法中 - 将其分配给您的视图绑定的属性,引发PropertyChanged 事件,并通过更改控制其可见性的视图模型属性来隐藏进度指示器。

      【讨论】:

      • 牢记错误处理。如果 async 初始化方法返回的 Task 从未被观察到,那么任何异常都会被默默吞噬。所以一定要在你的InitializeAsync 中有一个try/catch 或者有另一个方法await 结果。
      • 当然。无论调用是在初始化程序中还是在任何其他可能导致错误状态的方法中,这都适用。
      猜你喜欢
      • 1970-01-01
      • 2019-06-13
      • 2017-04-14
      • 2012-08-05
      • 1970-01-01
      • 2013-12-27
      • 2016-06-15
      • 1970-01-01
      • 2014-10-28
      相关资源
      最近更新 更多