IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Windows Phone 7.


précédentsommaire

VIII. Comment faire

VIII-A. SplashScreen

C'est une fenêtre qui s'ouvre au démarrage d'un programme, qui montre simplement une belle image, ensuite la fenêtre « Splash » disparaît et la fenêtre principale apparaît.

En WP c'est simple :

Il y a dans l'explorateur de solution un fichier nommé SplashScreenImage.jpg, il fait 480*800 pixels. Il suffit de double-cliquer dessus pour se retrouver dans Paint et modifier le SplashScreen.
Dans ses propriétés, « Action de génération » doit être à « contenu ».

S'il n'y a pas ce fichier, il n'y a pas de SplashScreen.
Si on veut que le SplashScreen reste plus longtemps il faut, dans le constructeur de la page (sous InitializeComponent) mettre une Thread.Sleep (voir chapitre « perdre du temps »).

 
Sélectionnez
using System.Threading;

namespace customcontrol
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructeur
        public MainPage()
        {
            InitializeComponent();
            Thread.Sleep(500);

VIII-B. Image de fond de page, icône

Dans le projet il y a déjà par défaut :
ApplicationIcon.png : icône de l'application (62*62 pixels) qui sera affichée dans la liste des applications ;
Background.png : icône qui sera affichée lorsque l'application est "épinglée" (pinned) sur la page d'accueil du téléphone (173*173 pixels).

Dans les propriétés du projet (menu "Projet" puis "Propriétés de") on peut modifier cela.

Image non disponible

Dans l'explorateur de solution à droite, il faut double-cliquer sur le nom d'une de ces deux images pour se retrouver dans Paint (ou Paint.Net ici) et ainsi la modifier.

Image non disponible

Pour ses deux icônes si on veut un fond ayant la couleur du thème il faut, au lieu de mettre un fond coloré, mettre un fond transparent, un avant plan blanc et sauvegarder votre image en .PNG avec support de la transparence (sauvegarde en 32 bits). J'utilise Paint.Net pour cela.

Image non disponible

Ici on a la liste des applications avec les icônes (ApplicationIcon.png de 63x63 px), WP ajoute le nom de l'application à droite.

Image non disponible

Ici, pour l'icône épinglée (Background.png 173x173 px) WP ajoute sur l'image le nom de l'application ('My app' ici) avec des caractères de 20 px de hauteur, à 7 px du bord gauche, et 7 px du bas.

Comment mettre une image de fond dans une page Panorama ou Pivot ?

 
Sélectionnez
<controls:Panorama  Title="mon application" >


 <controls:Panorama.Background>
                <ImageBrush ImageSource="Panoramafond.png"/>
 </controls:Panorama.Background>

Pour un panorama, si l'image à une largeur de deux pages mais que le panorama a quatre pages, le fond se déroulera lentement et s'affichera sur les quatre pages.

Comment mettre un fond sur une page simple ?
Il faut mettre l'image dans le background de la grille racine :

 
Sélectionnez
 <!--LayoutRoot est la grille racine où tout le contenu de la page est placé-->
    <Grid x:Name="LayoutRoot" >
        <Grid.Background>
            <ImageBrush ImageSource="PanoramaBackground.png" Stretch="UniformToFill" />
        </Grid.Background>

Le problème est que parfois on a (si on utilise un thème avec arrière-fond clair) une bande blanche en haut.

Image non disponible

Dans ce cas il ne faut pas afficher le SystemTray et il ne faut pas mettre de taille dans la Grid LayoutRoot (ainsi elle remplira la totalité de l'espace).
Si on a modifié la Grid à la souris, il apparaît la propriété Height, ensuite on a du mal à gérer, il vaut donc mieux enlever « Height=" " ».

 
Sélectionnez
shell:SystemTray.IsVisible="False"

 <!--LayoutRoot est la grille racine où tout le contenu de la page est placé-->
    <Grid x:Name="LayoutRoot" >

Comment mettre en fond de page une couleur aléatoire :

 
Sélectionnez
ContentPanel.Background =
new SolidColorBrush(Color.FromArgb(255, (byte)rand.Next(256),
(byte)rand.Next(256),
(byte)rand.Next(256)));

VIII-C. Positionnement dynamique des contrôles

Layout Absolu 
Dans un positionnement en Layout Absolu, les éléments sont placés dans un canvas à une position exacte absolue relative à leur élément parent.
Cela ne prend pas en compte les dimensions de l'écran.

Layout dynamique 
Permet un positionnement quel que soit la résolution de l'écran.
On utilise un StackPanel ou surtout une Grid.
Dans les cellules, on met des contrôles avec les propriétés Width et Height= Auto. Ils occupent toute la cellule (Margin permet de laisser un espace autour).
S'il y a un texte à afficher en totalité on donne une valeur à MinHeight et MinWidth pour que le texte ne soit pas tronqué.
On donne des dimensions relatives pour les colonnes et les lignes de la Grid (dans RowDefinition et ColumnDefinition) à l'aide des *.

L'utilisateur utilise son doigt pour toucher les éléments visuels ; il est conseillé d'agrandir la zone de touché bien au-delà de la zone visuelle. Les éléments trop rapprochés les uns des autres introduisent un risque pour l'utilisateur d'appuyer sur le mauvais bouton. Les contrôles de Silverlight sont déjà optimisés par nature, en ayant naturellement une Margin importante.
Il y a des contraintes de taille et Microsoft donne les conseils suivants :
une cible doit être au moins un carré de 34 px avec un espacement d'au moins 8 px. L'agrandissement de la zone de touché doit être d'au moins 60 % de la taille de l'élément. Pour les éléments textuels touchables, la taille de police doit être d'au moins 15 pts.

VIII-D. Navigation entre pages, transfert de paramètres

La page de démarrage est par défaut « MainPage.xaml ».
Si on veut en mettre une autre, il faut dans l'explorateur de solution, cliquer sur « Properties » puis double-cliquer sur « WMAppManifest.xml » et modifier la ligne :

 
Sélectionnez
 <DefaultTask  Name ="_default" NavigationPage="MainPage.xaml"/>

Comment dans une page ouvrir une autre page nommée « PageConvert.xaml » ?

En C# :

 
Sélectionnez
 NavigationService.Navigate(new Uri("/PageConvert.xaml", UriKind.Relative));

La Classe NavigationService contient ce qu'il faut pour naviguer. Les méthodes Navigate mais aussi GoBack, GoForward…

En XAML : on peut aussi utiliser un hyperlinkButton :

 
Sélectionnez
<HyperlinkButton NavigateUri="/PageConvert.xaml" Content="Aller à pageconvert" />

Exemple complet 
On met trois boutons dans une page, cliquer sur un des boutons ouvre la page correspondante.

Code XAML des boutons :

 
Sélectionnez
<Button x:Name="ButtonRouge" Content="Rouge" Click="Button_Click" Width="200" Height="75" />
<Button x:Name="ButtonVert" Content="Vert" Click="Button_Click" Width="200" Height="75" />
<Button x:Name="ButtonBleue" Content="Bleue" Click="Button_Click" Width="200" Height="75" />


Code C# :

 
Sélectionnez
private void Button_Click(object sender, RoutedEventArgs e)
{
    Button clickedButton = sender as Button;

    switch(clickedButton.Name)
    {
        case "ButtonRouge":
            NavigationService.Navigate(new Uri("/PageRouge.xaml", UriKind.Relative));
            break;
        case "ButtonVert":
            NavigationService.Navigate(new Uri("/PageVerte.xaml", UriKind.Relative));
            break;
        case "ButtonBleue":
            NavigationService.Navigate(new Uri("/PageBleue.xaml", UriKind.Relative));
            break;
    }
}

Comment passer un texte ?
Quand on clique sur button1, ouvrir SecondPage.xaml. Passer « montexte » de la page actuelle à la page SecondPage.xaml.

On va utiliser les QueryString : pour l'appel d'une nouvelle page avec NavigationService.Navigate, on ajoute le texte à l'URI (querystring= 'msg', valeur="montexte"). C'est comme pour une page Web, on utilise le point d'interrogation suivi d'une clé et de sa valeur. Dans la page qui s'ouvre on récupère le texte par NavigateContext.QueryString :

 
Sélectionnez
private void button1_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/SecondPage.xaml?msg="+"montexte",UriKind.Relative));
}


Dans SecondPage :

 
Sélectionnez
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string msg = "";
if (NavigationContext.QueryString.TryGetValue("msg", out msg))
//msg contient montexte.
}

