• Facile

Ce cours est visible gratuitement en ligne.

Vous pouvez être accompagné et mentoré par un professeur particulier par visioconférence sur ce cours.

J'ai tout compris !

Mis à jour le 29/04/2014

Une application à plusieurs pages, la navigation

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Pour l’instant, notre application est simple, avec une unique page. Il est bien rare qu’une application n’ait qu’une seule page… C’est comme pour un site internet, imaginons que nous réalisions une application mobile pour commander des produits, nous aurons une page contenant la liste des produits par rayon, une page pour afficher la description d’un produit, une page pour commander…

Nous allons donc voir qu’il est possible de naviguer facilement entre les pages de notre application grâce au service de navigation de Windows Phone.

Naviguer entre les pages

Avant de pouvoir naviguer entre des multiples pages, il faut effectivement avoir plusieurs pages ! Nous allons illustrer cette navigation en prenant pour exemple le site OpenClassrooms… enfin, en beaucoup beaucoup moins bien.

Première fonctionnalité, il faut pouvoir se loguer afin d’atteindre la page des cours. Nous allons donc avoir deux pages, une qui permet de se loguer, et une qui permet d’afficher la liste des cours.

Commençons par la page pour se loguer et vu qu’elle existe, utilisons la page MainPage.xaml :

<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
        <TextBlock x:Name="ApplicationTitle" Text="Démonstration de la navigation" Style="{StaticResource PhoneTextNormalStyle}"/>
        <TextBlock x:Name="PageTitle" Text="Page de Login" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>

    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <StackPanel>
            <TextBlock Text="Saisir votre login" HorizontalAlignment="Center" />
            <TextBox x:Name="Login"/>
            <Button Content="Se connecter" Tap="Button_Tap" />
        </StackPanel>
    </Grid>
</Grid>

Pour que cela soit plus simple, nous utilisons uniquement un login pour nous connecter.
Si nous affichons la page dans l’émulateur, nous avons la figure suivante.

Affichage de la page de login
Affichage de la page de login

Nous allons maintenant créer une deuxième page permettant d’afficher la liste des cours. Créons donc une autre page que nous nommons ListeCours.xaml. Pour cela, nous faisons un clic droit sur le projet et choisissons d’ajouter un nouvel élément. Il suffit de choisir le modèle de fichier Page en mode portrait Windows Phone et de lui donner le bon nom (voir la figure suivante).

Ajout d'une nouvelle page XAML dans le projet
Ajout d'une nouvelle page XAML dans le projet

Dans cette page, nous allons afficher simplement bonjour et que la page est en construction. Pour cela, un XAML très minimaliste :

<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
        <TextBlock x:Name="ApplicationTitle" Text="Démonstration de la navigation" Style="{StaticResource PhoneTextNormalStyle}"/>
        <TextBlock x:Name="PageTitle" Text="Page des cours" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>

    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <Grid.RowDefinitions>
            <RowDefinition Height="200" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBlock x:Name="Bonjour" Text="Bonjour" HorizontalAlignment="Center" />
        <TextBlock Grid.Row="1" Text="Cette page est en construction ..." />
    </Grid>
</Grid>

Retournons dans la méthode de clic sur le bouton de la première page. Nous allons utiliser le code suivant :

private void Button_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
    if (!string.IsNullOrEmpty(Login.Text))
        NavigationService.Navigate(new Uri("/ListeCours.xaml", UriKind.Relative));
 }

Nous utilisons le service de navigation et notamment sa méthode Navigate pour accéder à la page ListeCours.xaml, si le login n’est pas vide.
Grâce à cette méthode, nous pouvons aller facilement sur la page en construction. Remarquons que si nous appuyons sur le bouton en bas à gauche du téléphone permettant de faire un retour arrière, alors nous revenons à la page précédente. Si nous cliquons à nouveau sur le retour arrière, alors nous quittons l’application car il n’y a pas de page précédente.
Bon, c’est très bien tout ça, mais si on pouvait afficher un bonjour personnalisé, ça serait pas plus mal, avec par exemple le login saisi juste avant …
Il y a plusieurs solutions pour faire cela. Une des solutions consiste à utiliser la query string. Elle permet de passer des informations complémentaires à une page, un peu comme pour les pages web. Pour cela, on utilise la syntaxe suivante :

