我想在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";
}
}
亲切的问候
答案 0 :(得分:9)
我最近写了一篇关于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;
}
}
答案 1 :(得分:2)
强制异步方法同步运行通常会导致死锁,所以我不建议这样做。视图模型的特点是它们通常通过INotifyPropertyChanged
PropertyChanged
事件支持更改通知,因此无需立即获取所有数据。实际上,如果您的数据不是硬编码的 - 您不应该期望立即看到数据,并且您很可能希望在加载数据时显示进度指示器。因此...
在构造函数中调用异步初始化方法而不等待结果(因为您无法在构造函数中等待)和初始化方法中所有数据都可用时 - 将其分配给视图绑定到的属性/属性,引发这些属性的PropertyChanged事件,并通过更改控制其可见性的视图模型属性来隐藏进度指示器。