47 votes

WinRT/UWP Frame and Page caching : Comment créer une nouvelle instance de page lors de Navigate() et conserver l'instance de page lors de GoBack()

J'essaie de créer une application UWP (Universal Windows App) avec C#. Mon problème est le suivant Frame contrôle : Si je l'utilise sans NavigationCacheMode = Required Chaque fois que l'utilisateur revient en arrière, la page n'est pas conservée en mémoire et sera recréée. Si je définis NavigationCacheMode à Required o Enabled le retour en arrière fonctionne correctement (pas d'objet nouvelle page) pero si je navigue vers une autre page du même type, l'objet de la page précédente est recyclé et réutilisé (pas de nouvelle instance de page).

Comportement souhaité :

Est-il possible d'obtenir le comportement suivant avec l'original Frame (comme dans Windows Phone) :

  1. Créer une nouvelle instance de page sur Navigate()
  2. Maintenir l'instance de la page sur GoBack()

La seule solution que je connaisse est de créer un propre Frame mais cela conduit à d'autres problèmes (par exemple : absence de SetNavigationState() etc...)

Exemple de scénario :

Exemple de candidature simple de trois pages : TvShowListPage , TvShowDetailsPage , SeasonDetailsPage .

  1. TvShowListPage est la page d'entrée. Après avoir cliqué sur un TvShow naviguer vers TvShowDetailsPage .
  2. Maintenant dans TvShowDetailsPage sélectionner une saison dans la liste et naviguer jusqu'à l'onglet TvShowDetailsPage .
  3. Si vous naviguez en arrière, les pages doivent rester en mémoire pour éviter de les recharger.
  4. Mais si les utilisateurs reviennent à TvShowListPage et sélectionne un autre TvShow el TvShowDetailsPage est recyclé et se trouve peut-être dans un état erroné (par exemple en affichant le pivot du casting au lieu du premier pivot des saisons)

Je recherche le comportement par défaut de Windows Phone 7 : La navigation crée une nouvelle page dans la pile de pages, le retour en arrière supprime la page supérieure de la pile et affiche la page précédente de la pile (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 relatives à la pagination : Page, Frame, SuspensionManager, etc...

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

Références :

6 votes

C'est probablement l'une des choses les plus ennuyeuses de Windows 8. Merci pour votre solution !

17voto

Rico Suter Points 3089

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

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

Update:

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

0 votes

Est-il obligatoire d'utiliser l'élément Hamburger avec HamburgerFrameBuilder ? J'ai mon propre hamburger personnalisé, puis-je utiliser le mien ? Par exemple avec quelque chose d'aussi simple que frame.goback et frame.navigate avec mtPage comme paramètre et args ?

0 votes

Ce n'est pas obligatoire, il suffit de consulter la documentation sur la page GitHub ou de me contacter.

0 votes

D'accord, j'ai compris ! J'avais encore un doute MtFrame.Navigate() ne prend qu'un seul paramètre, la page, et aucun argument ne peut être passé. Comment envoyer un argument à la page de navigation ?

8voto

jkeagle13 Points 51

J'ai eu à peu près le même problème. Je voulais que lorsque j'avançais dans Metro (Windows Store à proprement parler), une nouvelle instance soit créée. Cependant, lorsque je revenais en arrière, il conservait les données que je voulais sauvegarder.

J'ai donc utilisé NavigationCacheMode = NavigationCacheMode.Enabled. J'ai constaté que, quel que soit le sens dans lequel je naviguais, vers l'avant ou vers l'arrière, tout était toujours sauvegardé. J'ai donc avancé de plusieurs pages, puis reculé de quelques unes. Espérant que tout était réinitialisé au fur et à mesure que j'avançais, je découvrais invariablement que ce n'était pas le cas ; les données avaient été conservées.

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

J'ai trouvé une solution. Je suis allé dans le fichier LayoutAwarePage.cs et j'ai simplement apporté une modification mineure. Sous "OnNavigatedTo", j'ai trouvé la ligne :

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

Cependant, le commentaire va à l'encontre de ce que je souhaitais. Je recherchais un chargement d'état dans un schéma unidirectionnel. En cas de mouvement vers l'avant, je voulais un chargement d'état ; en cas de mouvement vers l'arrière, je voulais le comportement indiqué dans le commentaire - pas de chargement d'état.

J'ai donc simplement modifié la ligne.

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

Je l'ai testé et il fonctionne parfaitement. Maintenant, lorsque l'on navigue en arrière, il se souvient de l'état et maintient la page à l'identique. Lorsque l'on navigue vers l'avant, la page se charge à nouveau.

Ce n'est peut-être pas la meilleure pratique, mais je n'appelle pas "OnNavigatedTo" depuis mon code-behind. Je fais tout par l'intermédiaire de "LoadState". Si vous surchargez "OnNavigatedTo" dans le code-behind, il se peut que le comportement soit différent.

Nous vous remercions,

Joseph Irvine

1 votes

Cela préserve-t-il également les positions de défilement, etc. ou seulement l'état que vous avez "sauvegardé manuellement" ?

0 votes

Comment y parvenir pour les applications UWP ?

6voto

Jared Bienz - MSFT Points 2866

Lorsque vous naviguez avant pouvez-vous paramétrer NavigationCacheMode à Handicapés avant d'appeler Cadre.Naviguer ? Ensuite, en OnNavigatedTo() fixer NavigationCacheMode retour à Activé encore une fois.

Ainsi, lorsque vous naviguez vers l'avant, la mise en cache est désactivée. Mais lorsque vous arrivez sur la nouvelle instance de page, OnNavigatedTo le permettrait à nouveau. Lorsque vous voudrez revenir en arrière, vous ne toucherez pas le bouton NavigationCacheMode avant d'appeler Cadre.Retour . Cela devrait vous donner l'instance mise en cache, je pense.

Je pense que cela fonctionnerait, mais je ne l'ai pas testé. Je serais curieux de savoir si c'est le cas. C'est un scénario intéressant. J'aimerais voir l'application en action et mieux comprendre l'utilisation de ce comportement.

3 votes

Cela ne semble pas fonctionner. Quelques résultats : NavigationCacheMode doit être défini dans le constructeur pour être pris en compte. Modifier la propriété ultérieurement (en naviguant ailleurs) n'a aucun effet...

0 votes

Cela fonctionne pour moi, où avez-vous lu que cela ne peut prendre effet que lorsque c'est défini dans le Constructeur ?

1 votes

@RicoSuter Il semble que NavigationCacheMode puisse être modifié ultérieurement dans UWP.

2voto

Magi Points 19

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

La valeur par défaut de la propriété NavigationCacheMode est Disabled. Attribuez la valeur Enabled ou Required à la propriété NavigationCacheMode lorsqu'une nouvelle instance de la page n'est pas indispensable à chaque visite. En utilisant une instance de la page mise en cache, vous pouvez améliorer les performances de votre application et réduire la charge sur votre serveur.

Le fait de donner à NavigationCacheMode la valeur Required signifie que la page est mise en cache quel que soit le nombre de pages mises en cache spécifié dans la propriété CacheSize. Les pages marquées comme requises ne sont pas prises en compte dans le total de CacheSize. Si NavigationCacheMode a la valeur Enabled, la page est mise en cache, mais elle peut être éliminée si le nombre de pages mises en cache dépasse la valeur de la propriété CacheSize.

Attribuez la valeur Désactivé à la propriété NavigationCacheMode si une nouvelle instance doit être créée pour chaque visite. Par exemple, vous ne devez pas mettre en cache une page qui affiche 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. Il est préférable d'inclure dans cette méthode le code qui doit être exécuté pour chaque requête plutôt que de le placer dans le constructeur de la page.

0 votes

Tout est correct, mais ce n'est pas une solution. Vous dites que la seule solution est de nettoyer la page en OnNavigatedTo() (ce n'est pas une bonne solution car j'ai des images en fondu qui s'effacent en premier etc...) ? Je vois dans votre réponse que je peux avoir soit le comportement 1. soit le comportement 2. mais pas les deux ?

0voto

David Rector Points 103

J'ai dû dériver un page2 de ma classe page puis, lorsque je veux naviguer vers une deuxième version de la même page, je détecte si la classe this est page o page2 . Je navigue ensuite vers page2 si j'étais en page et naviguez jusqu'à page si en page2 .

Le seul inconvénient, et il est de taille, est qu'il n'existe aucun moyen de dériver un fichier XAML d'un autre. Ainsi, tout le code C# se trouve dans le fichier page comme prévu, mais il y a deux fichiers XAML presque identiques, un pour chaque version de la page.

Un petit script pourrait probablement être ajouté comme étape de pré-construction 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 à me soucier de la duplication du code C# ou de problèmes de cache de navigation bizarres. Je me retrouve juste avec du code XMAL dupliqué, qui dans mon cas ne change jamais de toute façon. Je me retrouve également avec deux avertissements concernant la non-utilisation de l'élément new sur le code généré automatiquement pour page2.InitializeComponent() y page2.Connect() .

Il est intéressant de noter que la navigation vers page puis à page2 puis à page ne pose pas de problème et la deuxième instance de l'élément page est une seconde instance qui n'a rien à voir avec la première.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X