Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

Windows Store Apps : gérer la navigation

[new:15/11/2012]Nous avons vu dans les précédents billets de nombreuses choses spécifiques à WinRT, les templates de projet, les protocoles d’activation personnalisés, les Charmes, etc. Un autre aspect essentiels des Apps Windows Store est la navigation. Voyons comment cela fonctionne…

La navigation

C’est un aspect essentiel de la programmation sous WinRT pour deux raisons majeures : d’une part les mécanisme de navigation sont intégrés au framework, si on peut être inventif et s’écarter de la norme il faut savoir que celle-ci existe et est conçue pour assurer la cohérence de l’expérience utilisateur; d’autre part, la navigation est un point crucial d’une application qu’on sous-estime toujours. Une mauvaise expérience de navigation peut ruiner un bon logiciel et une expérience fluide, simple, peut faire d’un logiciel banal un best-seller…

Dans le principe tout est simple puisque géré par le framework. Mais si vous venez du monde Silverlight ou Windows Phone vous risquez d’être un peu perturbé par la façon de faire sous WinRT. Sous Windows Phone par exemple la navigation se fait en utilisant NavigationService.Navigate() auquel on passe une URI. Sous WinRT les choses se ressemblent mais il y a des nuances…

Dans une application Windows Store chaque page possède une “Frame”, un objet particulier qui implémente les méthodes et propriétés suivantes pour simplifier les opérations de navigation :

GoBack() Navigation arrière vers la page la plus récente page de l’historique
GoForward() Navigation avant vers la prochaine page de l’historique
Navigate(type,args) Navigation vers la page spécifiée
BackStackDepth Nombre d’entrées dans l’historique de navigation
CanGoBack Indique si la navigation arrière est possible
CanGoForward Indique si la navigation avant est possible

 

Les deux premières méthodes impliquent que l’historique de navigation est géré par l’objet Frame bien entendu.

Tout cela semble finalement très familier… Mais avez-vous remarqué les paramètres de la méthode Navigate() ?

Il s’agit d’un type et d’un argument et non plus d’une URI ! On ne passe donc plus une adresse absolue ou relative pour naviguer mais un type. Quel type ? Celui de la page à atteindre.

Frame.Navigate(typeof(SecondaryPage)); // navigation simple
Frame.Navigate(typeof(SecondaryPage), obj); // navigation avec passage de paramètre

 

Les arguments (le paramètre de type Object) sont très utiles pour passer un contexte ou des informations de page en page et ainsi de permettre à l’application de “garder le fil” malgré la grande liberté de navigation offerte à l’utilisateur. C’est un aspect que j’aurai certainement l’occasion de développer un peu plus dans un prochain billet.

Un exemple

Le projet

Prenons une application suivant le modèle “Blank”.

La page principale

Une fois le projet créé modifions le code de MainPage.xaml pour ajouter un bouton et un TextBlock, ce que le code Xaml suivant montre facilement lorsqu’on est habitué à ce langage :

<Page
    x:Class="NavigationDemo.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="Main Page" Style="{StaticResource HeaderTextStyle}"
                   Margin="100,50"/>
        <Button Style="{StaticResource BackButtonStyle}" Margin="403,0,0,668"
                RenderTransformOrigin="0.5, 0.5" Tapped="OnNextButtonTapped">
            <Button.RenderTransform>
                <RotateTransform Angle="180"/>
            </Button.RenderTransform>
        </Button>
    </Grid>
</Page>

 

Ce qui va donner un affichage de ce type :

image

La page secondaire

Maintenant, créons une seconde page que nous allons appeler SecondaryPage.xaml. Ce fichier sera laissé là où VS le propose, dans la racine du projet (au même niveau que MainPage). Cette page aura elle aussi un bouton (pour revenir en arrière) et un TextBlock pour la différencier de la page principale :

<Page
    x:Class="NavigationDemo.SecondaryPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="Secondary Page" Style="{StaticResource HeaderTextStyle}" 
                   Margin="100,50"/>
        <Button Style="{StaticResource BackButtonStyle}" Margin="29,0,0,674" 
                Tapped="OnBackButtonTapped"/>
    </Grid>
</Page>  

Ce qui donne cet affichage là :

image

Nous en avons terminé avec la conception visuelle de cette application extraordinaire !

Le code de navigation

Pour cet exemple je n’ajouterai pas les difficultés propres à MVVM. Nous utiliserons le code-behind pour traiter la navigation mais cela n’est pas à faire en production. Les boutons devraient être liés à des ICommand implémentées par les ViewModels des deux pages, commandes qui déclencheraient la navigation par l’accès à l’objet Frame (pas une bonne idée…) ou mieux par l’envoi d’un message de navigation que les vues transformeraient en ordre de navigation… Certains toolkits MVVM propose des approches rationnelles à ce problème.

Mais je fais abstraction ici de ces subtilités.

Dans la page principale codons le clic sur le bouton symbolisant la page suivante :

private void OnNextButtonTapped(object sender, TappedRoutedEventArgs e)
{
    Frame.Navigate(typeof (SecondaryPage));
}

 

Dans la page secondaire faisons de même pour le bouton de retour en arrière :

private void OnBackButtonTapped(object sender, TappedRoutedEventArgs e)
{
    if (Frame.CanGoBack)
    {
        Frame.GoBack();
    }
}

 

Dans le premier cas nous utilisons une navigation impérative, Navigate() auquel le type de la page secondaire est passé. Cela signifie que quel que soit l’état de l’historique de navigation l’utilisateur accèdera à la page secondaire.

Dans le second cas nous utilisons une autre stratégie : nous commençons par tester si le retour en arrière est possible et seulement dans l’affirmative nous invoquons la méthode GoBack() de l’objet Frame.

Bien entendu, puisque le seul moyen d’accéder à la page deux dans notre application est de la créer depuis la page principale, le test sera toujours vrai. Mais dans une application à la navigation plus complexe ce test pourrait s’avérer essentiel. D’un autre côté, dans un tel cas, je vous conseille plutôt de cacher / montrer le bouton de navigation… Afficher un bouton qui ne fonctionne pas est l’une des pires choses pour l’expérience utilisateur !

Conclusion

La navigation WinRT est finalement assez simple. Elle est basée sur une stratégie “View First” puisque c’est la vue qui navigue vers une autre vue et non pas un ViewModel vers un autre ViewModel. Comme l’exemple n’implémente pas le pattern MVVM cela n’a guère d’importance. Mais tentez de réfléchir à ce que cela signifie avec un framework MVVM qui serait basé sur une approche ViewModel First…

Naviguer, comme tout marin le sait, ça semble facile mais cela réserve des surprises à ceux qui ne savent pas être assez prudents !

Ce billet vous a montré où se trouvait le quai et les bateaux, ne croyez pas qu’il vous a donné le droit de vous prendre pour un capitaine de haute mer, il vous reste encore des choses à savoir… alors…

Stay Tuned !

blog comments powered by Disqus