Page.xaml?parametre1=valeur1&parametre2=valeur2

Modifions donc notre méthode pour avoir :

private void Button_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
    if (!string.IsNullOrEmpty(Login.Text))
        NavigationService.Navigate(new Uri("/ListeCours.xaml?login=" + Login.Text, UriKind.Relative));
}

Désormais, la page ListeCours sera appelée avec le paramètre login qui vaudra la valeur saisie dans la TextBox.
Pour récupérer cette valeur, rendez-vous dans le code behind de la seconde page où nous allons substituer la méthode appelée lorsqu’on navigue sur la page, il s’agit de la méthode OnNavigatedTo, cette méthode faisant partie de la classe PhoneApplicationPage. Nous aurons donc le code behind suivant :

public partial class ListeCours : PhoneApplicationPage
{
    public ListeCours()
    {
        InitializeComponent();
    }

    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
    }
}

C’est à cet endroit que nous allons extraire la valeur du paramètre avec le code suivant :

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    string login;
    if (NavigationContext.QueryString.TryGetValue("login", out login))
    {
        Bonjour.Text += " " + login;
    }
    base.OnNavigatedTo(e);
}

On utilise la méthode TryGetValue en lui passant le nom du paramètre. Cette méthode fait partie de l’objet QueryString du contexte de navigation accessible via NavigationContext.
Ce qui nous donne la figure suivante.

Affichage de la seconde page
Affichage de la seconde page

Une autre solution pour passer des informations de page en page serait d’utiliser le dictionnaire d’état de l’application afin de communiquer un contexte à la page vers laquelle nous allons naviguer. Il s’agit d’un objet accessible de partout où nous pouvons stocker des informations et les lier à une clé. Cela donne :

private void Button_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
    if (!string.IsNullOrEmpty(Login.Text))
    {
        PhoneApplicationService.Current.State["login"] = Login.Text;
        NavigationService.Navigate(new Uri("/ListeCours.xaml", UriKind.Relative));
    }
}

Et pour récupérer la valeur dans la deuxième page, nous ferons :

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    string login = (string)PhoneApplicationService.Current.State["login"];
    Bonjour.Text += " " + login;
    base.OnNavigatedTo(e);
}

L’utilisation du dictionnaire d’état est très pratique pour faire transiter un objet complexe qui sera difficilement représentable dans des paramètres de query string.

Voilà pour ce premier aperçu du service de navigation. Remarquez que le XAML possède également un contrôle qui permet de naviguer entre les pages, comme le NavigationService. Il s’agit du contrôle HyperlinkButton. Il suffira de renseigner sa propriété NavigateUri. Complétons notre page ListeCours pour rajouter en bas un HyperLinkButton qui renverra vers une page Contact.xaml :

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <Grid.RowDefinitions>
        <RowDefinition Height="200" />
        <RowDefinition Height="*" />
        <RowDefinition Height="auto" />
    </Grid.RowDefinitions>
    <TextBlock x:Name="Bonjour" Text="Bonjour" HorizontalAlignment="Center" />
    <TextBlock Grid.Row="1" Text="Cette page est en construction ..." />
    <HyperlinkButton Grid.Row="2" Content="Nous contacter" NavigateUri="/Contact.xaml" />
</Grid>

Puis créons une page Contact.xaml :

<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
        <TextBlock x:Name="ApplicationTitle" Text="Démonstration de la navigation" Style="{StaticResource PhoneTextNormalStyle}"/>
        <TextBlock x:Name="PageTitle" Text="Nous contacter" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>

    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <StackPanel>
            <TextBlock Text="Il n'y a rien pour l'instant ..." />
            <Button Content="Revenir à la page précédente" Tap="Button_Tap" />
        </StackPanel>
    </Grid>
</Grid>

Ainsi, lorsque nous démarrerons l’application et après nous être logués, nous pouvons voir le bouton « nous contacter » en bas de la page (voir la figure suivante).

Utilisation du contrôle HyperLinkButton pour la navigation
Utilisation du contrôle HyperLinkButton pour la navigation

Un clic dessus nous amène à la page de contact (voir la figure suivante).

