Mise en cache des frameworks et des pages WinRT / UWP: comment créer une nouvelle instance de page sur Navigate () et conserver l’instance de page sur GoBack ()

J’essaie de créer une application UWP (Universal Windows App) avec C #. Mon problème est le contrôle Frame : si je l’utilise sans NavigationCacheMode = Required , chaque fois que l’utilisateur revient, la page n’est pas conservée en mémoire et sera recréée. Si je mets NavigationCacheMode sur Required ou Enabled , le retour en arrière fonctionne correctement (pas de nouvel object page) mais si je navigue vers une autre page du même type, l’object page précédent est recyclé et réutilisé (pas de nouvelle instance de page).

Comportement désiré:

Y a-t-il un moyen d’avoir le comportement suivant avec le contrôle Frame origine (comme dans Windows Phone):

  1. Créer une nouvelle instance de page sur Navigate()
  2. Conservez l’instance de page sur GoBack()

La seule solution que je connaisse est de créer un propre contrôle Frame mais cela conduit à d’autres problèmes (par exemple: méthode SetNavigationState() manquante, etc …)

Exemple de scénario:

Exemple d’application simple avec trois pages: TvShowListPage , TvShowDetailsPage , SeasonDetailsPage .

  1. TvShowListPage est la page d’entrée. Après avoir cliqué sur un TvShow accédez à TvShowDetailsPage .
  2. Maintenant, dans TvShowDetailsPage sélectionnez une saison dans la liste et accédez à la TvShowDetailsPage .
  3. Si vous naviguez en arrière, les pages doivent restr en mémoire pour éviter de recharger les pages.
  4. Mais si les utilisateurs retournent à TvShowListPage et sélectionnent un autre TvShow le TvShowDetailsPage est recyclé et est peut-être dans un mauvais état (par exemple, affichage du pivot au lieu du premier, saisons pivot)

Je recherche le comportement par défaut de Windows Phone 7: la navigation crée une nouvelle page sur la stack de pages, le retour supprime la première page de la stack et affiche la page précédente de la stack (stockée dans la mémoire).

Solution:

Comme il n’y avait pas de solution à ce problème, j’ai dû réimplémenter toutes les classes pertinentes pour la pagination: Page, Frame, SuspensionManager, etc.

La bibliothèque MyToolkit qui fournit toutes ces classes peut être téléchargée ici: https://github.com/MyToolkit/MyToolkit/wiki/Paging-Overview

Les références:

  • http://www.jayway.com/2012/05/25/clearing-the-windows-8-page-cache/ : pas de bonne solution
  • http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/88e6d1b3-1fa6-4ab4-a816-e77c86ef236f/ : L’implémentation d’une propre classe Frame n’est pas une solution car elle ne fonctionne pas avec SuspensionManager

Comme il n’y avait pas de solution à ce problème, j’ai dû réimplémenter toutes les classes pertinentes pour la pagination: Page, Frame, SuspensionManager, etc.

La solution peut être téléchargée ici: https://github.com/MyToolkit/MyToolkit/wiki/Paging-Overview

Mettre à jour:

La classe de page fournit désormais également la méthode OnNavigatingFromAsync pour afficher, par exemple, une fenêtre contextuelle asynchrone et annuler la navigation si nécessaire …

J’ai eu le même problème. Je le voulais tel que lorsque je progressais dans Metro (Windows Store pour être correct), cela créerait une nouvelle instance. Cependant, en revenant, cela conserverait les données que je voulais sauvegarder.

Donc, j’ai également utilisé NavigationCacheMode = NavigationCacheMode.Enabled. J’ai trouvé que peu importe la façon dont je traversais, vers l’avant ou l’arrière, tout était toujours sauvegardé. Donc, je devais avancer plusieurs pages, puis prendre un peu de recul. En espérant que tout était réinitialisé au fur et à mesure que j’avançais, j’ai toujours constaté que ce n’était pas le cas; il avait conservé les données.

J’ai tout essayé, y compris écrire mon propre code de bouton pour inclure NavigationCacheMode = NavigationCacheMode.Disabled, mais en vain. Comme d’autres l’ont souligné, une fois que vous l’avez activé, le NavigationCacheMode ne sera tout simplement pas désactivé.

J’ai trouvé une solution. Je suis allé au LayoutAwarePage.cs et j’ai simplement fait un changement mineur. Sous le “OnNavigatedTo” j’ai trouvé la ligne:

 // Returning to a cached page through navigation shouldn't sortinggger state loading if (this._pageKey != null) return; 

Cependant, le commentaire était contraire à ce que je voulais. Je cherchais un chargement d’état dans un modèle unidirectionnel. En avançant, je voulais un chargement d’état; en reculant, je voulais le comportement indiqué par le commentaire – pas de chargement d’état.

J’ai donc simplement modifié la ligne.

 // Returning to a cached page through navigation shouldn't sortinggger state loading if (this._pageKey != null && e.NavigationMode == NavigationMode.Back) return; 

Je l’ai testé et cela fonctionne parfaitement. Maintenant, lorsque vous naviguez en arrière, il se souvient de l’état et conserve la même page. En naviguant vers l’avant, il charge frais.

Peut-être pas les meilleures pratiques, mais je n’appelle pas “OnNavigatedTo” de mon code-behind. Je fais tout par le biais du “LoadState”. Si vous remplacez “OnNavigatedTo” dans le code-behind, vous risquez de voir un comportement différent.

