Ответ 1
ОК, быстрый ответ заключается в том, что вы, вероятно, не пропускаете уведомления INotifyPropertyChanged
в настройках Items
и/или IsDataLoaded
.
Более длинный ответ займет немного.:)
Во-первых, вы должны избегать async void
. Я подробно описываю, почему в статье Best Practices in Asynchronous Programming. В этом случае рассмотрите обработку ошибок. Приятно, что ваш счастливый случай - когда "звонок вернулся успешно", но печальный случай будет разорвать вашу программу вверх.
Итак, перепишите все как async Task
как можно больше, а следуйте за соглашением *Async
, пока мы на нем
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, дружественной к базе данных системе обработки ошибок. Таким образом, "отключенный" является совершенно естественным для вашего приложения; даже если все, что он делает, отображает сообщение об ошибке, ваше приложение заканчивается тем, что оно предназначено для случайно подключенной системы (т.е. телефона). Кроме того, полученный код более подвержен тестированию.
Я описываю этот подход в нескольких своих сообщениях в блоге: я описываю асинхронный шаблон инициализации в своем сообщении в конструкторах async
и привязка данных в частности в моем сообщении в свойствах 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
для печального случая и т.д.