Affichage de la page de contact
Affichage de la page de contact

Et voilà, la navigation est rendue très simple avec ce contrôle, nous naviguons entre les pages de notre application en n'ayant presque rien fait, à part ajouter un contrôle HyperlinkButton. Il sait gérer facilement une navigation avec des liens entre des pages. C’est la forme de navigation la plus simple.
Nous avons pu voir ainsi deux façons différentes de naviguer entre les pages, via le contrôle HyperlinkButton et via le NavigationService. Puis nous avons vu deux façons différentes de passer des informations entre les pages, via la query string et via le dictionnaire d'état de l'application.

Le fichier WMAppManifest.xml dans l'explorateur de solutions
Le fichier WMAppManifest.xml dans l'explorateur de solutions

Double-cliquez dessus et une nouvelle page s’ouvre permettant de saisir une autre page de démarrage (voir la figure suivante).

Le concepteur permettant de modifier la page XAML de démarrage de l'application
Le concepteur permettant de modifier la page XAML de démarrage de l'application

Gérer le bouton de retour arrière

Et pour revenir en arrière ? Nous l’avons vu, il faut cliquer sur le bouton de retour arrière qui fait nécessairement partie d’un téléphone Windows Phone. Mais il est également possible de déclencher ce retour arrière grâce au service de navigation.
C’est à cela que va servir le bouton que j’ai rajouté dans la page Contact.xaml. Observons l’événement associé au clic :

private void Button_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
    NavigationService.GoBack();
}

Très simple, il suffit de déclencher le retour arrière avec la méthode GoBack() du service de navigation. Notez qu’il peut être utile dans certaines situations de tester si un retour arrière est effectivement possible. Cela se fait avec la propriété CanGoBack :

private void Button_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
    if (NavigationService.CanGoBack)
        NavigationService.GoBack();
}

Il est également possible de savoir si l’utilisateur a appuyé sur le fameux bouton de retour arrière. À ce moment-là, on passera dans la méthode OnBackKeyPress. Pour pouvoir faire quelque chose lors de ce clic, on pourra substituer cette méthode dans notre classe :

protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
    base.OnBackKeyPress(e);
}

Il est possible ici de faire ce que l’on veut, comme afficher un message de confirmation demandant si on veut réellement quitter cette page, ou sauvegarder des infos, etc. On pourra annuler l’action de retour arrière en modifiant la propriété Cancel de l’objet CancelEventArgs à true, si par exemple l’utilisateur ne souhaite finalement pas revenir en arrière. On peut également choisir de rediriger vers une autre page si c’est pertinent :

protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
    if (MessageBox.Show("Vous n'avez pas sauvegardé votre travail, voulez-vous vraiment quitter cette page ?", "Attention", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel)
    {
        e.Cancel = true;
    }
    base.OnBackKeyPress(e);
}

Qui donne la figure suivante.

Affichage d'une confirmation avant de quitter la page
Affichage d'une confirmation avant de quitter la page

Et voilà pour les bases de la navigation. D’une manière générale, il est de bon ton de garder une mécanique de navigation fluide et cohérente. Il faut privilégier la navigation intuitive pour que l’utilisateur ne soit pas perdu dans un labyrinthe d’écran…

Ajouter une image d’accueil (splash screen)

Il est maintenant d’un usage commun de faire en sorte qu’au démarrage de son application il y ait une image pour faire patienter l’utilisateur pendant que tout se charge. On appelle cela en général de son nom anglais : Splash screen, que l’on peut traduire en image d’accueil. On y trouve souvent un petit logo de l’application ou de l’entreprise qui l’a réalisé, pourquoi pas le numéro de version,… bref, des choses pour faire patienter l’utilisateur et lui dire que l’application va bientôt démarrer.
Avec Windows Phone, il est très facile de réaliser ce genre d’image d’accueil, il suffit de rajouter (si elle n’est pas déjà présente) une image s’appelant SplashScreenImage.jpg à la racine du projet. Elle doit avoir son action de génération à Contenu (voir la figure suivante).

L'image d'accueil dans l'explorateur de solutions
L'image d'accueil dans l'explorateur de solutions

