gpt4 book ai didi

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

转载 作者:可可西里 更新时间:2023-11-01 08:01:54 26 4
gpt4 key购买 nike

我使用默认模板启动了一个手机应用程序,该模板已经定义了一个 View 模型。我修改了 MainViewModel 的 LoadData() 方法以异步调用 odata 服务。但它不适用于数据绑定(bind)。我已验证调用成功返回但未显示任何结果。

LongListSelector 的项源绑定(bind)到 View 模型中的 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>

这是我对 View 模型的修改(注意 async 和 await 的用法):

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;
}
}

点击运行,但什么也没有出现……我是不是遗漏了什么?非常感谢任何指点。

最佳答案

好的,快速回答是您可能在 Items 和/或 IsDataLoaded setter 上缺少 INotifyPropertyChanged 通知。

较长的答案会花费一些时间。 :)

首先,你应该避免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();
}
}

这是编写异步代码的更自然的方式。

接下来,让我们修复该错误情况。您可以OnNavigatedTo 中执行try/catch:

protected override async void OnNavigatedTo(NavigationEventArgs e)
{
try
{
if (!App.ViewModel.IsDataLoaded)
{
await App.ViewModel.LoadDataAsync();
}
}
catch (Exception ex)
{
...
}
}

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

我在我的几篇博文中描述了这种方法:我介绍了 asynchronous initialization pattern在我关于 async 构造函数和 data-binding in particular 的帖子中在我关于 async 属性的帖子中。我写了一个名为 TaskCompletionNotifier 的辅助类这使您能够将 Task 与数据绑定(bind)一起使用。

将这些设计就位后,您的 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);
}
}

(假设您要开始在构造函数中加载数据。)

然后您可以直接绑定(bind)到 Items,您还可以绑定(bind)到 Initialization.IsSuccessfullyCompletedInitialization.IsFaultedInitialization.ErrorMessage 用于悲伤的情况等

关于c# - 异步加载 ViewModel 中的数据(使用 async 和 await)不使用数据绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15305189/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com