异步加载ViewModel中的数据(使用async和await)不能使用数据绑定
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异步加载ViewModel中的数据(使用async和await)不能使用数据绑定相关的知识,希望对你有一定的参考价值。
我开始使用默认模板的手机应用程序,该模板已经定义了视图模型。我修改了MainViewModel的LoadData()方法,以异步方式调用odata服务。但它不适用于数据绑定。我已验证调用已成功返回,但未显示任何结果。
LongListSelector的items源绑定到视图模型中的Items属性。
<phone:LongListSelector ItemsSource="{Binding Items}" x:Name="MainLongListSelector" Margin="0,0,-12,0" SelectionChanged="MainLongListSelector_SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17">
<TextBlock Text="{Binding UnReadCount}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding description}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
这是我对视图模型的修改(注意异步和等待使用):
public void LoadData()
{
FetchTileViewItems();
}
private async void FetchTileViewItems()
{
var ret = await I2ADataServiceHelper.GetTileViewItemsAsync();
this.Items = new ObservableCollection<TileViewItem>(ret);
this.IsDataLoaded = true;
}
我正在调用页面上NavigatedTo事件中的LoadData()方法,就像之前一样:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
pr1.IsVisible = false;
}
}
命中运行,没有任何显示......我错过了什么?任何指针都非常感谢。
好的,快速回答是你可能在你的INotifyPropertyChanged
和/或Items
setter上缺少IsDataLoaded
通知。
更长的答案需要一点点。 :)
首先,你应该避免使用async void
。我在Best Practices in Asynchronous Programming文章中详细描述了原因。在这种情况下,请考虑您的错误处理。很高兴你的快乐案例是“电话成功回复”,但是悲伤的情况会破坏你的程序。
所以,让我们尽可能重写async Task
的所有内容,并在我们处理时重写follow the *Async
convention:
public async Task LoadDataAsync()
{
await FetchTileViewItemsAsync();
}
private async Task FetchTileViewItemsAsync()
{
var ret = await I2ADataServiceHelper.GetTileViewItemsAsync();
this.Items = new ObservableCollection<TileViewItem>(ret);
this.IsDataLoaded = true;
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
await App.ViewModel.LoadDataAsync();
}
}
这是编写async
代码的更自然的方式。
接下来,让我们解决这个错误情况。你可以在try
做一个catch
/ OnNavigatedTo
:
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
try
{
if (!App.ViewModel.IsDataLoaded)
{
await App.ViewModel.LoadDataAsync();
}
}
catch (Exception ex)
{
...
}
}
但我实际上更倾向于以ViewModel为中心,数据绑定友好的系统来进行错误处理。这样,“断开连接”对于您的应用来说是一个非常自然的状态;即使它只是显示错误信息,您的应用程序最终也会被设计用于偶尔连接的系统(即电话)。此外,生成的代码更易于测试。
我在几篇博文中描述了这种方法:我在asynchronous initialization pattern构造函数的帖子中介绍了async
,在data-binding in particular属性的帖子中介绍了async
。我写了一个名为TaskCompletionNotifier
的辅助类,它允许你使用Task
进行数据绑定。
将这些设计放在适当的位置后,您的ViewModel代码看起来更像是这样的:
public sealed class MyViewModel : INotifyPropertyChanged
{
public ObservableCollection<TileViewItem> Items
{
get { return _items; }
private set { _items = value; RaisePropertyChanged(); }
}
public ITaskCompletionNotifier Initialization { get; private set; }
public MyViewModel()
{
Initialization = TaskCompletionNotifierFactory.Create(InitializeAsync());
}
private async Task InitializeAsync()
{
var ret = await I2ADataServiceHelper.GetTileViewItemsAsync();
this.Items = new ObservableCollection<TileViewItem>(ret);
}
}
(这假设您要开始在构造函数中加载数据。)
然后你可以直接绑定到Items
,你也可以绑定到Initialization.IsSuccessfullyCompleted
为快乐的情况,Initialization.IsFaulted
和Initialization.ErrorMessage
为悲伤的情况,等等。
以上是关于异步加载ViewModel中的数据(使用async和await)不能使用数据绑定的主要内容,如果未能解决你的问题,请参考以下文章
在 viewmodel 的构造函数中调用异步方法加载数据有警告