Pour les applications Windows Phone 8, elle doit avoir la taille 768x1280 pixels alors que pour les applications Windows Phone 7.X elle devra être de 480x800 (voir la figure suivante).

Affichage de l'écran d'accueil dans l'émulateur
Affichage de l'écran d'accueil dans l'émulateur

Vous noterez au passage mon talent de dessinateur et ma grande force à exploiter toute la puissance des formes de Paint.

Le tombstonning

Avec Windows Phone 7 est apparu un changement radical dans la façon dont sont traitées les applications. Fini le multitâche comme on le connaissait auparavant avec un Windows classique, il n’y a désormais qu’une application qui s’exécute à la fois. Cela veut dire que si je suis dans une application, que j’appuie sur le bouton de menu et que j’ouvre une nouvelle application, je n’ai pas deux applications qui tournent en parallèle, mais une seule. Ma première application ne s’est pas fermée non plus, elle est passée dans un mode « suspendu », voire « désactivé » en fonction du contexte. Ainsi, si je quitte ma seconde application en appuyant par exemple sur le bouton de retour arrière, alors ma première application qui était en mode suspendu ou désactivé, se réactive et repasse dans le mode en cours d’exécution.

Ce fonctionnement est conservé pour Windows Phone 8 et a été également étendu pour les applications Windows 8.
Une application peut donc soit être :

  • En cours d’exécution

  • Suspendue

  • Désactivée

  • Non démarrée

Lorsque l’application passe en mode suspendu, par exemple lorsque j’appuie sur le bouton de menu, elle reste intacte en mémoire. Cela veut dire qu’un retour arrière pour retourner à l’application sera très rapide et vous retrouverez votre application comme elle se trouvait précédemment.

Enfin, ça, c’est la théorie. En vrai, c’est un peu plus compliqué que ça. C’est le système d’exploitation qui s’occupe de gérer les états des applications en fonction notamment de la mémoire disponible. En effet, Windows Phone peut choisir de désactiver une application suspendue si l’application en cours d’exécution a besoin de mémoire. De la même façon, l’application peut avoir simplement été suspendue et se réactiver de manière optimale si le système d’exploitation n’a pas eu besoin de mémoire.
Une application désactivée a été terminée par le système d’exploitation, bien souvent parce qu’il avait besoin de mémoire. Quelques informations restent cependant disponibles et si l’utilisateur revient sur l’application, celle-ci est alors redémarrée depuis zéro mais ces informations sont accessibles afin de permettre de restaurer l’état de l’application.

Tout ceci implique que l’on ne peut jamais garantir que l’utilisateur va fermer correctement une application ou que celle-ci va se terminer proprement, c’est même d’ailleurs rarement le cas. Il peut y avoir plein de scénarios possibles. Par exemple votre utilisateur est en train de saisir des informations dans votre application, il change d’application pour aller lire un mail, voir la météo, puis plus tard il revient à votre application ; entre temps il a reçu un coup de téléphone, rechargé son téléphone ... Qu’est devenue notre application ? Comment apporter à l’utilisateur tout le confort d’utilisation possible et lui garantir qu’il n’a pas perdu toute sa saisie ?
Heureusement, lorsque l’application change d’état, nous pouvons être prévenus grâce à des événements. Ce sont des événements applicatifs que l’on retrouve dans le fichier d’application que nous avons déjà vu : App.xaml. Par contre, ici nous allons nous intéresser à son code behind : App.xaml.cs et notamment aux événements déjà générés pour nous. Ouvrez-le et vous pouvez voir :

// Code à exécuter lorsque l'application démarre (par exemple, à partir de Démarrer)
// Ce code ne s'exécute pas lorsque l'application est réactivée
private void Application_Launching(object sender, LaunchingEventArgs e)
{
}

// Code à exécuter lorsque l'application est activée (affichée au premier plan)
// Ce code ne s'exécute pas lorsque l'application est démarrée pour la première fois
private void Application_Activated(object sender, ActivatedEventArgs e)
{
}

// Code à exécuter lorsque l'application est désactivée (envoyée à l'arrière-plan)
// Ce code ne s'exécute pas lors de la fermeture de l'application
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
}