La méthode OnNavigatedTo de la page s'exécute lorsque la page devient active. Elle est préférable à la méthode « Loaded » qui peut s'exécuter plusieurs fois.
On surcharge donc cette méthode pour récupérer le QueryString.

On peut mettre plusieurs textes séparés par '&'.

 
Sélectionnez
private void button1_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/SecondPage.xaml?msg=montexte&msg2=montexte2",UriKind.Relative));
}


Comment passer un objet ?

En utilisant le dictionnaire d'état temporaire avec PhoneApplicationService.Current.State permettant de stocker les données de l'application, un objet en particulier.

Il faut au préalable inclure l'espace de noms Microsoft.Phone.Shell.

 
Sélectionnez
using Microsoft.Phone.Shell;

Dans la page de départ :

 
Sélectionnez
Personne MyPersonne; // soit un objet MyPersonne de type Personne
PhoneApplicationService.Current.State["ItemEnCours"] = MyPersonne;

Ouvrir la seconde page et surcharger OnNavigateTo dans celle-ci. Récupérer l'objet dans les données de l'application.

 
Sélectionnez
using Microsoft.Phone.Shell;

namespace CalculeTout
{
    public partial class PageConvert : PhoneApplicationPage
    {
        //Variable 
        ElementDeListe currentCalcul;
        Boolean IsInverse;
        public PageConvert()
        {
            InitializeComponent();
            
        }

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            //Recupération de l'objet de type personne
            base.OnNavigatedTo(e);
            MyLocalPersonne = (personne) PhoneApplicationService.Current.State["ItemEnCours"];
            
