• 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

Navigateur web

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

Malgré tous les superbes contrôles dont dispose Windows Phone, vous allez parfois avoir besoin d’afficher du HTML ou bien directement une page web.
C’est ainsi que le SDK de Windows Phone dispose d’un contrôle bien pratique : le WebBrowser. Vous pouvez le voir comme un mini Internet Explorer que l’on peut mettre où on veut dans une page et qui n’a pas toute la gestion des barres d’adresses, des favoris, …

Si nos téléphones possèdent déjà un navigateur web, en l’occurrence Internet Explorer, à quoi pourrait bien servir un tel contrôle ?

Les scénarios sont divers, cela peut aller de l’affichage d’un billet issu d’un flux RSS à une authentification via un formulaire HTML, sur un réseau social par exemple. Ou pourquoi pas un jeu en HTML5 ?
De plus, il est également possible de communiquer entre le Javascript d’une page web et notre page XAML. Regardons tout cela de plus près.

Naviguer sur une page web

Tout d’abord, il nous faut ce fameux contrôle. Vous pouvez le mettre dans votre XAML via la boite à outils, comme indiqué à la figure suivante.

Le contrôle WebBrowser dans la boite à outils
Le contrôle WebBrowser dans la boite à outils

Ou comme nous en avons désormais l’habitude, directement dans le XAML :

<phone:WebBrowser x:Name="MonWebBrowser" />

Il est ensuite possible de naviguer sur une page web grâce à la méthode Navigate() qui prend une URI en paramètre :

public MainPage()
{
    InitializeComponent();
    MonWebBrowser.Navigate(new Uri("http://fr.openclassrooms.com/informatique/cours/apprenez-a-developper-en-c", UriKind.Absolute));
}

Ici, j’effectue la navigation dans le constructeur de la page. La page internet s’affiche donc comme on peut le voir sur la figure suivante.

La page web s'affiche dans le contrôle
La page web s'affiche dans le contrôle

(si bien sûr vous êtes connectés à internet !)

Evénements de navigation

Le contrôle WebBrowser possède également des événements qui permettent de savoir par exemple quand une page est chargée, il s’agit de l’événement Navigated. Ce qui est pratique si l’on souhaite afficher un message d’attente, ou si on veut n’afficher vraiment le WebControl qu’une fois la page complètement chargée.
Il y a également un autre événement intéressant qui permet de savoir si la navigation a échoué, par exemple si l’utilisateur ne capte plus internet. Il s’agit de l’événement NavigationFailed. Cet événement nous fournit notamment une exception qui peut nous donner plus d’informations sur l’erreur.

Il est toujours intéressant d’indiquer à l’utilisateur si la navigation a échoué. Il est également approprié de lui proposer un bouton lui permettant de retenter sa navigation, si jamais il se trouve à nouveau dans une zone de couverture.

Navigation interne

Mais nous pouvons également créer notre propre HTML et l’afficher grâce à la méthode NavigateToString :

public MainPage()
{
    InitializeComponent();
    MonWebBrowser.NavigateToString(
        @"<html>
            <body>
                <h3>Bonjour HTML !</h3>
            </body>
        </html>");
}

Qui donnera la figure suivante.

Affichage direct de HTML
Affichage direct de HTML

Vous avouerez que ce n’est pas très pratique de devoir saisir le HTML dans le code. Cela serait plus pratique de pouvoir intégrer un fichier HTML à notre application et de naviguer dessus. Pour ce faire, il va falloir dans un premier temps intégrer le fichier dans le répertoire local. Commencez déjà par ajouter un nouveau fichier de type texte au projet que vous nommez hello.html et qui possède le code suivant :

<html>
    <body>
        <h3>Bonjour HTML local!</h3>
    </body>
</html>

Ensuite, dans les propriétés du fichier, vérifiez que l’action de génération est à « contenu ».
Puis, on peut utiliser le code suivant pour ajouter un fichier HTML dans le répertoire local :

public MainPage()
{
    InitializeComponent();
    IntegreHtmlDansRepertoireLocalSiNonPresent("hello.html");
    MonWebBrowser.Navigate(new Uri("hello.html", UriKind.Relative));
}

private void IntegreHtmlDansRepertoireLocalSiNonPresent(string nomFichier)
{
    IsolatedStorageFile systemeDeFichier = IsolatedStorageFile.GetUserStoreForApplication();

    if (!systemeDeFichier.FileExists(nomFichier))
    {
        // lecture du fichier depuis les ressources
        StreamResourceInfo sr = Application.GetResourceStream(new Uri(nomFichier, UriKind.Relative));

        using (StreamReader reader = new StreamReader(sr.Stream))
        {
            string html = reader.ReadToEnd();
            using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(nomFichier, FileMode.Create, IsolatedStorageFile.GetUserStoreForApplication()))
            {
                using (StreamWriter writer = new StreamWriter(stream))
                {
                    writer.Write(html);
                    writer.Close();
                }
            }
        }
    }
}

Le principe est de vérifier la présence du fichier. S’il n’existe pas alors on le lit depuis les ressources comme on l’a déjà vu, puis on écrit le contenu dans le répertoire local.
Il ne restera plus qu’à naviguer sur ce fichier créé grâce à la méthode Navigate comme on peut le voir plus haut.