// Code à exécuter lors de la fermeture de l'application (par exemple, lorsque l'utilisateur clique sur Précédent)
// Ce code ne s'exécute pas lorsque l'application est désactivée
private void Application_Closing(object sender, ClosingEventArgs e)
{
}

Les commentaires générés parlent d’eux-mêmes. Ces méthodes sont donc l’endroit idéal pour faire des sauvegardes de contexte.
Voici à la figure suivante un schéma récapitulatif des différents états.

Les différents états d'une application Windows Phone
Les différents états d'une application Windows Phone

-

Action

Événement applicatif

1

Démarrage

Launching

2

Désactivation

Deactivated

3

Reprise rapide

Activated

4

Reprise lente

Activated

5

Fermeture

Closing

6

Fermeture forcée par l’OS

-

Imaginons que je sois en train de saisir un long texte dans mon application, que mon téléphone sonne et que je doive partir d’urgence. L’application va commencer par passer en mode suspendu. Si je retourne dans mon application rapidement en appuyant sur le retour arrière, alors je vais retrouver mon texte intact. Par contre, si celle-ci est désactivée par le système d’exploitation, alors je peux dire adieu à ma saisie. Et là, je risque de maudire cette application et ne plus jamais l’utiliser. Et c’est encore pire si c’est moi qui relance depuis zéro l’application depuis le menu, je ne pourrais même pas maudire le système d’exploitation.
Une solution est de sauvegarder ce texte au fur et à mesure de sa saisie. Comme ça, si jamais l’application est désactivée, je pourrai alors profiter des événements applicatifs pour enregistrer ce texte dans la mémoire du téléphone, afin de le repositionner si jamais l’utilisateur ré-ouvre l’application. Mais avant cela, essayons de bien comprendre le processus d’activation/désactivation et modifions MainPage.xaml pour avoir ceci :

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <StackPanel>
        <TextBox />
    </StackPanel>
</Grid>

Et dans le code-behind :

public partial class MainPage : PhoneApplicationPage
{
    private bool _estNouvelleInstance = false;
    private string laPage; // info à conserver

    public MainPage()
    {
        InitializeComponent();
        _estNouvelleInstance = true;
    }

    protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
    {
        if (e.NavigationMode != System.Windows.Navigation.NavigationMode.Back)
        {
            // l'appli est désactivée, la page est quittée
            State["MainPage"] = laPage;
        }
        else
        {
            // on quitte l'appli en appuyant sur back
        }
    }

    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
        if (_estNouvelleInstance)
        {
            if (State.Count > 0)
            {
                // application a été désactivée par l'OS, on peut accéder au dictionnaire d'état
                // pour restaurer les infos
                laPage = (string)State["MainPage"];
            }
            else
            {
                // équivalent à un démarrage de l'appli
                laPage = "MainPage";
            }
        }
        else
        {
            // la page est gardée en mémoire, pas besoin d'aller lire le dictionnaire d'état
        }
        _estNouvelleInstance = false;
    }
}

J’espère que les commentaires sont assez explicites. Ce qu’il faut retenir c’est que si nous démarrons l’application en appuyant sur F5, que nous saisissons un texte dans le TextBox et que nous appuyons sur le bouton menu, alors l’application est suspendue (voir la figure suivante).

Appui sur le bouton de menu pour que l'application soit suspendue
Appui sur le bouton de menu pour que l'application soit suspendue

Nous sommes alors passés dans la méthode OnNavigatedTo et nous sommes dans le cas où _estNouvelleInstance vaut vrai et que le dictionnaire d’état est vide (démarrage de l’application). Lorsqu’on clique sur le bouton de menu, alors nous passons dans la méthode OnNavigatedFrom qui indique que la page est désactivée. Vous arrivez alors sur la page d’accueil de votre émulateur (ou de votre Windows Phone). Un petit clic sur le bouton de retour vous ramène sur notre application avec la zone de texte qui correspond à ce que nous avons saisi. On repasse dans la méthode OnNavigatedTo avec _estNouvelleInstance qui vaut faux. Ceci prouve bien que l’application est intacte en mémoire et que nous ne sommes pas repassés dans le constructeur de la classe. Il n’y a rien à faire car l’application est exactement la même qu’avant son changement d’état.
Il ne reste plus qu’à cliquer à nouveau sur la flèche de retour pour fermer l’application et ainsi repasser dans la méthode OnNavigatedFrom mais cette fois-ci dans le else, quand e.NavigationMode vaut NavigationMode.Back.
Remarquez que le débogueur est toujours en route et qu’il faut l’arrêter. Voilà pour l’état suspendu.