            {

            }

        }

Comment retourner à la page précédente avec du code ?

 
Sélectionnez
NavigationService.GoBack();

Bien sûr il y a le bouton de gauche qui est le bouton « back ».

Comment détourner l'usage du « back Button », exécuter du code et annuler son effet ?
En surchargeant la méthode OnBackKeyPress :

 
Sélectionnez
 protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
    {
        //votre code.
        e.Cancel = true;  //annule l'effet 'back'.
    }

VIII-E. Validation de caractère dans un TextBox

Problème récurrent.
Je veux permettre la saisie des chiffres de 0 à 9 (uniquement) et permettre l'effacement (back) dans un TextBox nommé « entree1 », comment faire ?


Premièrement, il faut bien choisir le clavier virtuel (InputScope). On utilise « Digit ».

 
Sélectionnez
<TextBox Name="entree1"  KeyUp="TesteTouche">
                <TextBox.InputScope>
                    <InputScope>
                        <InputScopeName NameValue="Digit" />
                    </InputScope>
                </TextBox.InputScope>
            </TextBox>

Quand le TextBox à le focus, le clavier suivant apparaît :

Image non disponible


Ce clavier ne permet de saisir que des chiffres mais parfois il y a d'autres caractères possible qu'il faut éliminer (le point ici).
On va donc intercepter l'évènement KeyUp (KeyUp="TesteTouche" dans le XAML précédent) qui se déclenche quand on appuie sur une touche, cela exécutera « TesteTouche » ; cette routine va accepter les seules touches permises.

 
Sélectionnez
private void TesteTouche(object sender, KeyEventArgs e)
        { //Controle validité des touches
            //touches permisses
            string keys;
            keys = "1234567890";
            TextBox TextBoxControl= (TextBox) sender;            
            for (int j = 0; j < TextBoxControl.Text.Length; j++)
                 {
                 if ( ! (keys.Contains(TextBoxControl.Text.Substring(j,1))))
                 {TextBoxControl.Text=TextBoxControl.Text.Remove(j,1);
                 TextBoxControl.SelectionStart = TextBoxControl.Text.Length;
                 }
                 }  
         }

keys est une string qui contient les touches permises.
Je caste le sender en TextBox.
Je regarde si chaque caractère du TextBox fait partie des caractères autorisés ; sinon je l'élimine.
Enfin je remets le curseur à la fin.

Si la saisie doit permettre les nombres fractionnaires, il faut accepter le bon séparateur décimal. Une méthode est de lire ce séparateur ('.' ou ',') dans la currentCulture et de l'ajouter à keys.

 
Sélectionnez
//touches permisses
            string keys;
            keys = "1234567890";
            if (Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator == ",")
            { 
                keys = keys + ","; 
            }
            else
            {
                keys = keys + ";";

            }

Comment remplacer un caractère par un autre au cours de la saisie ?
Ici on va utiliser TextChanged :

 
Sélectionnez
 <TextBox Name="entree2" TextChanged="ChangeCar"  >
 </TextBox>

Et dans le code behind :

 
Sélectionnez
private void ChangeCar(object sender, TextChangedEventArgs e)
        { 
           if (entree2.Text.Contains("1"))
                {
                  entree2.Text = entree2.Text.Replace("1", "2");
           
                entree2.SelectionStart = entree2.Text.Length;
               }
         }

Une autre méthode se trouve sur Internet.
Dans la routine C# on déclare un tableau contenant les Key (touches du clavier) à accepter.
Ensuite on teste si la touche tapée (qui est dans e.Key) est dans le tableau.
Si IndexOf retourne -1 , la touche n'y est pas.
Dans ce cas on indique d'annuler le traitement de la touche (e.Handled= true) :

 
Sélectionnez
      private void entree1_KeyDown(object sender, KeyEventArgs e)
        { //Controle validité des touches
            //touches permisses
        Key[] numeric = new Key[] {Key.Back, Key.NumPad0, Key.NumPad1,
            Key.NumPad2, Key.NumPad3, Key.NumPad4,
            Key.NumPad5, Key.NumPad6, Key.NumPad7, Key.NumPad8, Key.NumPad9  };
            // handles non numeric
            if (Array.IndexOf(numeric, e.Key) == -1)
            {
                e.Handled = true;
            }

        }

Elle ne fonctionne pas si on utilise les codes touche keyD1, KeyD2… Il faut utiliser Key.NumPad1, KeyNumPad2… (e.Key retourne la touche mais avec les InputScope, le même code est retourné pour plusieurs touches ! Cela fonctionne avec l'exemple précédent mais pas avec toutes les touches).

Autre exemple plus complexe :
L'utilisateur tape du texte dans une TextBox nommée entree.
Eliminer '*', '#', " ".
Si le séparateur décimal est '.' , remplacer ',' par '.' et vice versa.

 
Sélectionnez
private void ChangeCar(object sender, TextChangedEventArgs e)
        { 
string entr =entree.Text;

            // Le séparateur est point ou virgule? Remplacer dans la saisie ; par , ou l'inverse
            //Pour L'affichage  ToString affiche suivant la culture
            if (Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator == ",")
            {
                if (entr.Contains(".") || entr.Contains("*") || entr.Contains("#") || entr.Contains(" "))
                {
                    entr = entr.Replace(".", ",");
                    entr = entr.Replace("*", "");
                    entr = entr.Replace("#", "");
                    entr = entr.Replace(" ", "");
                    entree.Text = entr;
                    entree.SelectionStart = 500;
                }
                }
                else
                {
                    if (entr.Contains(",") || entr.Contains("*") || entr.Contains("#") || entr.Contains(" "))
                    {
                        entr = entr.Replace(",", ".");
                        entr = entr.Replace("*", "");
                        entr = entr.Replace("#", "");
                        entr = entr.Replace(" ", "");
                        entree.Text = entr;
                        entree.SelectionStart = 500;
                    }
                }
                }

VIII-F. Créer ses propres contrôles

Contrôle étendu 

On peut utiliser un contrôle et étendre ses possibilités, on peut aussi créer son propre contrôle.

On va créer un contrôle étendu nommé « TextBoxNumerique » qui est une TextBox qui n'accepte que les chiffres de 0 à 9 et permet l'effacement.

On va créer une classe.
Menu « Projet » puis « Ajouter une classe ».


Notre classe va hériter de TextBox :

 
Sélectionnez
 public class TextBoxNumerique : TextBox
 {}

On va surcharger la méthode OnKeyDown
(qui est exécutée quand l'évènement KeyDown va se produire) :

 
Sélectionnez
public class TextBoxNumerique : TextBox
 {
protected override void OnKeyDown(KeyEventArgs e)
        {
        }
}

On y teste la touche appuyée, si elle n'est pas dans le tableau des touches valides (0 à 9 et Back), on annule la touche.

Voici le code complet :

 
Sélectionnez
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace customcontrol
{
    public class TextBoxNumerique : TextBox
    {
        private readonly Key[] KeyValide = new Key[] {Key.Back, Key.NumPad0, Key.NumPad1,
            Key.NumPad2, Key.NumPad3, Key.NumPad4,
            Key.NumPad5, Key.NumPad6, Key.NumPad7, Key.NumPad8, Key.NumPad9 };
        
        public TextBoxNumerique()
        {
           
            this.InputScope = new InputScope();
            this.InputScope.Names.Add(new InputScopeName() { NameValue = InputScopeNameValue.TelephoneLocalNumber });
        }



        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (Array.IndexOf(KeyValide, e.Key) == -1)
            {
                e.Handled = true;
            }
            base.OnKeyDown(e);
        }
    }
}

Dans le constructeur on indique l'InputScope qui est « TelephoneLocalNumber » ce qui ouvre le clavier téléphone pour l'utilisateur.

On peut maintenant ajouter le contrôle dans l'UI.
Menu « Build » puis « Générer la solution » et on retrouve le contrôle dans la boîte à outils en haut.
Il faut inclure l'espace de noms (ici avec un alias nommé « local ») puis mettre le customcontrol « TextBoxNumerique » dans le code XAML.

 
Sélectionnez
 xmlns:local="clr-namespace:customcontrol"
  <!--.............--> 

        <!--ContentPanel - placez tout contenu supplémentaire ici-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            
            <local:TextBoxNumerique x:Name="MonTB" Margin="0,43,183,470" />

        </Grid>
    </Grid>

On peut utiliser les champs et méthodes hérités de TextBox dans le code C# ( MonTB.Text, par exemple).

Le Custom Control hérite d'un contrôle ; il hérite aussi des propriétés et méthodes de ce contrôle.
On peut surcharger les méthodes pour modifier le comportement ou ajouter des champs et de nouvelles méthodes.

UserControl : contrôle utilisateur.

Là on va créer un UserControl qui est un contrôle composite contenant plusieurs contrôles et réutilisable.
Il dérive de la classe UserControl ; il a une propriété « Content » où on mettra les contrôles.


On va créer un UserControl contenant deux TextBox permettant de saisir un nom, un mot de passe, un bouton « ok » qui déterminera si le mot de passe est valide.


Créons le UserControl : menu « Projet » puis « Ajouter un nouvel élément ».

Image non disponible


Choisir « Contrôle utilisateur Windows Phone » puis en bas donner le nom « MyControl », puis cliquer sur ajouter.
Il s'ouvre un onglet nommé « MyControl.xaml » ; dans le concepteur il n'y a même pas de bord.
À l'aide de la boîte à outils ajouter les contrôles nécessaires :

Image non disponible

Cela donne le code XAML correspondant suivant :

 
Sélectionnez
<UserControl x:Class="Test.Mycontrol"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="480" d:DesignWidth="480">
    
    <Grid x:Name="LayoutRoot">
        <StackPanel HorizontalAlignment="Center">

            <StackPanel.Resources>
                <!--Create a Style for a TextBlock.-->
                <Style TargetType="TextBlock" x:Key="TextBlockStyle">
                    <Setter Property="Foreground" Value="Aquamarine"/>
                    <Setter Property="FontSize" Value="20"/>
                    <Setter Property="VerticalAlignment" Value="Bottom"/>
                </Style>

                <!--Create a Style for a TextBlock.-->
                <Style TargetType="TextBox" x:Key="TextBoxStyle">
                    <Setter Property="Width" Value="200"/>
                    <Setter Property="Height" Value="30"/>
                    <Setter Property="Margin" Value="4"/>
                    <Setter Property="FontSize" Value="10"/>
                    <Setter Property="Background" Value="Beige"/>
                </Style>
            </StackPanel.Resources>

            <TextBlock FontSize="18" Text="Identification."/>
            <StackPanel Orientation="Vertical" Height="74" Width="207">
                <TextBlock Style="{StaticResource TextBlockStyle}">
               Nom:
                </TextBlock>
                <TextBox Name="_Nom" Style="{StaticResource TextBoxStyle}" Height="50" FontSize="15" />
            </StackPanel>
            <StackPanel Orientation="Vertical" Height="75">
                <TextBlock Style="{StaticResource TextBlockStyle}">
                Mot de passe:
                </TextBlock>
                <TextBox Name="_MotdePasse" Style="{StaticResource TextBoxStyle}"  
                     Margin="6,4,4,4" Height="50" FontSize="15" />
            </StackPanel>
            <Button Name="Bouton" Width="108" Content="Ok"  Height="70" Click="Bouton_Click" />

        </StackPanel>
    </Grid>
</UserControl>

Il y a un TextBox nommé « _Nom », un autre nommé « _MotDePasse » et un bouton « Bouton ».


Maintenant on va créer le code propre au UserControl, dans les fonctions privées du UserControl.
Le code contenu dans les propriétés et méthodes privées va piloter le ou les contrôles internes. Ce code fournit un comportement propre au UserControl.
On va déclarer une variable bool nommée « _IsValid ». La fonction Bouton_Click (exécutée lorsque l'utilisateur clique sur « Ok ») contrôle la validité du nom et du mot de passe et si tout est valide cela entraîne _IsValid= true. Cela donne dans MyControl.xaml.cs.

 
Sélectionnez
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Test
{
    public partial class Mycontrol : UserControl
    {
       public bool _IsValid;

        public Mycontrol()
        {
            InitializeComponent();
            _IsValid = false;
        }

        
        
        private void Bouton_Click(object sender, RoutedEventArgs e)
        {
            //Validation mot de passe

            if (_Nom.Text=="toto" & _MotdePasse.Text=="pass")
            { _IsValid = true; }
        }
    
    }

Notez bien que la validation est triviale ; ce n'est pas notre propos ici.

Bien, le UserControl fonctionne mais pour le moment il n'y a pas de liaison avec l'extérieur.

Les contrôles qui sont dans le UserControl sont privés au UserControl et leurs propriétés ou méthodes ne sont pas accessibles à l'extérieur. On ne peut donc pas avoir accès à la propriété « Text » du contrôle « _Nom » par exemple. Il va falloir rajouter dans le UserControl des membres et des méthodes public qui seront accessibles à l'utilisateur du composant. Ces champs public (avec get et set) et ces méthodes publiques créeront une interface.


Ajoutons donc l'interface du UserControl
On va donc créer une propriété « public » « IsValid » pour que l'utilisateur du contrôle puisse savoir si « nom/mot de passe » sont valides, une propriété public « Nom » cela peut être utile.
Enfin une méthode Clear « public » pour réinitialiser le UserControl :

 
Sélectionnez
public bool IsValid
        {
            get
            {
                return _IsValid;
            }
            set
            {
                if (value != _IsValid)
                {
                    _IsValid = value;

                }
            }
        }

        public string Nom     // Variable public avec son get et son set
        {
            get
            {
                return _Nom.Text;
            }
            set
            {
                if (value != _Nom.Text)
                {
                    _Nom.Text = value;

                }
            }
        }


        public void Clear()
        {
            _Nom.Text = "";
            _MotdePasse.Text = "";
            _IsValid = false;
        }


Le UserControl est terminé, un coup de menu « Build » puis « Générer » ; maintenant on va pouvoir utiliser le UserControl.


Utilisons le UserControl « MyControl ».
Dans la page MainPage, j'ouvre la boîte à outils ; le UserControl « MyControl » est là, on peut j'ajouter à la page :

Image non disponible

Cela donne le code XAML suivant :

 
Sélectionnez
<phone:PhoneApplicationPage 
    x:Class="test.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True" 
    xmlns:my="clr-namespace:test">

    <!--LayoutRoot est la grille racine où tout le contenu de la page est placé-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <!--...........-->
        <my:Mycontrol x:Name="mycontrol1" Height="260" HorizontalAlignment="Left"  VerticalAlignment="Top" Width="262" />
        <Button Content="Button" Height="72" HorizontalAlignment="Left" Margin="112,379,0,0" Name="button1" 
        VerticalAlignment="Top" Width="160" Click="button1_Click_1" />
       
         </Grid>
 
</phone:PhoneApplicationPage>

On note que cela a ajouté la ligne « xmlns:my="clr-namespace:test » qui ajoute le namespace « test » (l'application), ce qui permet ensuite d'utiliser « my:Mycontrol ».

Dans le code C# de MainPage on peut accéder à la méthode Clear et aux propriétés IsValid et Nom du contrôle « mycontrole1 »

 
Sélectionnez
 MessageBox.Show(mycontrol1.IsValid.ToString());

Affiche true si la saisie Nom/Mot de passe est valide.

VIII-G. Gérer le BackButton

Image non disponible

On peut simuler l'appui du bouton « back » par code :

 
Sélectionnez
private void BtnBack_Click(object sender, RoutedEventArgs e)
{
NavigationService.GoBack();
}

Si un texte a été tapé dans le TextBox « MonTexte », demander confirmation avant de quitter la page si l'utilisateur appuie sur le bouton « Back ».

Pour cela, on surcharge OnBackKeyPress

 
Sélectionnez
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
base.OnBackKeyPress(e);
if(MonTexte.Text != string.Empty)
{
var result = MessageBox.Show("Vous étes sur le point de perdre votre saisie. Continuer?",
"Attention", MessageBoxButton.OKCancel);
if (result != MessageBoxResult.OK)
{
e.Cancel = true;
}
}
}

On remarque qu'on peut annuler l'effet de la touche « Back » par e.Cancel = true.

Quand on veut forcer un « back » par code, on peut tester avant si c'est possible :

 
Sélectionnez
private void BtnBack_Click(object sender, RoutedEventArgs e)
{
if (NavigationService.CanGoBack)
NavigationService.GoBack();
}

Enfin, on peut interdire l'action de la touche « Back ».

 
Sélectionnez
 this.goBackButton.IsEnabled = false;

VIII-H. Saisie tactile, gesture

Rappel des différents gestures (dessin de Microsoft) :

Image non disponible

Un événement Tap a lieu lorsqu'un doigt touche l'écran et le quitte avant 1,1 secondes sans se déplacer beaucoup. Si deux événements Tap se succèdent rapidement, le deuxième est traité comme un événement DoubleTap. Un événement Hold (tenir) a lieu lorsqu'un doigt appuie sur l'écran et reste au même endroit pendant environ 1,1 secondes. L'événement Hold est généré à la fin de cet intervalle de temps sans attendre que le doigt se soulève.
Note : l'émulateur ne supporte pas le multitouche.

VIII-H-1. Événements souris

On utilise habituellement les événements souris.

Un doigt qui touche un bouton déclenche un événement Click.
Soit un bouton en XAML :

 
Sélectionnez
<Button Click="Button_Click>Ok</Button>

Le Click exécute :

 
Sélectionnez
 private void Button_Click(object sender, RoutedEventArgs e)
        {

        }


Un doigt qui touche un objet visuel (UIElement) est converti en un évènement de souris ; événement MouseLeftButtonDown lorsque vous placez votre doigt, événement MouseLeftButtonUp lorsque vous levez votre doigt, MouseMove lorsque vous faites glisser votre doigt.
Il y a aussi MouseLeave (sortie de la zone) MouseEnter (entrée dans la zone).
Les arguments de ces événements sont : Sender l'objet d'où vient l'événement et e de type MouseButtonEventArgs.

Exemple, gestion de l'événement MouseLeftButtonUp sur un rectangle :

 
Sélectionnez
 <Rectangle Height="67" Name="rectangle1" Width="331" 
 Fill="Transparent"
 MouseLeftButtonUp="Rectangle_MouseLeftButtonUp"/>

Noter que pour que cela fonctionne, il faut remplir le rectangle ; ici on met une couleur transparente grâce à Fill.
La méthode suivante sera exécutée lors du « levé » du doigt sur le rectangle.

 
Sélectionnez
 private void Rectangle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {

        }

VIII-H-2. Événements de bas niveau

La classe System.Windows.Input.Touch fournit un service au niveau de l'application qui traite l'entrée tactile et déclenche l'événement FrameReported.
L'argument TouchFrameEventArgs de l'événement a la méthode GetPrimaryTouchPoint qui retourne le point tactile (TouchPoint) actuel par rapport à l'élément spécifié (null pour l'écran).
TouchPoint.Action obtient la dernière action qui s'est produite à cet emplacement. TouchPOint.TouchDevice obtient le périphérique tactile qui a généré ce TouchPoint.

Voici l'exemple d'un tap sur un TextBlock nommé « txBlock » :

 
Sélectionnez
 public partial class MainPage : PhoneApplicationPage
    {
        // Constructeur
        public MainPage()
        {
            InitializeComponent();
            // On utilise Touch.FrameReported l'événement de bas niveau
            Touch.FrameReported += OnTouchFrameReported;
        }

        void OnTouchFrameReported(object sender, TouchFrameEventArgs args)
        // Méthode exécutée lors d'un événement sur l'écran
        {
            TouchPoint MyTouchPoint = args.GetPrimaryTouchPoint(null);
            if (MyTouchPoint != null && MyTouchPoint.Action == TouchAction.Down)
            {
                if (MyTouchPoint.TouchDevice.DirectlyOver == txBlock)
                {
                    txBlock.Text = "Clicker";

                    txBlock.Foreground = new SolidColorBrush( Colors.Green); 

                }

            }

        }

    }

VIII-H-3. ɐvénements de haut niveau

Ces événements de haut niveau sont exécutés sur les objets dérivés de UIElement ; il y a les événements de gesture : Tap, DoubleTap, Hold.

Exemple avec Tap.

 
Sélectionnez
<Ellipse Height="109" Fill="red" Tap="buttonTap"  Name="ellipse1" Stroke="Black" StrokeThickness="1"  Width="326" />
 
Sélectionnez
 private void buttonTap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            Point p = e.GetPosition(null);// Coordonnées dans l'écran
            Point p1 = e.GetPosition(ellipse1);// Coordonnées relative à l'ellipse1
            MessageBox.Show(p.ToString());
        }

On peut utiliser l'appuie prolongé avec « Hold ».

 
Sélectionnez
 <Ellipse Height="109" Fill="red" Hold="ellipse2_Hold"  Name="ellipse2" Stroke="Black" StrokeThickness="1"  Width="326" Margin="58,409,72,89" />



On peut aussi utiliser les événements de manipulation :

ManipulationStarted
intervient quand la manipulation démarre.
ManipulationCompleted
intervient quand la manipulation s'arrête.
ManipulationDelta
intervient quand le doigt change de position et survient de multiples fois au cours de la manipulation.

Par exemple, pour effectuer une action si l'utilisateur pose le doigt sur un contrôle comme une ellipse.

 
Sélectionnez
 <Ellipse ManipulationStarted="Manip" Height="109" Fill="red"  Name="ellipse1"  />
 
Sélectionnez
 private void Manip(object sender, ManipulationStartedEventArgs e)
        {   
            Point p = e.ManipulationOrigin; // Coordonnées de la manipulation dans l'objet
            MessageBox.Show(p.ToString());
        }

Le second paramètre est de type ManipulationStartedEventArgs.

L'événement ManipulationDelta permet de « lire » les mouvements de « Translation » et de « Scale » (pas de rotation en WP).
Ici un glissé horizontal du doigt permet d'élargir ou de réduire l'ellipse.

 
Sélectionnez
<Ellipse  Height="109" Fill="red" ManipulationDelta="ManipDelta"  Name="ellipse1" Stroke="Black" StrokeThickness="1"  Width="326" />

Pour une événement ManipulationDelta le second paramètre est de type ManipulationDeltaEventArgs.
La propriété DeltaManipulation contient les modifications qui se sont produites depuis le précédent événement ManipulationDelta.

 
Sélectionnez
 private void ManipDelta(object sender, ManipulationDeltaEventArgs e)
        {
            Point p = e.DeltaManipulation.Translation;
            ellipse1.Width = ellipse1.Width  + p.X;
        }

Dans le code C# on peut surcharger la méthode OnManipulationStarted (et les autres événements de manipulation) de la page :
Si l'utilisateur pose le doigt sur l'écran.

 
Sélectionnez
// Dans le code de la page
protected override void OnManipulationStarted(ManipulationStartedEventArgs args)
{
// Code a effectuer quand l'utilisateur tape sur l'écran.
args.Complete();
base.OnManipulationStarted(args);
}

VIII-H-4. Gestures du toolkit

Le Toolkit fournit des fonctionnalités très puissantes.
Il y a dans le Toolkit la classe GestuleService qui permet d'attacher un GestureListener à un élément.
Cela permet de gérer les Tap, DoubleTap, Hold, PinchStarted, PinchDelta, PinchCompleted, Flick, DragStarted, DragDelta, DragCompleted, GestureBegin, GestureCompleted.

Il faut installer le Toolkit, ajouter dans les références « Microsoft.Phone.Controls.Toolkit.dll ».

Dans le code XAML, dans la balise d'ouverture de la page, il faut taper :

 
Sélectionnez
 xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"

Maintenant on peut utiliser les gestures du toolkit : on retrouve Tap DoubleTap et Hold.
Exemple simple avec Tap ; on va appliquer un GestureService.GestureListener à la grille principale « ContentPanel » et on va « écouter » l'événement Tap.

 
Sélectionnez
<!--ContentPanel - placez tout contenu supplémentaire ici-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    
            <toolkit:GestureService.GestureListener>
            <toolkit:GestureListener 
              Tap="OnGestureListenerTap"/>
             </toolkit:GestureService.GestureListener>