Communiquer entre XAML et HTML

Le WebBrowser a aussi la capacité de faire communiquer la page web et la page XAML. Plus particulièrement, il est possible d’invoquer une méthode Javascript depuis notre page XAML et inversement, la page web peut déclencher un événement dans notre application.
Pour que ceci soit possible, vous devez positionner la propriété IsScriptEnabled à true dans votre WebBrowser et vous abonner à l’événement ScriptNotify :

<phone:WebBrowser x:Name="MonWebBrowser" IsScriptEnabled="True" ScriptNotify="MonWebBrowser_ScriptNotify" />

Pour que cela soit plus simple, je vais illustrer le fonctionnement avec du HTML et du Javascript que j’embarquerai dans mon application avec la méthode montrée précédemment. Mais il est bien sûr possible de faire la même chose avec une page sur internet.
L’événement ScriptNotify est levé lorsque la page web invoque la méthode Javascript window.external.notify(). Cette méthode accepte un paramètre sous la forme d’une chaine de caractères qui pourra être récupérée dans l’événement ScriptNotify.
Pour l’illustrer, modifions notre page hello.html pour avoir :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Demo javascript</title>
    <script type="text/javascript">
      function EnvoyerMessage()
      {
        window.external.notify("Bonjour, je suis " + prenom.value);
        resultat.innerHTML = "Message bien envoyé";
      }
    </script>
  </head>
  <body>
    <h3>Communication entre page web et XAML</h3>
    <p>Saisissez votre prénom : </p>
    <input type="text" id="prenom" />
    <input type="button" value="Dire bonjour" onclick="EnvoyerMessage();" />
    <div id="resultat" />
  </body>
</html>

Cette page possède une zone de texte pour saisir un prénom et un bouton qui invoque la méthode Javascript EnvoyerMessage(). Cette méthode récupère la valeur du champ saisi, la concatène à la chaine « Bonjour, je suis » et l’envoie à notre application Windows Phone via la méthode window.external.notify. Enfin, elle affiche un message sur la page web pour indiquer que le message a bien été envoyé.
Côté code-behind, nous avons juste à naviguer sur notre page et à récupérer la valeur envoyée :

public partial class MainPage : PhoneApplicationPage
{
    public MainPage()
    {
        InitializeComponent();
        IntegreHtmlDansRepertoireLocalSiNonPresent("hello.html", true);
        MonWebBrowser.Navigate(new Uri("hello.html", UriKind.Relative));
    }

    private void IntegreHtmlDansRepertoireLocalSiNonPresent(string nomFichier, bool force)
    {
        IsolatedStorageFile systemeDeFichier = IsolatedStorageFile.GetUserStoreForApplication();

        if (!systemeDeFichier.FileExists(nomFichier) || force)
        {
            // lecture du fichier depuis les ressources
            StreamResourceInfo sr = Application.GetResourceStream(new Uri(nomFichier, UriKind.Relative));

            using (StreamReader reader = new StreamReader(sr.Stream))
            {
                string html = reader.ReadToEnd();
                using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(nomFichier, FileMode.Create, IsolatedStorageFile.GetUserStoreForApplication()))
                {
                    using (StreamWriter writer = new StreamWriter(stream))
                    {
                        writer.Write(html);
                        writer.Close();
                    }
                }
            }
        }
    }

    private void MonWebBrowser_ScriptNotify(object sender, NotifyEventArgs e)
    {
        MessageBox.Show(e.Value);
    }
}

Notez que j’ai rajouté un paramètre à la méthode permettant de stocker la page HTML dans le répertoire local, qui force l’enregistrement afin d’être sûr d’avoir toujours la dernière version.
Rappelez-vous, nous recevons la valeur envoyée par la page web grâce à l’événement ScriptNotify. Lorsque cette chaine est reçue, on l’affiche simplement avec une boite de message. Démarrons l’application, la page web s’affiche, comme vous pouvez le voir à la figure suivante.

La page web avant envoi du message
La page web avant envoi du message

Notez que nous sommes un peu obligés de zoomer pour pouvoir voir le contenu de la page web et cliquer sur le bouton. Pour rappel, le zoom s’effectue avec deux doigts, en posant les doigts sur l’écran et en les étirant vers l’extérieur. Ce mouvement s’appelle le Pinch-to-zoom. Il est également possible de double-cliquer dans l'émulateur afin de produire le même effet. Nous verrons comment corriger ce problème plus loin.
Saisissez une valeur et cliquez sur le bouton. Le message est bien envoyé par la page HTML et est bien reçu par notre application, comme en témoigne la figure suivante.

L'application Windows Phone reçoit un message de la page web
L'application Windows Phone reçoit un message de la page web

Mais alors, cette page HTML illisible, on ne peut pas un peu l’améliorer ?
Il y a plusieurs solutions pour ce faire. La première est d’utiliser un tag meta que le navigateur va interpréter. Cette balise se met à l’intérieur de la balise <head> :

<meta name="viewport" content="width=device-width, user-scalable=no" />