Pour simuler l’état désactivé, il faut aller dans les propriétés du projet en faisant un clic droit dessus, puis propriétés. On arrive sur l’écran des propriétés du projet, cliquez sur déboguer et vous pouvez alors cocher la case qui permet de forcer à passer dans l’état désactivé (Tombstone) lorsque l’on suspend l’application (voir la figure suivante).

Activer le tombstoning de l'application
Activer le tombstoning de l'application

Maintenant, lorsque vous allez appuyer sur F5, saisir un texte dans la TextBox, puis appuyer sur le bouton de menu, l’application sera désactivée, comme si c’était le système d’exploitation qui le faisait pour libérer de la mémoire. Revenez en arrière pour réveiller l’application, nous pouvons constater que le TextBox est vide. L’état de l’application n’est pas conservé et nous passons cette fois-ci dans la méthode OnNavigatedTo mais lorsque le dictionnaire d’état n’est pas vide. Il contient en l’occurrence ce que nous avons associé à la chaine « MainPage ». Nous allons donc pouvoir nous servir du dictionnaire d’état pour restaurer l’état de l’application lorsque celle-ci est désactivée.

Allez modifier le XAML pour donner un nom à notre TextBox :

<TextBox x:Name="LeTextBox" />

Puis modifiez le code behind, tout en conservant le squelette de MainPage, pour avoir ceci :

public partial class MainPage : PhoneApplicationPage
{
    private bool _estNouvelleInstance = false;

    public MainPage()
    {
        InitializeComponent();
        _estNouvelleInstance = true;
    }

    protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
    {
        if (e.NavigationMode != System.Windows.Navigation.NavigationMode.Back)
        {
            // l'appli est désactivée, la page est quittée
            State["MonTexte"] = LeTextBox.Text;
        }
        else
        {
            // on quitte l'appli en appuyant sur back
        }
    }

    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
        if (_estNouvelleInstance)
        {
            if (State.Count > 0)
            {
                // application a été désactivée par l'OS, on peut accéder au dictionnaire d'état pour restaurer les infos
                LeTextBox.Text = (string)State["MonTexte"];
            }
            else
            {
                // équivalent à un démarrage de l'appli
            }
        }
        else
        {
            // la page est gardée en mémoire, pas besoin d'aller lire le dictionnaire d'état
        }
        _estNouvelleInstance = false;
    }
}

Et voilà. L’état de la zone de texte est restauré grâce à :

LeTextBox.Text = (string)State["MonTexte"];

Qui est exécuté lorsque l’application est désactivée.
Vous me direz qu’on s’embête peut-être un peu pour rien. Ne pourrait-on pas remplacer la méthode OnNavigatedTo par :

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    if (State.ContainsKey("MonTexte"))
        LeTextBox.Text = (string)State["MonTexte"];
}

Car finalement, peu importe si on est en mode démarré, suspendu ou désactivé, tout ce qui nous intéresse c’est que le TextBox soit rempli si jamais il l’a été auparavant.
Je vous dirais oui, mais… Ici, l’appel au dictionnaire d’état est assez rapide, mais imaginons que nous ayons besoin d’aller lire une information sur internet (ce que nous apprendrons à faire très bientôt), ou effectuer un calcul complexe, ou quoi que ce soit, ce n’est pas la peine de le faire si nous possédons déjà l’information. Cela fluidifie le redémarrage de l’application, évite de consommer des datas pour rien, etc. Veillez toujours à ne pas faire des choses inutiles et gardez à l’esprit qu’un téléphone a des ressources limitées.

Et les événements applicatifs ?

Ils servent aussi à ça. Lorsque l’application est suspendue ou désactivée, nous avons vu que l’événement application Deactivated était levé. C’est également l’emplacement idéal pour faire persister des informations dans le dictionnaire d’état :

private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
    PhoneApplicationService.Current.State["DateDernierLancement"] = DateTime.Now;
}

