Chargement des données dans ViewModel de manière asynchrone (avec async et await) ne fonctionnant pas avec la liaison de données
J'ai commencé une application du téléphone avec le modèle par défaut qui a une vue modèle déjà défini. J'ai modifié le MainViewModel de LoadData() la méthode à appeler un service odata de manière asynchrone. Mais il ne fonctionne pas avec la liaison de données. J'ai vérifié que l'appel est retourné avec succès, mais aucun résultat n'est affiché.
Le LongListSelector la source des éléments est lié à la propriété des Éléments dans le modèle de vue.
<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>
Voici ma modification du modèle de vue (note de l'async et await utilisation):
public void LoadData()
{
FetchTileViewItems();
}
private async void FetchTileViewItems()
{
var ret = await I2ADataServiceHelper.GetTileViewItemsAsync();
this.Items = new ObservableCollection<TileViewItem>(ret);
this.IsDataLoaded = true;
}
Et je vais appeler la méthode LoadData() dans le NavigatedTo de l'événement sur la page comme avant:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
pr1.IsVisible = false;
}
}
Frappé exécuter et rien ne s'affiche...j'ai loupé quelque chose? Tous les pointeurs sont grandement appréciés.
source d'informationauteur user2137225
Vous devez vous connecter pour publier un commentaire.
OK, la réponse rapide est que vous êtes probablement manquant
INotifyPropertyChanged
notifications sur votreItems
et/ouIsDataLoaded
setters.La plus longue réponse va prendre un peu. 🙂
Tout d'abord, vous devriez éviter de
async void
. Je décris pourquoi en détail dans mon Les meilleures Pratiques dans la Programmation Asynchrone article. Dans ce cas, tenir compte de votre erreur de manipulation. C'est bien que vos heureux de cas, c'est quand "l'appel retourné avec succès", mais la triste affaire va déchirer votre programme.Donc, nous allons réécrire tout ce que
async Task
autant que possible, et suivez le*Asynchrone
de la convention de pendant que nous y sommes:C'est le moyen plus naturel d'écrire
async
code.Ensuite, nous allons corriger cette erreur de la situation. Vous peut faire un
try
/catch
dansOnNavigatedTo
:Mais je penche plus vers un ViewModel-centric, la liaison de données un système de gestion d'erreur. De cette façon, "déconnecté" est parfaitement naturelle, de l'état de votre candidature, même si il ne fait qu'afficher un message d'erreur, votre application se conçu pour un de temps en temps-système connecté (c'est à dire, un téléphone). Aussi, le code résultant est plus testable.
Je décrire cette approche dans un couple des articles de mon blog: je m'occupe de la initialisation asynchrone modèle dans mon post sur
async
les constructeurs, et le de liaison de données en particulier dans mon post surasync
propriétés. J'ai écrit une classe d'assistance appeléTaskCompletionNotifier
qui vous permet d'utiliserTask
avec la liaison de données.De mettre ces dessins en place, votre ViewModel code finit par regarder plus comme ceci:
(C'est en supposant que vous souhaitez démarrer le chargement des données dans le constructeur.)
Vous pouvez ensuite lier à
Items
directement, et vous pouvez également les lier àInitialization.IsSuccessfullyCompleted
pour le plaisir du cas,Initialization.IsFaulted
etInitialization.ErrorMessage
pour la triste affaire, etc.