            <Ellipse  Height="109" Fill="red"   Name="ellipse1" Stroke="Black" StrokeThickness="1"  Width="326" />
            <Button  Content="Button" Height="86" HorizontalAlignment="Left" Name="button1" Width="280" Click="button1_Click" />

            <Ellipse Height="109"  Fill="red"   Name="ellipse2"  Width="326" Margin="58,409,72,89" />

        </Grid>
 
Sélectionnez
 private void OnGestureListenerTap(object sender, System.Windows.Input.GestureEventArgs e)
        {
  Point p = e.GetPosition(ellipse2);
  MessageBox.Show(p.X.ToString() + "  " + p.Y.ToString());
        }

Un Tap exécute OnGestureService qui ici ouvre une simple MessageBox.
Noter que le Tap fonctionne sur les ellipses et le bouton, pas sur le fond autour.
GetPosition retourne un Point ici par rapport à ellipse2 (qui a été donné en argument), l'origine étant le coin supérieur gauche d'un rectangle contenant l'ellipse. Pour que Tap soit actif même sur le fond, il faut un Background sur la grille.

 
Sélectionnez
 <!--ContentPanel - placez tout contenu supplémentaire ici-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" Background="Transparent">

On peut écrire cela en C# :
Ici on a un rectangle, quand on clique dessus, il devient blanc.

 
Sélectionnez
        Rectangle rectg;
       