De la même façon, lorsque l’application est réactivée, que ce soit en reprise rapide (depuis l’état suspendu) ou en reprise lente (depuis l’état désactivée), l’événement applicatif Activated est levé. C’est également un endroit idéal pour préparer à nouveau l’état de notre application :

private void Application_Activated(object sender, ActivatedEventArgs e)
{
    if (PhoneApplicationService.Current.State.ContainsKey("DateDernierLancement"))
    {
        DateTime dernierLancement = (DateTime)PhoneApplicationService.Current.State["DateDernierLancement"];
        if (DateTime.Now - dernierLancement > TimeSpan.FromMinutes(30))
        {
            // si ca fait plus de trente minutes que l'application est désactivée, mon information n'est peut-être plus à jour
            TelechargerLesNouvellesDonnees();
        }
    }
}

Mais bon, il y a encore un petit problème ! Étant donné que nous ne maîtrisons pas le passage en désactivé, encore moins la fermeture forcée de l’application par le système d’exploitation, ou encore le redémarrage manuel de l’application par l’utilisateur (s’il relance l’application depuis la page d’accueil), nous risquons de perdre à nouveau toutes les informations que notre utilisateur a saisi mais cette fois-ci, pas parce que nous avons mal géré la désactivation, mais parce que l’application s’est terminée !

La solution est d’utiliser la même mécanique mais en faisant persister les informations dans la mémoire du téléphone dédiée à l’application. Il s’agit du répertoire local (en anglais Local folder), également connu sous son ancien nom : IsolatedStorage. Voyez cela un peu comme des fichiers sur un disque dur où nous pouvons enregistrer ce que bon nous semble. Puisque cette information persiste entre les démarrages successifs de l’application, il sera possible d’enregistrer l’état de notre application afin par exemple que l’utilisateur ne perde pas toute sa saisie.
Je ne vais pas détailler le code qui permet d’enregistrer des informations dans la mémoire du téléphone, car j’y reviendrai dans un prochain chapitre.

Avant de terminer, sachez qu’il existe un autre état, l’état Obscured, que l’on peut traduire par « obscurci ». Il s’agit d’un état où une partie de l’écran est masqué, par exemple lorsqu’on reçoit un SMS, un appel, une notification, etc. L’application reste dans un état où elle est en cours d’exécution, mais l’application peut devenir difficile à utiliser. Imaginons que votre utilisateur soit en plein compte à rebours final, prêt à vaincre le boss final et qu’il reçoive un SMS juste au moment où il va gagner et qu’à cause de cela il reçoit la flèche fatale juste en plein milieu du cœur…, il va maudire votre application, à juste titre !
Pour éviter cela, il est possible d’être notifié lorsque l’application passe en mode Obscured, ce qui nous laisse par exemple l’opportunité de faire une pause dans notre compte à rebours final … Pour cela, rendez-vous dans le constructeur de la classe App pour vous abonner aux événements Obscured et Unobscured :

public App()
{
    // plein de choses …

    RootFrame.Obscured += RootFrame_Obscured;
    RootFrame.Unobscured += RootFrame_Unobscured;
}

private void RootFrame_Unobscured(object sender, EventArgs e)
{
    // L’application quitte le mode Obscured
}

private void RootFrame_Obscured(object sender, ObscuredEventArgs e)
{
    // L’application passe en mode Obscured
    bool estVerouille = e.IsLocked;
}

Remarquez que le paramètre de type ObscuredEventArgs permet de savoir si l’écran est verrouillé ou non.

  • Il est possible de naviguer de page en page dans une application grâce au service de navigation.

  • Le contrôle HyperlinkButton permet de démarrer une navigation très simplement.

  • Il est possible de faire transiter des informations de contexte entre les pages ; on pourra utiliser la query string ou le dictionnaire d’état.

  • Pour déclencher un retour arrière par code, on utilisera la méthode GoBack() du NavigationService.

  • On peut ajouter facilement une image d’accueil à une application Windows Phone en utilisant une image JPEG, nommée SplashScreenImage.jpg.

  • Il est très important de gérer correctement les différents états par lesquels peut passer une application afin de fournir une expérience d’utilisation la plus optimale.

Exemple de certificat de réussite
Exemple de certificat de réussite