C# 异步加载ViewModel中的数据(使用async和await)而不使用数据绑定

C# 异步加载ViewModel中的数据(使用async和await)而不使用数据绑定,c#,data-binding,mvvm,windows-phone-8,async-await,C#,Data Binding,Mvvm,Windows Phone 8,Async Await,我用默认模板启动了一个手机应用程序,该模板已经定义了一个视图模型。我修改了MainViewModel的LoadData()方法,以异步调用odata服务。但它不适用于数据绑定。我已验证呼叫已成功返回,但未显示结果 LongListSelector的items源绑定到视图模型中的items属性 <phone:LongListSelector ItemsSource="{Binding Items}" x:Name="MainLongListSelector" Margin="0,0,-12,

我用默认模板启动了一个手机应用程序,该模板已经定义了一个视图模型。我修改了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>

一走了之,什么也没出现……我错过了什么吗?非常感谢任何指针。

好的,快速的回答是您可能缺少
项目
和/或
IsDataLoaded
设置器上的
INotifyPropertyChanged
通知

较长的答案需要一点时间。:)

首先,应该避免
async void
。我在文章中详细描述了原因。在这种情况下,考虑错误处理。令人高兴的是,当“呼叫成功返回”时,您的快乐案例是很好的,但悲伤的案例将撕毁您的程序

因此,让我们尽可能地将所有内容重写为
异步任务
,同时:

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();
    }
}
但实际上,我更倾向于以ViewModel为中心、数据绑定友好的错误处理系统。这样,“断开连接”对于应用程序来说是一种非常自然的状态;即使它所做的只是显示一条错误消息,您的应用程序最终也是为偶尔连接的系统(即电话)设计的。此外,生成的代码更易于测试

我在几篇博客文章中描述了这种方法:我在
async
构造函数的文章中介绍了,在
async
属性的文章中介绍了。我编写了一个名为的helper类,它使您能够对数据绑定使用
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);
    }
}
公共密封类MyViewModel:INotifyPropertyChanged
{
公共可观测收集项目
{
获取{return\u items;}
私有集{u items=value;RaisePropertyChanged();}
}
公共ITaskCompletionNotifier初始化{get;private set;}
公共MyViewModel()
{
Initialization=TaskCompletionNotifierFactory.Create(InitializeAsync());
}
专用异步任务InitializeAsync()
{
var ret=await i2adasservicehelper.GetTileViewItemsAsync();
此项=新的可观察集合(ret);
}
}
(假设您希望开始在构造函数中加载数据。)


然后,您可以直接绑定到
,也可以绑定到
初始化。对于快乐的情况,IsSuccessfullyCompleted
;对于悲伤的情况,IsFaulted
Initialization.ErrorMessage
等等。

什么是
pr1
?这不应该是
pr1.IsVisible=true?我相信App.ViewModel.LoadData()应该是App.ViewModel.LoadDataAsync()(多次)
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();
    }
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
    try
    {
        if (!App.ViewModel.IsDataLoaded)
        {
            await App.ViewModel.LoadDataAsync();
        }
    }
    catch (Exception ex)
    {
        ...
    }
}
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);
    }
}