        public MainPage()
        {
            InitializeComponent();
            this.rectg = new Rectangle();
            rectg.Height = 100;
            rectg.Width = 100;
            rectg.Fill = new SolidColorBrush(Colors.Cyan);
            this.ContentPanel.Children.Add(rectg);
            GestureListener gl = GestureService.GetGestureListener(rectg);
            gl.Tap += new EventHandler<Microsoft.Phone.Controls.GestureEventArgs>(GestureListener_Tap);
        }
        private void GestureListener_Tap(object sender, Microsoft.Phone.Controls.GestureEventArgs e)
        {
            this.rectg.Fill = new SolidColorBrush(Colors.White);
        }

Passons rapidement sur GestureBegin et GestureCompleted qui permettent de voir l'objet qui a déclenché la gesture (OriginalSource) et les coordonnés (GetPosition).

 
Sélectionnez
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" Background="Transparent">
<toolkit:GestureService.GestureListener>
    <toolkit:GestureListener 
      GestureBegin="OnGestureBegin"/>
    </toolkit:GestureService.GestureListener>

            <Ellipse  Height="109" Fill="red"   Name="ellipse1" Stroke="Black" StrokeThickness="1"  Width="326" />
</Grid>
 
Sélectionnez
 private void OnGestureBegin(object sender, Microsoft.Phone.Controls.GestureEventArgs e)
        {
            Object  o = e.OriginalSource;
            Point p = e.GetPosition(ellipse1);
            MessageBox.Show("Taptc");
        }

Une séquence Drag (traîner) est constituée d'un événement DragStarted, de zéro ou plusieurs événements DragDelta et d'un événement DragCompleted (lorsqu'un doigt touche l'écran, se déplace, puis quitte l'écran).

DragStarted permet, outre l'objet et les coordonnées, de voir la direction de départ (retourne une « Orientation » qui est une enum ayant deux valeurs : Horizontal et Vertical).

 
Sélectionnez
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" Background="Transparent">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener 
      DragStarted="OnGestureDrag"/>
     
</toolkit:GestureService.GestureListener>
 
Sélectionnez
private void OnGestureDrag(object sender, Microsoft.Phone.Controls.DragStartedGestureEventArgs e)
        {
            Object  o =e.OriginalSource;
             Point p = e.GetPosition(rectg);
           Orientation orient =e.Direction;
            MessageBox.Show (orient.ToString()); // Horizontal ou Vertical
        }

DragDelta, outre les informations précédentes, permet de voir le déplacement horizontal et vertical (positif si le déplacement se fait à droite et en bas).

 
Sélectionnez
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" Background="Transparent">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener 
      DragDelta="OnGestureDragDelta"/>
     
</toolkit:GestureService.GestureListener>
 
Sélectionnez
private void OnGestureDragDelta(object sender, Microsoft.Phone.Controls.DragDeltaGestureEventArgs e)
        {
            Object  o =e.OriginalSource;
            Point p = e.GetPosition(rectg);
           Orientation or =e.Direction;
            MessageBox.Show (or.ToString()); //Horizontal ou Vertical
            
            double x = e.HorizontalChange;
            double y = e.VerticalChange;
            MessageBox.Show(x.ToString() + " " + y.ToString());
        }

DragCompleted présente les mêmes informations (sur quel objet on lâche) mais avec en plus HorizontalVelocity et VerticalVelocity.

L'événement Flick a lieu lorsqu'un doigt quitte l'écran alors qu'il se déplace encore, ce qui suggère que l'utilisateur souhaite obtenir une inertie ; je le fais lorsque j'enlève vers le haut l'écran de démarrage. Les arguments comprennent une valeur Angle (de 0 à 360 °, mesuré dans le sens des aiguilles d'une montre à partir de l'axe des X positifs horizontal à droite), ainsi que des valeurs HorizontalVelocity et VerticalVelocity (mesurées en pixels par seconde).
On va l'appliquer à une ellipse.

 
Sélectionnez
<Ellipse  Height="109" Fill="red"   Name="ellipse1" Stroke="Black" StrokeThickness="1"  Width="326">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener 
      Flick="OnFlick"/>

</toolkit:GestureService.GestureListener>
</Ellipse>
 
Sélectionnez
private void OnFlick(object sender, FlickGestureEventArgs e)
        {
            double x = e.HorizontalVelocity;
            double y = e.VerticalVelocity;
            double a = e.Angle;

            MessageBox.Show(x.ToString() + " " + y.ToString() + " " + a.ToString());

        }

La séquence Pinch (pincement) a lieu lorsque deux doigts touchent l'écran ; elle est généralement interprétée pour développer ou réduire un objet. Pinch correspond aux deux doigts qui s'écartent ou se rapprochent.
La position actuelle d'un doigt (le doigt principal) est toujours disponible avec la méthode GetPosition.

Il y a PinchStarted.

 
Sélectionnez
<Ellipse  Height="109" Fill="red"   Name="ellipse1" Stroke="Black" StrokeThickness="1"  Width="326">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener 
      PinchStarted="PinchS"/>

</toolkit:GestureService.GestureListener>
</Ellipse>
 
Sélectionnez
 private void PinchS(object sender, PinchStartedGestureEventArgs e)
        {
            double a = e.Angle;
            double d = e.Distance;
           
        }

Il y a aussi PinchDelta.

 
Sélectionnez
<Ellipse  Height="109" Fill="red"   Name="ellipse1" Stroke="Black" StrokeThickness="1"  Width="326">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener 
      PinchDelta="PinchD"/>

</toolkit:GestureService.GestureListener>
</Ellipse>


On peut voir le « DistanceRatio » rapport de la distance actuelle entre les deux doigts et la distance de départ. Il y a aussi le « TotalAngleDelta » différence de l'angle actuel entre les deux doigts et l'angle de départ.

 
Sélectionnez
private void PinchD(object sender, PinchGestureEventArgs e)
        {
            double ratio = e.DistanceRatio;
            double a = e.TotalAngleDelta;
        }


Il existe aussi PinchCompleted qui n'apporte rien de plus.

VIII-I. Perdre du temps

Parfois on a besoin de perdre du temps, suspendre l'exécution durant 1/2 s par exemple.
Il faut inclure l'espace de nom System.Threading puis utiliser la méthode Sleep du Thread (avec en paramètre 500 ms).

 
Sélectionnez
using System.Threading;

            Thread.Sleep(500);

VIII-J. Sortir de l'application

Logiquement, le fait d'utiliser le bouton « Back » quand on est sur la première page de l'application permet de sortir de l'application.
Si on quitte l'application avec le bouton central, elle se met à l'état dormant et se fermera automatiquement si on s'y revient pas.
Il n'y a donc pas besoin de méthode pour quitter l'application.

Si on veut vraiment, Application.Exit() n'existant pas, il faut déclencher une exception non gérée ! Ce n'est pas élégant !

 
Sélectionnez
 private void Exit(object sender, RoutedEventArgs e)
        {
            throw new Exception("Exit");
        }

VIII-K. Application démonstration ou payée

On peut distribuer une application gratuite en démonstration ; elle pourra ensuite être achetée et ainsi donner accès à des niveaux ou fonctions supplémentaires.
La Méthode IsTrial de LicenceInformation indique si on est en mode démo.

 
Sélectionnez
//Ajouter en haut
using Microsoft.Phone.Marketplace;

//instancier une licenceinformation
LicenseInformation licInfo = new LicenseInformation();

//Tester si on est en version démo ou payée
if (!licInfo.IsTrial())
{
    //Faire seulement pour les users ayant payé.
}
else
{
    //Faire pour tous.
}

Code non testé.

VIII-L. Mes trucs

Sans prétention !

Attention au nom de l'application !

Si je crée une application se nommant « calcul » puis une variable « calcul » et si je me fais aider pour l'écriture (IntelliSense), je peux avoir des confusions entre espace de noms « calcul » et variable « calcul » :

Image non disponible

De même si le nom de l'application a le nom d'une classe.

L'enfer des accolades.

Dans le code C#, quand on a plusieurs classes dans un espace de noms ou si on a des if imbriqués, il y a plein d'accolades ouvrantes et fermantes.
C'est l'horreur pour savoir où ajouter une fonction ou une classe ou un else ; si on se trompe et qu'on met une fonction une accolade trop haut, les messages d'erreur ne sont pas toujours clairs.
Le plus simple pour s'y retrouver est de cliquer sur une accolade ouvrante cela surligne l'accolade fermante correspondante.

Image non disponible

Groupe de contrôles 

Avant l'univers .NET, en VB6 par exemple, on pouvait créer des groupe de contrôles, les contrôles d'un groupe avaient les mêmes fonctions évènements et pour un clic sur différents boutons on exécutait la même fonction.
Pour simuler les « groupes de contrôles » qui n'existent pas en WP on a un moyen simple : en XAML, pour que plusieurs boutons exécutent la même fonction, on peut indiquer Click="MyButtonClick" pour plusieurs boutons.

 
Sélectionnez
<Button Name="Button1" Click="MyButtonClick">
<Button Name="Button2" Click="MyButtonClick">

Ensuite dans la fonction MyButtonClick il suffit de regarder le « sender » pour voir quel bouton a été cliqué (il faut le caster en bouton avant de tester son nom).

On peut aussi utiliser un StackPanel « parent » pour gérer l'évènement Click de tous les boutons enfants dans le StackPanel (comme il n'y a pas de « Click= » dans les boutons, l'évènement Click remonte dans le StackPanel) :

 
Sélectionnez
  <StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="ClickHandlerCommun">
    <Button Name="ButtonOui" Width="Auto" >Oui</Button>
    <Button Name="ButtonNon" Width="Auto" >Non</Button>
  </StackPanel>

IX. Compilation, test, distribution

IX-A. Compilation

La compilation c'est transformer un code source (le code XAML et le code C# que vous avez tapé), en code exécutable et distribuable.

En haut on peut choisir Windows Phone Emulator ou Windows Phone Device pour lancer l'application sur l'émulateur ou le portable connecté (si on est enregistré) :

Image non disponible

Puis on peut choisir Debug (permettant le débogage) ou Release (pour la distribution).


Si on clique sur le bouton d'exécution (ou F5) on lance le débogage.

Par le menu « Build » puis « Générer la solution » ou F6, on compile l'application.

Cela crée un répertoire « Bin » avec un sous répertoire « Debug » ou « Release » contenant un fichier .xap (archive compressée contenant l'exécutable, les DLL, les ressources, images…).
Le fichier .xap est en fait un fichier .zip (vous pouvez renommer ce fichier en .zip et ensuite aller voir ce qu'il y a dedans).

Pour tester le .xap passer par le menu « Build» puis « Déployer » ; il s'exécutera dans l'émulateur.

On se souvient où se trouvent les sources des applications.
Pour mon application qui se nomme « CalculTout » voir dans 'C:\Users\Philippe\Documents\Visual Studio 2010\Projects\CalculTout'.
Il y a les fichiers « CalculTout.sln » et « CalculTout.suo ».

Image non disponible

Il y a dessous un répertoire nommé aussi « CalculTout » qui contient les fichiers « .xaml » et « .xaml.cs » et les répertoires « Bin » et « Obj » qui contiennent chacun les répertoires « Debug » et « Release ».

Quand on compile il y a création des fichiers « .g.cs » et « .g.i.cs » en C# pour chaque page XAML. On n'a théoriquement pas besoin de s'en occuper sauf quand il y a un bogue dans le code XAML et que VS s'arrête sur une instruction de ces fichiers ; lire l'erreur donne une indication sur la correction nécessaire dans le code XAML.

IX-B. Test sur un Windows Phone

Il est possible de voir tourner votre application dans l'émulateur.
Impossible de charger simplement sur votre Windows Phone une application que vous venez de développer.
Impossible donc de tester une application sur votre portable ou de faire une application uniquement pour les membres de votre entreprise.
La solution : enregistrez-vous comme développeur chez Microsoft (99 $) et là vous aurez la possibilité de charger sur votre portable une application pour la tester.

Pour déboguer, il faut choisir l'émulateur en haut au milieu :

Image non disponible


Si on clique sur le bouton d'exécution (ou F5) on compile l'application, on charge l'émulateur WP7 et on exécute l'application dans l'émulateur.

Image non disponible

La souris permet de simuler le doigt sur l'écran.


À sa gauche il y a une barre d'outils qui apparaît quand le curseur de la souris s'approche.
Les boutons de haut en bas :

  • fermer l'émulateur ;
  • réduire l'émulateur ;
  • faire pivoter l'émulateur pour passer en mode paysage ;
  • faire pivoter mais dans l'autre sens.
  • ajuster l'émulateur à la taille de l'écran ;
  • définir le zoom de l'émulateur ;
  • autres.
  • accéléromètre ;
  • localisation ;
  • copie d'écran.

Sur la droite de l'écran, il y a des compteurs :

Image non disponible


En détails :

Image non disponible

De haut en bas ils indiquent

- Thread de composition (Render Thread).
3 chiffres. En nombre de frames par seconde (maximum : 120)
Bonne valeur = 60.
Mauvaise valeur si inférieur à 30 (devient rouge).

- Thread UI (User Interface Thread).
3 chiffres. En nombre de frames par seconde (si la valeur est faible, la réaction de l'UI est moins bonne).
Bonne valeur si supérieur à 15.
Devient rouge si inférieur à 15.

- Textures (mémoire utilisée par les textures)
6 chiffres.

- Compteur de surfaces
Nombre de surfaces passées au chip graphique.

- Compteur IRT (Intermediate Texture Count).

- Screen Fill rate (nombre d'écrans dessinés par frame).
Un écran représente 480 x 800 pixels.
si> 3 mauvaises performances.
si inférieur à 2, bonnes performances.


Dans le constructeur de la classe App de votre application (App.xaml.cs), vous pouvez faire disparaître ces compteurs.

 
Sélectionnez
Application.Current.Host.Settings.EnableFrameRateCounter = false;

C'est bien pour faire des copies d'écran.

Un profiler dédié au projet WP7 a été ajouté, il n'est pas à l'heure actuelle dans sa version définitive, mais il permet de pouvoir cibler certains problèmes de frame rate et d'utilisation de thread sur la CPU/GPU.
Passez par le menu « déboguer » puis « Démarrer l'analyse des performances de Windows Phone ».

IX-C. La distribution

Il faut préparer des images.

Trois images pour le MarketPlace :
Large Mobile App Tile : 173*173 px 96 DPI, fichier .PNG ;

Small Mobile App Tile : 99*99 px 96 DPI, fichier .PNG ;

Large PC App Tile : 200*200 px 96 DPI, fichier .PNG.


Une (minimum) à huit captures d'écran (Screenshots) 480*800 px 96 DPI, fichier .PNG ;

Une image en option (Background art) utilisée si l'application devient l'application du jour 1000*800 px 96 DPI, fichier .PNG.


On peut charger à partir du site CodePlex un logiciel gratuit (http://wpiconmaker.codeplex.com/) permettant, très simplement, de créer les icônes à partir d'une image.

On se souvient que dans l'application il y a les 2 icônes :
Background.png, 173×173 px (utilisé sur l'écran de démarrage).
ApplicationIcon.png, 62x62 px (utilisée dans la liste des applications installées).

La distribution se fait uniquement par le Marquet Place.

Merci à Tomlev pour sa relecture ses corrections et ses conseils sur une partie de ce document, il m'a été d'un grand secours.
Merci à jacques jean pour sa relecture orthographique d'une grosse partie du document. Merci aux autres.
A suivre…
Philippe LASSERRE.


précédentsommaire

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2011 Lasserre Philippe. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.