Je vous remercie,

Joseph Irvine

Lorsque vous naviguez vers l’avant , pouvez-vous définir NavigationCacheMode sur Désactivé avant d’appeler Frame.Navigate ? Ensuite, dans OnNavigatedTo (), définissez à nouveau NavigationCacheMode sur Activé .

Cela devrait faire en sorte que lorsque vous naviguez vers l’avant, la mise en cache est désactivée. Mais lorsque vous arrivez sur la nouvelle instance de la page, OnNavigatedTo l’active à nouveau. Lorsque vous souhaitez revenir en arrière, vous ne touchez pas NavigationCacheMode avant d’appeler Frame.GoBack . Cela devrait vous donner l’instance en cache, je pense.

Je crois que cela fonctionnerait mais je ne l’ai pas testé. Je serais curieux de savoir si c’est le cas. Scénario intéressant là-bas. J’aimerais voir l’application en action et mieux comprendre l’utilisation de ce comportement.

Vous utilisez la propriété NavigationCacheMode pour spécifier si une nouvelle instance de la page est créée pour chaque visite de la page ou si une instance précédemment construite de la page enregistrée dans le cache est utilisée pour chaque visite.

La valeur par défaut de la propriété NavigationCacheMode est Disabled. Définissez la propriété NavigationCacheMode sur Activé ou Obligatoire lorsqu’une nouvelle instance de la page n’est pas essentielle pour chaque visite. En utilisant une instance mise en cache de la page, vous pouvez améliorer les performances de votre application et réduire la charge sur votre serveur.

La définition de NavigationCacheMode sur Obligatoire signifie que la page est mise en cache, quel que soit le nombre de pages mises en cache spécifiées dans la propriété CacheSize. Les pages marquées comme requirejses ne sont pas comptabilisées dans le total de CacheSize. Si vous définissez NavigationCacheMode sur Activé, la page est mise en cache, mais vous pouvez l’éliminer si le nombre de pages mises en cache dépasse la valeur de CacheSize.

Définissez la propriété NavigationCacheMode sur Désactivée si une nouvelle instance doit être créée pour chaque visite. Par exemple, vous ne devez pas mettre en cache une page affichant des informations propres à chaque client.

La méthode OnNavigatedTo est appelée pour chaque requête, même lorsque la page est extraite du cache. Vous devez inclure dans ce code de méthode qui doit être exécuté pour chaque demande plutôt que de placer ce code dans le constructeur Page.

J’ai dû dériver une classe page2 de ma classe de page , puis, lorsque je souhaite naviguer vers une seconde version de la même page, je détecte si this object est une page ou une page2 . Je navigue alors à la page2 si j’étais dans la page et navigue à la page si dans la page2 .

Le seul inconvénient, énorme, est qu’il n’ya aucun moyen de dériver un fichier XAML d’un autre. Ainsi, tout le code C # se trouve dans le code de la classe de page -behind comme prévu, mais il existe deux fichiers XAML presque identiques, un pour chaque version de la page.

Un petit script pourrait probablement être ajouté comme étape préalable à la génération pour générer la deuxième classe de page à partir de la première, en copiant les données XAML et en ajustant les noms de classe.

C’est moche mais ça fonctionne presque parfaitement et je n’ai jamais à m’inquiéter de la duplication de code C # ou des problèmes de cache de navigation bizarres. J’ai fini par avoir un code XMAL en double, qui dans mon cas ne change jamais vraiment. Je me retrouve également avec deux avertissements sur le fait de ne pas utiliser le new mot-clé sur le code généré automatiquement pour page2.InitializeComponent() et page2.Connect() .

Fait intéressant, la navigation vers la page puis la page2 puis la page ne pose pas de problème et la deuxième instance de la classe de page est une seconde instance réelle sans rapport avec la première.

Notez que cette solution est probablement déconseillée par MS.

J’ai réalisé ceci par:

  • Définir NavigationCacheMode sur Required / Enabled pour les pages requirejses.
  • En cliquant sur le bouton / lien de la page2:

    Parcourez le BackStack du cadre et vérifiez si la Page2 est dans BackStack. Si Page2 est trouvé, appelez Frame.GoBack () le nombre de fois requirejs. Si non trouvé, naviguez simplement vers la nouvelle page. Cela fonctionnera pour n’importe quel nombre de pages.

Exemple de code:

 public void Page2Clicked(object sender, RoutedEventArgs e) { int isPresent = 0; int frameCount = 0; //traverse BackStack in reverse order as the last element is latest page for(int index= Frame.BackStack.Count-1; index>=0;index--) { frameCount += 1; //lets say the first page name is page1 which is cached if ("Page2".Equals(Frame.BackStack[index].SourcePageType.Name)) { isPresent = 1; //Go back required no of times while (frameCount >0) { Frame.GoBack(); frameCount -= 1; } break; } } if (isPresent == 0) { Frame.Content = null; Frame.Navigate(typeof(Page2)); } } 

Cela sera utile si les boutons avant / arrière ne seront pas utilisés. comme cette solution affectera la navigation avant / arrière. Si vous souhaitez également utiliser la navigation avant / arrière, vous devez gérer des cas supplémentaires.