Elle permet de définir la taille de la fenêtre. On peut y mettre une valeur numérique allant de 320 à 10000 ou l’ajuster directement à la taille du téléphone avec la valeur device-width. Remarquez, que la propriété user-scalable empêchera l’utilisateur de pouvoir zoomer dans la page. Voici le rendu à la figure suivante.

Le zoom est adapté à la largeur de la page
Le zoom est adapté à la largeur de la page

Ce qui est beaucoup plus lisible ! :)
L’autre solution est d’utiliser une propriété CSS pour ajuster la taille du texte :

<h3 style="-ms-text-size-adjust:300%">Communication entre page web et XAML</h3>

Ici, j’augmente la taille de cette balise de 300%.
Remarquez que cette balise est incompatible avec la balise viewport.

Il est possible de faire communiquer nos deux éléments également dans l’autre sens. Ainsi, nous pouvons invoquer une méthode Javascript présente sur la page web depuis le code C#. Modifions notre page pour qu’elle possède une méthode Javascript qui accepte deux paramètres :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta name="viewport" content="width=device-width, user-scalable=no" />
    <title>Demo javascript</title>
    <script type="text/javascript">
      function ReceptionMessage(texte, heure)
      {
          resultat.innerHTML = texte + ". Il est " + heure;
          return "OK";
      }
    </script>
  </head>
  <body>
    <h3>En attente d'un envoi ...</h3>
    <div id="resultat" />
  </body>
</html>

Rajoutons ensuite dans notre XAML un bouton qui va permettre d’envoyer des informations à la page web :

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="auto" />
    </Grid.RowDefinitions>
    <phone:WebBrowser x:Name="MonWebBrowser" IsScriptEnabled="True" ScriptNotify="MonWebBrowser_ScriptNotify" />
    <Button Content="Envoyer l'heure" Tap="Button_Tap" Grid.Row="1" />
</Grid>

Et dans le code-behind nous aurons :

private void Button_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
    string retour = (string)MonWebBrowser.InvokeScript("ReceptionMessage", "Bonjour depuis Windows Phone", DateTime.Now.ToShortTimeString());
}

On utilise la méthode InvokeScript de l’objet WebBrowser en lui passant en paramètre le nom de la méthode Javascript à appeler. Puis nous pouvons passer ensuite autant de paramètres que nous le souhaitons, sous la forme d’une chaine de caractères. Il faut bien sûr qu’il y ait autant de paramètres que peut accepter la méthode Javascript. Ce qui donne la figure suivante.

Réception par la page HTML du message envoyé par l'application Windows Phone
Réception par la page HTML du message envoyé par l'application Windows Phone

Notez que le Javascript peut renvoyer une valeur au code C#. Ici je renvoie la chaine OK, que je stocke dans la variable retour pour une éventuelle interprétation.
Remarquez qu’il est également possible de passer des objets complexes grâce au JSON. Le principe consiste à envoyer une version sérialisée d’un objet à la page web et la page web désérialise cet objet pour pouvoir l’utiliser. Utilisons donc la bibliothèque open-source JSON.NET que nous avions précédemment utilisée afin de sérialiser un objet. Référencez l’assembly Newtonsoft.Json.dll et créez une classe avec des propriétés :

public class Informations
{
    public string Message { get; set; }
    public DateTime Date { get; set; }
}

Puis, sérialisez un objet pour l’envoyer à notre méthode Javascript :

private void Button_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
    Informations informations = new Informations { Message = "Bonjour depuis Windows Phone", Date = DateTime.Now };
    string objetSerialise = JsonConvert.SerializeObject(informations);
    Retour retour = JsonConvert.DeserializeObject<Retour>((string)MonWebBrowser.InvokeScript("ReceptionMessage", objetSerialise));
}

De la même façon, on pourra désérialiser le retour de la méthode, dans l’objet Retour suivant :

public class Retour
{
    public string Resultat { get; set; }
    public bool Succes { get; set; }
}

Il ne reste plus qu’à modifier le Javascript de la page :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta name="viewport" content="width=device-width, user-scalable=no" />
    <title>Demo javascript</title>
    <script type="text/javascript">
      function ReceptionMessage(objet)
      {
        var infos = JSON.parse(objet);
        var d = new Date(infos.Date);
        resultat.innerHTML = infos.Message + ". Il est " + d.getHours() + 'h' + d.getMinutes();
        var retour = {
          Resultat : "OK",
          Succes : true
        }
        return JSON.stringify(retour);
      }
    </script>
  </head>
  <body>
    <h3>En attente d'un envoi ...</h3>
    <div id="resultat" />
  </body>
</html>

Pour désérialiser du JSON coté javascript, on utilise la méthode JSON.parse et pour sérialiser, on utilisera JSON.stringify.
Et voilà. Plutôt puissant n’est-ce pas ?

  • Le contrôle WebBrowser nous permet facilement d’afficher du HTML dans nos applications Windows Phone.

  • Il est possible d’interagir entre l’application et la page web grâce à du Javascript.

  • Grâce au JSON, nous pourrons passer des paramètres complexes entre l’application et la page web.

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