我已经知道这是不可能的。我是C#和WP开发的新手,所以我只想学习最佳实践,以及如何应对这种情况的方法。这是代码:
public static ObservableCollection<Substance> Substances
{
get
{
if (_substances == null) await Substance.GetSubstanceDataAsync(); // and nothing gets returned anyway
else return _substances;
}
set
{
_substances = value;
}
}
我是否应该在App.xaml.cs GetSubstanceDataAsync();
方法中调用OnLaunched()
,然后对那里的数据进行排序(如果它为空则抛出异常)?或者我应该在每个页面上使用private void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
方法异步并在每次导航页面时检查空值,如果是,则获取数据(这可能是更好的解决方案)?
答案 0 :(得分:3)
如您所知,您的getter永远不会异步。因此,如果您需要一个资源,您只能通过异步方法,那么getter显然不适合这样做。
您可以做的是让您的属性位于实现INotifyPropertyChanged的ViewModel的实例上。这样,您可以在GetSubstanceDataAsync
任务返回时通知侦听器您的Substance属性已更改。非常方便的是,如果在XAML绑定中使用此属性,绑定将自动刷新。
答案 1 :(得分:1)
private ObservableCollection<Substance> _substances;
public static ObservableCollection<Substance> Substances
{
get
{
if (_substances == null) {
GetSubstanceDataAsync();
}
return _substances;
}
set
{
_substances = value;
}
}
private async void GetSubstanceDataAsync(){
Substances = await Substance.GetSubstanceDataAsync();
}
现在,如果您在第一次调用列表时实现INotifyPropertyChanged并且它为空,它将启动异步方法。异步方法完成后,它将更新列表并通知UI有更新。
答案 2 :(得分:1)
根据您实际想要做的事情,有几种不同的可能方法。
如果你想要真正的延迟初始化,那么你应该缓存Task<T>
,即使用Lazy<Task<T>>
(或AsyncLazy<T>
from my AsyncEx library之类的东西)。但是如果这是针对VM类的,那么延迟初始化实际上没有意义(View 总是访问该属性)。
使用VM,您始终可以加载数据,因此您可以在构造函数中开始加载,并在数据到达时更新数据(通过INotifyPropertyChanged
/ INotifyCollectionChanged
)。要记住的重要部分是您希望干净地处理异常。请注意,您的UI将具有(至少)三种不同的状态:加载,成功和错误。当构造函数完成时,它将处于加载状态,然后它将转换为成功或错误状态。
可以对所有这些进行手动编码,或者您可以使用我的MSDN article on async MVVM data binding(也是included in my AsyncEx library)中描述的NotifyTaskCompletion
类型。 NotifyTaskCompletion
实际上只是一个Task<T>
来实现INotifyPropertyChanged
,因此您可以在数据绑定完成时成功响应(成功或出错)。