VI. Les différents contrôles▲
- Contrôles disponibles.
Border
Button
Canvas
CheckBox
ContentControl
ContentPresenter
Control
Grid
HyperlinkButton
Image
InkPresenter
ListBox
MediaElement
MultiScaleImage
Panel
PasswordBox
ProgressBar
RadioButton
ScrollViewer
Slider
StackPanel
TextBlock
TextBox
Viewbox
UserControl
Tous les contrôles ne sont pas disponibles dans la boîte à outils.
On peut si on le désire ajouter un contrôle dans la boîte à outils. Dans celle-ci, clic droit sur « Windows Phone Controls », puis dans le menu « Choisir les éléments » et cocher un contrôle à ajouter dans la liste de la boîte à outils.
- Contrôles Silverlight différents dans Windows Phone.
ScroolBarr
ToolsTip
ComboBox
RichTextBox
- Ne sont pas disponibles dans Windows Phone.
System.Windows.Controls.OpenFileDialog
System.Windows.Controls.SaveFileDialog
- Ne sont pas disponibles les contrôles qui sont dans le Silverlight SDK.
Calendar
ChildWindow
DataGrid
DatePicker
Frame
GridSplitter
Label
Page
TabControl
TreeView
On peut ajouter le ToolKit Silverlight for Windows Phone Toolkit pour Mango 7.1 :http://silverlight.codeplex.com/.
- Cela ajoute :
AutoCompleteBox
ContextMenu
DatePicker
GestureService/GestureListener
ListPicker
LongListSelector
Page Transitions
PerformanceProgressBar
TiltEffect
TimePicker
ToggleSwitch
WrapPanel
Il faut les ajouter à la boîte à outils. Voir le chapitre sur le Toolkit.
VI-A. Page▲
Une application très simple peut se composer d'une page principale (nommée « MainPage » par défaut).
C'est le cas quand on crée une application en choisissant « Application Windows Phone » :
Ensuite on peut créer d'autres pages (menu « Projet » puis « Ajouter un nouvel élément »).
Dans la page principale on peut ouvrir une autre page à l'aide du code suivant :
NavigationService.
Navigate
(
new
Uri
(
"/PageSecondaire.xaml"
,
UriKind.
Relative));
Quand on crée une page :
Elle est dans la Frame de l'application.
Cette Page contient une grille principale (nommée LayoutRoot).
Elle contient un StackPanel (nommé TitlePanel) comprenant le titre de l'application et le titre de la page.
Dessous il y une grille nommée ContentPanel dans laquelle il faudra mettre le contenu de la Page.
<
phone
:
PhoneApplicationPage
x
:
Class
=
"MyProjet.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"
>
<!--LayoutRoot est la grille racine où tout le contenu de la page est placé-->
<Grid
x
:
Name
=
"LayoutRoot"
Background
=
"Transparent"
>
<Grid.RowDefinitions>
<RowDefinition
Height
=
"Auto"
/>
<RowDefinition
Height
=
"*"
/>
</Grid.RowDefinitions>
<!--TitlePanel contient le nom de l'application et le titre de la page-->
<StackPanel
x
:
Name
=
"TitlePanel"
Grid.
Row
=
"0"
Margin
=
"12,17,0,28"
>
<TextBlock
x
:
Name
=
"ApplicationTitle"
Text
=
"MON APPLICATION"
Style
=
"{StaticResource PhoneTextNormalStyle}"
/>
<TextBlock
x
:
Name
=
"PageTitle"
Text
=
"nom de la page"
Margin
=
"9,-7,0,0"
Style
=
"{StaticResource PhoneTextTitle1Style}"
/>
</StackPanel>
<!--ContentPanel - placez tout contenu supplémentaire ici-->
<Grid
x
:
Name
=
"ContentPanel"
Grid.
Row
=
"1"
Margin
=
"12,0,12,0"
>
</Grid>
</Grid>
<!--Exemple de code illustrant l'utilisation d'ApplicationBar-->
<!--<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Bouton 1"/>
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Bouton 2"/>
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem Text="ÉlémentMenu 1"/>
<shell:ApplicationBarMenuItem Text="ÉlémentMenu 2"/>
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>-->
</
phone
:
PhoneApplicationPage>
Une page fait 800 * 480 px. Le SystemTray en haut fait 32 px
(il peut y avoir des écrans de 480 * 320).
Si on regarde le code C#, on constate que l'espace de noms est celui du projet (comme pour le code XAML) ; il y a une classe partielle « MainPage » (la classe MainPage est donc composée du code XAML et de la classe partielle en C#).
using
System.
Windows.
Shapes;
using
Microsoft.
Phone.
Controls;
namespace
MyProjet
{
public
partial
class
MainPage :
PhoneApplicationPage
{
// Constructeur
public
MainPage
(
)
{
InitializeComponent
(
);
}
}
}
Cette class MainPage hérite de la classe PhoneApplicationPage qui est la page standard.
Dans cette classe MainPage, il y a une fonction « public MainPage() » qui est le constructeur de la page ; on y initialise les composants de la page ; on peut y ajouter du code qui sera exécuté lors de la création de la page.
Dans une page, on peut utiliser des évènements ; Loaded, par exemple.
Dans ce cas il faut ajouter « Loaded=… »
<
phone
:
PhoneApplicationPage
x
:
Class
=
"CalculeTout.Inflation"
xmlns
=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation"
...
Loaded
=
"PhoneApplicationPage_Loaded"
>
Quand la page est chargée, la routine suivante, dans le code C#, est exécutée :
private
void
PhoneApplicationPage_Loaded
(
object
sender,
RoutedEventArgs e)
{
}
On verra qu'il est plus judicieux, pour mettre du code quand la page est chargée, d'utiliser une surcharge de OnNavigatedTo :
protected
override
void
OnNavigatedTo
(
System.
Windows.
Navigation.
NavigationEventArgs e)
{
}
Il y a deux autres manières de structurer une application Windows Phone :
En utilisant le Pivot ou le Panorama.
VI-B. Pivot et Panorama▲
Utilisons une page « Pivot ».
C'est le cas quand on crée une application en choisissant « Application Pivot Windows Phone » :
Voici un exemple de pages pivots :
Une application « Pivot » contient plusieurs pages, on passe de l'une à l'autre en glissant horizontalement ou en tapant sur le nom grisé en haut de la page désirée.
Dans le code XAML on voit que le contrôle « Pivot » contient des PivotItem ayant un titre (Header).
<
controls
:
Pivot
Title
=
"MON APPLICATION"
>
<
controls
:
PivotItem
Header
=
"premier"
>
</
controls
:
PivotItem>
<
controls
:
PivotItem
Header
=
"second"
>
</
controls
:
PivotItem>
</
controls
:
Pivot>
Code complet avec dans chaque PivotItem une ListBox :
<!--LayoutRoot est la grille racine où tout le contenu de la page est placé-->
<Grid
x
:
Name
=
"LayoutRoot"
Background
=
"Transparent"
>
<!--Contrôle Pivot-->
<
controls
:
Pivot
Title
=
"MON APPLICATION"
>
<!--Élément un de tableau croisé dynamique-->
<
controls
:
PivotItem
Header
=
"premier"
>
<!--Liste double trait avec habillage du texte-->
<ListBox
x
:
Name
=
"FirstListBox"
Margin
=
"0,0,-12,0"
ItemsSource
=
"{Binding Items}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel
Margin
=
"0,0,0,17"
Width
=
"432"
>
<TextBlock
Text
=
"{Binding LineOne}"
TextWrapping
=
"Wrap"
Style
=
"{StaticResource PhoneTextExtraLargeStyle}"
/>
<TextBlock
Text
=
"{Binding LineTwo}"
TextWrapping
=
"Wrap"
Margin
=
"12,-6,12,0"
Style
=
"{StaticResource PhoneTextSubtleStyle}"
/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</
controls
:
PivotItem>
<!--Élément deux de tableau croisé dynamique-->
<
controls
:
PivotItem
Header
=
"second"
>
<!--Liste triple trait, aucun habillage du texte-->
<ListBox
x
:
Name
=
"SecondListBox"
Margin
=
"0,0,-12,0"
ItemsSource
=
"{Binding Items}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel
Margin
=
"0,0,0,17"
>
<TextBlock
Text
=
"{Binding LineOne}"
TextWrapping
=
"NoWrap"
Margin
=
"12,0,0,0"
Style
=
"{StaticResource PhoneTextExtraLargeStyle}"
/>
<TextBlock
Text
=
"{Binding LineThree}"
TextWrapping
=
"NoWrap"
Margin
=
"12,-6,0,0"
Style
=
"{StaticResource PhoneTextSubtleStyle}"
/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</
controls
:
PivotItem>
</
controls
:
Pivot>
</Grid>
Utilisons maintenant un « Panorama ».
C'est le cas quand on crée une application en choisissant « Application Panorama Windows Phone ».
Voici une page panorama :
Une application « Panorama » contient une page unique très large, on se déplace en glissant horizontalement. Le titre est large et s'étale sur toute la grande page. Le début du contenu de la page suivante de droite est légèrement visible.
Le contrôle Panorama contient des PanoramaItem ayant un titre (Header). Mis côte à côte les PanoramaItem forment la grande page virtuelle.
<
controls
:
Panorama
Title
=
"mon application"
>
<
controls
:
PanoramaItem
Header
=
"premier élément"
>
</
controls
:
PanoramaItem>
<
controls
:
PanoramaItem
Header
=
"second élément"
>
</
controls
:
PanoramaItem>
</
controls
:
Panorama>
Code complet avec dans chaque PanoramaItem une ListBox :
<!--Contrôle Panorama-->
<
controls
:
Panorama
Title
=
"mon application"
>
<
controls
:
Panorama.Background>
<ImageBrush
ImageSource
=
"PanoramaBackground.png"
/>
</
controls
:
Panorama.Background>
<!--Élément un de panorama-->
<
controls
:
PanoramaItem
Header
=
"premier élément"
>
<!--Liste double trait avec habillage du texte-->
<ListBox
Margin
=
"0,0,-12,0"
ItemsSource
=
"{Binding Items}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel
Margin
=
"0,0,0,17"
Width
=
"432"
>
<TextBlock
Text
=
"{Binding LineOne}"
TextWrapping
=
"Wrap"
Style
=
"{StaticResource PhoneTextExtraLargeStyle}"
/>
<TextBlock
Text
=
"{Binding LineTwo}"
TextWrapping
=
"Wrap"
Margin
=
"12,-6,12,0"
Style
=
"{StaticResource PhoneTextSubtleStyle}"
/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</
controls
:
PanoramaItem>
<!--Élément deux de panorama-->
<!--Utilisez 'Orientation="Horizontal"' pour activer un panneau qui s'affiche horizontalement-->
<
controls
:
PanoramaItem
Header
=
"second élément"
>
<!--Liste double trait avec espace réservé pour une image et habillage du texte-->
<ListBox
Margin
=
"0,0,-12,0"
ItemsSource
=
"{Binding Items}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel
Orientation
=
"Horizontal"
Margin
=
"0,0,0,17"
>
<!--Remplacer le rectangle par l'image-->
<Rectangle
Height
=
"100"
Width
=
"100"
Fill
=
"#FFE5001b"
Margin
=
"12,0,9,0"
/>
<StackPanel
Width
=
"311"
>
<TextBlock
Text
=
"{Binding LineOne}"
TextWrapping
=
"Wrap"
Style
=
"{StaticResource PhoneTextExtraLargeStyle}"
/>
<TextBlock
Text
=
"{Binding LineTwo}"
TextWrapping
=
"Wrap"
Margin
=
"12,-6,12,0"
Style
=
"{StaticResource PhoneTextSubtleStyle}"
/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</
controls
:
PanoramaItem>
</
controls
:
Panorama>
VI-C. Les Conteneurs▲
Les conteneurs peuvent contenir plusieurs contrôles et permettent de les positionner.
VI-C-1. Les Grid▲
En Silverlight une Grid est un conteneur, comprenant des cellules servant à aligner les contrôles (et pas une grille de données comme dans les Windows forms).
Aller chercher une Grid dans la boîte à outils à gauche et la mettre sur la page.
<
Grid Height=
"520"
HorizontalAlignment=
"Left"
Margin=
"81,51,0,0"
Name=
"grid1"
VerticalAlignment=
"Top"
Width=
"335"
>
</
Grid>
On a une grille mais avec une seule cellule.
En fait quand on ajoute une page vide à un projet, la fenêtre contient déjà une Grid.
Comportement d'une Grid a une seule cellule.
Ce n'est pas recommandé mais ajoutons deux TextBlock, une image et une ellipse dans la cellule unique :
<
Grid x:
Name=
"ContentPanel"
Grid.
Row=
"1"
Margin=
"12,0,12,0"
>
<
TextBlock Text=
"TextBlock aligné à droite et en haut"
HorizontalAlignment=
"Right"
VerticalAlignment=
"Bottom"
/>
<
TextBlock Text=
"TextBlock aligné à gauche et en bas"
HorizontalAlignment=
"Left"
VerticalAlignment=
"Top"
/>
<
Image Source=
"c:
\v
shaghet.jpg"
/>
<
Ellipse Stroke=
"{StaticResource PhoneAccentBrush}"
StrokeThickness=
"24"
/>
Cela donne :
On se rend compte que les éléments comme l'image et l'ellipse sont centrés et occupent le maximum de place.
Les TextBox sont placés en fonction de leur alignement.
Enfin on remarque que les éléments se superposent : l'ellipse qui est dans la dernière ligne du code XAML est au dessus.
Pour ajouter des lignes et des colonnes dans la grille (dans le designer), il faut cliquer dans les barres grises horizontales ou verticales de la grille et positionner les traits à la souris.
Cela génère le code XAML suivant :
<
Grid Height=
"520"
HorizontalAlignment=
"Left"
Margin=
"81,51,0,0"
Name=
"grid1"
VerticalAlignment=
"Top"
Width=
"335"
>
<
Grid.
RowDefinitions>
<
RowDefinition Height=
"265*"
/>
<
RowDefinition Height=
"255*"
/>
</
Grid.
RowDefinitions>
<
Grid.
ColumnDefinitions>
<
ColumnDefinition Width=
"190*"
/>
<
ColumnDefinition Width=
"145*"
/>
</
Grid.
ColumnDefinitions>
</
Grid>
On voit dans le code XAML les largeurs des colonnes (Grid.ColumnDefinition) et les hauteurs des lignes (Grid.RowDefinition).
On peut aussi vouloir définir le nombre de lignes et de colonnes sans définir leurs largeurs et hauteurs : simplement mettre trois lignes, deux colonnes.
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
Dans la définition des dimensions des lignes et colonnes : on peut, comme on l'a vu, donner dans le designer la taille que l'on veut aux cellules.
Mais on peut, dans le code XAML, donner les dimensions des cellules :
- un chiffre ("150", par exemple) indique la largeur ou hauteur en pixels ;
- '*' signifie autant que possible' (cette ligne reçoit une proportion pondérée de l'espace disponible , 2* indiquant deux fois la proportion) ;
- 'Auto' force à prendre la taille des éléments qu'elle contient.
Exemple de colonnes avec Auto :
<ColumnDefinition
Width
=
"Auto"
/>
<ColumnDefinition
Width
=
"Auto"
/>
<ColumnDefinition
Width
=
"Auto"
/>
Exemple de lignes avec des étoiles :
<RowDefinition
Height
=
"*"
/>
<RowDefinition
Height
=
"*"
/>
<RowDefinition
Height
=
"2*"
/>
Si on fait :
<
Grid.
RowDefinitions>
<
RowDefinition Height=
"*"
/>
<
RowDefinition Height=
"*"
/>
<
RowDefinition Height=
"*"
/>
</
Grid.
RowDefinitions>
<
Grid.
ColumnDefinitions>
<
ColumnDefinition Width=
"*"
/>
<
ColumnDefinition Width=
"*"
/>
<
ColumnDefinition Width=
"*"
/>
</
Grid.
ColumnDefinitions>
On aura trois lignes d'égale hauteur et trois colonnes d'égale largeur. Cela donne neuf cellules carrées.
On peut rendre les lignes de séparation visibles :
ShowGridLines="True"
On peut ensuite ajouter des contrôles dans les cellules de la grille pour les positionner.
Pour chaque contrôle ajouté dans une cellule de la Grid, on définira la cellule où le contrôle se trouve, ses marges et son ancrage si nécessaire.
Ici on va ajouter une ListBox en bas à droite de la grille, voyons ce que cela donne dans le code XAML.
<Grid
Height
=
"279"
Name
=
"Grid1"
>
<Grid.RowDefinitions>
<RowDefinition
Height
=
"74*"
/>
<RowDefinition
Height
=
"84*"
/>
<RowDefinition
Height
=
"121*"
/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition
Width
=
"37*"
/>
<ColumnDefinition
Width
=
"28*"
/>
<ColumnDefinition
Width
=
"31*"
/>
<ColumnDefinition
Width
=
"176*"
/>
</Grid.ColumnDefinitions>
<ListBox Grid.
Column
=
"3"
Grid.
Row
=
"2"
Name
=
"ListBox1"
>
<ListBoxItem>
toto</ListBoxItem>
<ListBoxItem>
lululu</ListBoxItem>
</ListBox>
</Grid>
ListBox Grid.Column="3" Grid.Row="2" indiquent dans quelle cellule est la ListBox.
Attention la première colonne est Column=0 et la première ligne est Row=0.
On aurait pu ajouter Grid.ColumnSpan=2 pour indiquer que la ListBox occupe deux colonnes (la 3 et la 4 dans ce cas).
Il existe aussi Grid.RowSpan pour étendre le contrôle sur plusieurs lignes de la Grid.
On aurait pu ajouter :
Margin="22,26,21,19" pour indiquer les distances au conteneur autour de la ListBox.
Comment faire la même chose en C# ?
La Grid1 étant présente, ajoutons une ListBox comme ci dessus :
ListBox lb =
new
ListBox
(
);
lb.
Margin =
new
Thickness
(
22
,
26
,
11
,
19
);
Grid.
SetColumn
(
lb,
3
);
Grid.
SetRow
(
lb,
2
);
grid1.
Children.
Add
(
lb);
VI-C-2. Les StackPanel▲
Arrange, empile les contrôles sur une même ligne qui peut être horizontale ou verticale (on parle d'empilement).
En C# :
StackPanel instance =
new
StackPanel
(
);
En XAML :
<StackPanel>
</StackPanel>
On a ajouté dans le StackPanel trois boutons.
En XAML :
<StackPanel
Height
=
"362"
HorizontalAlignment
=
"Left"
Margin
=
"29,51,0,0"
Name
=
"stackPanel1"
VerticalAlignment
=
"Top"
Width
=
"390"
>
<Button
Content
=
"Button"
Height
=
"85"
Name
=
"button1"
Width
=
"300"
/>
<Button
Content
=
"Button"
Height
=
"85"
Name
=
"button2"
Width
=
"300"
/>
<Button
Content
=
"Button"
Height
=
"85"
Name
=
"button3"
Width
=
"300"
/>
</StackPanel>
On voit qu'il suffit de mettre les objets dans le StackPanel, ils seront empilés.
La valeur par défaut de Orientation du StackPanel est Vertical, aussi les contrôles seront positionnés de haut en bas. L'attribut Orientation="Horizontal" permet de mettre les contrôles enfants de gauche à droite.
<
StackPanel Orientation=
"Horizontal"
Height=
"362"
HorizontalAlignment=
"Left"
Margin=
"29,51,0,0"
Name=
"stackPanel1"
VerticalAlignment=
"Top"
Width=
"390"
>
<
Button Content=
"Button"
Height=
"220"
Name=
"button1"
Width=
"100"
/>
<
Button Content=
"Button"
Height=
"220"
Name=
"button2"
Width=
"100"
/>
<
Button Content=
"Button"
Height=
"220"
Name=
"button3"
Width=
"100"
/>
</
StackPanel>
C'est bien pratique quand on veut mettre sur une même ligne, les différents champs d'un objet (nom, prénom, adresse) :
<StackPanel
Orientation
=
"Horizontal"
>
<TextBlock
Padding
=
"5,0,5,0"
<
Text
=
"{Binding FirstName}"
/>
<TextBlock
Text
=
"{Binding LastName}"
/>
<TextBlock
Text
=
", "
/>
<TextBlock
Text
=
"{Binding Address}"
/>
</StackPanel>
En C#, voici un autre exemple :
StackPanel StackPanel =
new
StackPanel
(
);
StackPanel.
Orientation =
System.
Windows.
Controls.
Orientation.
Vertical;
StackPanel.
HorizontalAlignment =
System.
Windows.
HorizontalAlignment.
Right;
StackPanel.
VerticalAlignment =
System.
Windows.
VerticalAlignment.
Center;
Button MyButton1 =
new
Button
(
);
Button MyButton2 =
new
Button
(
);
MyButton1.
Content =
"bouton1"
;
MyButton2.
Content =
"bouton2"
;
StackPanel.
Children.
Add
(
MyButton1);
StackPanel.
Children.
Add
(
MyButton2);
this
.
ContentPanel.
Children.
Add (
StackPanel);
On a instancié des boutons que l'on ajoute à la collection Children du StackPanel.
Enfin, on met donc le StackPanel dans une grille nommée ContentPanel.
On peut insérer un bouton3 supplémentaire à une position définie :
Button MyButton3 =
new
Button
(
);
MyButton3.
Content =
"bouton3"
;
StackPanel.
Children.
Insert
(
1
,
MyButton3);
//1 indique la position d'insertion.
Le bouton2 est automatiquement repositionné.
VI-C-3. Les Canvas▲
Il existe un contrôle Canvas qui permet de positionner des contrôles en indiquant leurs coordonnées (comme dans les Windows Forms), mais il n'y a pas de repositionnement automatique quand on modifie les dimensions du Canvas.
On positionne les contrôles avec les propriétés attachés Canvas.Top et Canvas.Left qui se trouvent dans le contrôle enfant.
En XAML :
<Canvas
Margin
=
"72,65,118,302"
>
<CheckBox Canvas.
Top
=
"80"
Canvas.
Left
=
"0"
>
Check Me</CheckBox>
<RadioButton Canvas.
Top
=
"0"
Canvas.
Left
=
"80"
>
Yes</RadioButton>
</Canvas>
Les Canvas ont une propriété attachée ZIndex permettant d'imposer l'ordre de superposition des éléments enfants (syntaxe dans l'élément enfant : Canvas.ZIndex = "2").
VI-C-4. Les ScrollViewer▲
Représente une zone défilante qui peut contenir d'autres éléments visibles bien plus grands ; on fait défiler le contenu qui est dans le ScrollViewer au doigt, il apparaît des ScrollBarr si nécessaire.
Une utilisation habituelle est de mettre dans un petit ScrollViewer qui utilise la place disponible, un grand TextBlock, contenant un long texte.
<ScrollViewer
Height
=
"232"
Width
=
"448"
HorizontalScrollBarVisibility
=
"Auto"
>
<TextBlock
Width
=
"530"
TextWrapping
=
"Wrap"
Text
=
"texte très long...."
/>
</ScrollViewer>
HorizontalScrollBarVisibility et VerticalScrollBarVisibility permettent de forcer ou non l'affichage de la ScrollBarr ; ici il est à « Auto» .
Voici comment on positionne le ScrollViewer (qui reste sur l'écran) et le TextBlock interne (plus grand que l'écran) dans le designer :
Le ScrollViewer peut aussi être utilisé comme conteneur de tous les objets de la page ; si on passe en mode paysage les objets du bas de la page ne sont plus visibles mais on peut remonter la page pour en voir le bas.
VI-C-5. WrapPanel▲
Le WrapPanel qui est un conteneur où les éléments sont mis à la suite l'un de l'autre mais où il y a "retour à la ligne" quand on atteint la limite du conteneur. Les éléments se positionnent de gauche à droite et de haut en bas.
Voir le chapitre sur le Toolkit.
VI-C-6. Positionnement dynamique : les grandes règles▲
Layout dynamique : permet un positionnement quel que soit la résolution de l'écran.
On utilise un StackPanel ou surtout une Grid comme conteneur.
Dans les cellules, on met des contrôles avec les propriétés Width et Height= Auto. Ils occupent toutes 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 *.
VI-D. Les Boutons▲
VI-D-1. Les Button▲
Pour ajouter un bouton, on clique sur le bouton dans les outils à gauche puis sur le formulaire, on appuie (bouton gauche de la souris), on déplace puis on lâche. Le bouton apparaît.
En bas à droite, on a la fenêtre de propriétés du bouton.
Le nom du contrôle est en haut, après « Name ».
Dans le designer, la propriété « Content » contient le texte à afficher sur le bouton.
Si on double-clique sur un bouton, par exemple, on se retrouve dans la fonction évènement correspondante qui est Button1_Click.
Créons un bouton avec du code XAML.
Il faut taper dans la fenêtre XAML :
<Button>
Ok</Button>
Cela crée un bouton sur lequel est affiché « Ok ». Il apparaît en haut.
Faisons plus complet :
<Button
Height
=
"150"
Margin
=
"55,50,79,0"
Name
=
"Button1"
VerticalAlignment
=
"Top"
Click
=
"OnClick5"
>
Ok</Button>
Voyons le détail de cette ligne :
La balise « Button » crée un bouton.
Name="Button1" indique le nom du contrôle dans le designer.
VerticalAlignment="Top" indique que le contrôle est ancré en haut (il reste toujours à la même distance du bord sur lequel il est ancré. Valeur possible : Top, Bottom, Center.
HorizontalAlignment="Left" même chose pour l'alignement horizontal.
Margin définit la distance par rapport aux bords du conteneur.
Width="" Height="" indiquent les dimensions du bouton (largeur, hauteur).
On peut aussi ajouter MinWidth MinHeight MaxWidth et MaxHeight qui indiquent les tailles minimales et maximales.
On aurait pu utiliser l'attribut Content="Ok" pour mettre un texte dans le bouton.
On peut positionner le « Content » dans le bouton en indiquant des alignements et marges internes (Padding) :
<Button
Content
=
"Cliquez ici"
Padding
=
"70 100"
HorizontalContentAlignment
=
"Right"
VerticalContentAlignment
=
"Bottom"
/>
Click="OnClick5" indique que l'action de cliquer sur le bouton déclenche la fonction OnClick5.
Cela crée automatiquement, dans le code C#, la routine suivante :
private
void
OnClick5
(
object
sender,
RoutedEventArgs e)
{
}
sender est l'objet qui a déclenché l'évènement.
e contient les arguments de l'évènement, remarquons que e est de type RoutedEventArgs (et pas EventArgs comme dans les Windows Forms).
On peut ajouter du code dans la routine, pour modifier les propriétés du bouton, par exemple :
private
void
OnClick5
(
object
sender,
RoutedEventArgs e)
{
Button1.
FontSize =
16
;
Button1.
Content =
"Ok Ok.."
;
}
Mettre des formes dans un bouton puis y mettre une image.
<Button>
<StackPanel>
<Ellipse
Height
=
"40"
Width
=
"40"
Fill
=
"Blue"
/>
<TextBlock
TextAlignment
=
"Center"
>
Button</TextBlock>
</StackPanel>
</Button>
<Button>
<Rectangle
Height
=
"40"
Width
=
"40"
Fill
=
"Blue"
/>
</Button>
<Button
Height
=
"130"
Margin
=
"9,362,0,0"
Name
=
"Button2"
VerticalAlignment
=
"Top"
>
<Image
Source
=
"wphone.jpg"
></Image>
</Button>
Cela donne :
Pour mettre une image dans un bouton il faut avoir le fichier image, l'ajouter au projet (menu « Projet » puis « Ajouter un élément existant ») ajouter Image et renseigner la source.
On peut choisir un fichier GIF avec un fond transparent ce qui permet de ne pas voir le fond de l'image.
Comment mettre un texte et une image dans un bouton ?
Il faut mettre un StackPanel dans le bouton (puisque celui-ci ne peut contenir qu'un seul objet), dans ce StackPanel mettre un TextBlock et une Image. Le faire en tapant du code XAML (dans le designer VB c'est difficile de mettre un StackPanel dans un Button, il se met dessus et pas dedans, donc copier/coller le code XAML). De plus l'image doit être dans les ressources.
<Button
Height
=
"170"
Margin
=
"31,377,-22,0"
Name
=
"Button2"
VerticalAlignment
=
"Top"
>
<StackPanel
Height
=
"212"
>
<TextBlock
HorizontalAlignment
=
"Center"
>
Ok</TextBlock>
<Image
Source
=
"wphone.jpg"
Height
=
"84"
Width
=
"96"
></Image>
</StackPanel>
</Button>
Cela donne :
Voir aussi le chapitre sur les ressources.
Créons un bouton avec du code C# :
Button myButton =
new
Button
(
);
//Création du bouton
myButton.
Content =
"ok"
;
//Afficher 'Ok' dans le bouton
myButton.
Background =
new
SolidColorBrush
(
Colors.
Blue);
//Fond en bleu
ContentPanel.
Children.
Add
(
myButton);
//Ajouter le bouton à la grid
myButton.
Click +=
new
RoutedEventHandler
(
buttonClick);
//Indiquer que le click sur le bouton
//doit exécuter 'buttonClick'
private
void
buttonClick
(
object
sender,
RoutedEventArgs e)
{
MessageBox.
Show
(
"ok"
);
}
'doit exécuter la Sub nommée '
Click'
On remarque que, comme on crée par code, il faut soi même écrire la gestion des évènements.
Quand on crée le bouton en mode designer, et que l'on double-clique sur le bouton, la routine myButton_Click est automatiquement affichée.
VI-D-2. HyperLinkButton▲
Représente un bouton qui affiche un lien hypertexte.
<HyperlinkButton
Content
=
"Cliquer ici pour voir Silverlight.net"
NavigateUri
=
"http://www.silverlight.net"
TargetName
=
"_blank"
Margin
=
"10,60,0,0"
/>
NavigateUri donne l'adresse.
TargetName a la valeur :
_blank, _media ou _search, cela charge le document dans une nouvelle fenêtre vide.
_parent, _self, _top, ou "" cela charge la page dans la fenêtre dans laquelle l'utilisateur a cliqué sur le lien (la fenêtre active).
L'effet n'est pas visible.
Si on met une adresse Internet, cliquer sur le lien ouvre le navigateur Web.
On peut aussi naviguer vers une autre page :
<HyperlinkButton
NavigateUri
=
"MySecondPage.xaml"
/>
VI-E. Les contrôles contenant du texte▲
Les contrôles permettant de voir ou de modifier du texte sont :
- les TextBlock ;
- les TextBox ;
- les RichTextBox ;
- les PasswordBox.
VI-E-1. Les TextBlock▲
Permettent d'afficher du texte dans une page en lecture seule, sans possibilité de le modifier. Il est bien adapté pour afficher une ou au maximum quelques lignes.
Prendre un TextBlock dans les outils et le mettre dans un formulaire.
Pour mettre rapidement un petit texte dedans en C#, utiliser la propriété Text.
TextBlock1.
Text=
"Mon texte"
;
La même chose en XAML :
<TextBlock>
Mon texte
</TextBlock>
TextWrapping="Wrap"
Permet de passer automatiquement à la ligne.
On peut modifier le texte (Text), la hauteur des caractères (FontSize), la couleur du texte (Foreground) :
<TextBlock
Name
=
"TextBlock1"
Text
=
"Hauteur:"
FontSize
=
"46"
Foreground
=
"Cyan"
Height
=
"55"
Width
=
"308"
/>
Un TextBlock a une propriété Foreground (couleur du texte) mais pas de Background (pas de couleur de fond), pas de bords.
Pour mettre une couleur de fond, il faut mettre le TextBlock dans un Rectangle.
Pour avoir un bord, mettre le TextBlock dans un Border (dans le TextBox mettre Margin="0").
<Border
Margin
=
"12,189,0,352"
BorderThickness
=
"2"
BorderBrush
=
"Bisque"
>
<TextBlock
Name
=
"resultat"
HorizontalAlignment
=
"Left"
Margin
=
"0"
TextAlignment
=
"Center"
>
</TextBlock>
</Border>
On peut ajouter des sauts de lignes simplement grâce à \n.
TextBlock1.
Text=
"Mon texte
\n
Seconde ligne "
;
On peut ajouter dans le code XAML plusieurs lignes (avec la balisee Run qui correspond à un morceau de texte) avec des couleurs, des tailles, des polices différentes et des retours à la ligne avec des LineBreak.
<TextBlock
Height
=
"151"
HorizontalAlignment
=
"Left"
Margin
=
"65,243,0,0"
Name
=
"textBlock4"
VerticalAlignment
=
"Top"
Width
=
"290"
>
<LineBreak/>
<Run
Foreground
=
"Maroon"
FontFamily
=
"Courier New"
FontSize
=
"24"
>
Courier New 24</Run>
<LineBreak/>
<Run
Foreground
=
"Teal"
FontFamily
=
"Times New Roman"
FontSize
=
"18"
FontStyle
=
"Italic"
>
Times New Roman Italic 18</Run>
<LineBreak/>
<Run
Foreground
=
"SteelBlue"
FontFamily
=
"Verdana"
FontSize
=
"14"
FontWeight
=
"Bold"
>
Verdana Bold 14</Run>
</TextBlock>
On peut le faire en C# :
using
System.
Windows.
Documents;
TextBlock textlong =
new
TextBlock
(
);
Run r =
new
Run
(
);
r.
Text =
"mon texte"
;
r.
FontSize =
20
;
r.
FontWeight =
FontWeights.
Bold;
r.
Foreground =
new
SolidColorBrush
(
Colors.
Orange);
textlong.
Inlines.
Add
(
r);
textlong.
Inlines.
Add
(
new
LineBreak
(
));
On déclare un « Run », on modifie ses propriétés ; on l'ajoute à la collection de lignes (InLines). On peut aussi ajouter un saut de ligne.
Exercice : j'ai une string mySting, je veux l'ajouter à un TextBlock avec des passages à la ligne et mettre la première ligne en orange.
string
myString=
"Titre:?Première ligne.?Seconde ligne."
;
J'ai ajouté un caractère '¤' signifiant retour à la ligne.
Je vais découper la string grâce à Split puis avec une boucle je vais ajouter à la collection InLines un Run (un texte ) puis un LineBreak.
int
i=
0
;
foreach
(
var
line in
myString.
Split
(
'?'
))
{
if
(
i ==
0
)
{
var
r =
new
Run
(
);
r.
Text =
line;
r.
FontSize =
20
;
r.
FontWeight =
FontWeights.
Bold;
r.
Foreground =
new
SolidColorBrush
(
Colors.
Orange);
TextLong.
Inlines.
Add
(
r);
TextLong.
Inlines.
Add
(
new
LineBreak
(
));
i++;
}
else
{
TextLong.
Inlines.
Add
(
line);
TextLong.
Inlines.
Add
(
new
LineBreak
(
));
}
}
VI-E-2. Les TextBox▲
Permettent d'afficher du texte, il est modifiable par l'utilisateur.
La police de caractères, sa taille, la couleur, l'enrichissement des caractères affectent la totalité du texte. Il n'est pas possible d'enrichir (gras, italique…) une partie du texte seulement.
Créons un TextBox en XAML :
<TextBox></TextBox>
Donnons lui un nom :
<TextBox
Name
=
"TextBox1"
></TextBox>
Mettons un texte dedans :
<TextBox
Name
=
"TextBox1"
>
Ceci est le texte</TextBox>
En C#
TextBox1.
Text=
"le texte"
;
TextBox1.Text contient le texte affiché dans la TextBox.
TextBox1.IsReadOnly=true interdit les modifications du texte.
TextBox1.AcceptEnter=true autorise le passage à la ligne quand on tape « Enter ». Si AcceptEnter=false, on ne peut saisir qu'une seule ligne.
VerticalScrollBarVisibility=true affiche une ScrollBar verticale.
TextBox1.MaxLength permet de définir le nombre de caractères. 0 pour une saisie illimitée.
Si l'utilisateur a sélectionné du texte, il est dans TextBox1.SelectedText.
TextBox1.SelectionStart, TextBox1.SelectionLength indique la position du premier caractère sélectionné (le premier caractère du texte étant le caractère 0) et le nombre de caractères sélectionnés.
On peut utiliser ces propriétés pour sélectionner du texte avec du code ou utiliser TextBox1.Select(3, 2), il existe enfin SelectAll qui selectionne la totalité du texte.
Si le texte est modifié cela déclenche :
private
void
textBox1_TextChanged
(
object
sender,
TextChangedEventArgs e)
{
}
Double_cliquez sur le TextBox, cela fera apparaître le code qui précède.
Quand l'utilisateur frappe une touche cela déclenche les évènements KeyDown puis KeyUp (pas de keyPress !)
Pour ajouter la gestion de l'évènement KeyUp, cliquer sur le bouton. Dans la fenêtre des propriétés cliquer sur l'onglet « Évènements ».
Puis dans la liste double-cliquez sur « KeyUp » vous voyez apparaître :
<TextBox
Name
=
"textBox1"
Text
=
"TextBox1"
KeyUp
=
"textBox1_KeyUp"
/>
Et dans le code C# :
private
void
textBox1_KeyUp
(
object
sender,
KeyEventArgs e)
{
}
On note que la fonction a un paramètre e de type KeyEventArgs qui a la propriété Key qui contient la touche tapée. Malheureusement e.Key est en lecture seule ! On ne peut donc pas modifier le caractère tapé !
De plus le contenu de e.Key est bizarre ! Des expressions comme if (e.Key==Key.B)… ne fonctionnent pas car e.Key ne contient pas ce qui est attendu.
Pour modifier les caractères tapés on les modifie directement dans la propriété text :
private
void
textBox1_KeyUp
(
object
sender,
KeyEventArgs e)
{
TextBox TextBoxControl =
(
TextBox)sender;
string
keys;
keys =
"1234567890"
;
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;
}
}
}
Quand on tape sur une TextBox et qu'elle prend le focus, il apparaît automatiquement un clavier virtuel en bas.
Le clavier par défaut, si on n'indique rien est le clavier "Default".
Il permet de taper des minuscules et donne accès aux majuscules et aux chiffres :
Ce petit clavier à l'écran est appelé "panneau de saisie logiciel" ou SIP.
Mais on peut avoir besoin d'afficher un autre clavier virtuel.
Voici le clavier TelephoneNumber permettant de taper des numéros de téléphone :
Comment l'obtenir ?
En utilisant un InputScope.
<
TextBox Name=
"entree1"
InputScope=
"TelephoneNumber"
Height=
"75"
Text=
""
>
</
TextBox>
Ci dessous une syntaxe plus longue mais permettant d'avoir de l'aide à la saisie, la liste des valeurs s'affiche quand on saisit NameValue :
<TextBox
Height
=
"90"
Name
=
"textBox1"
Text
=
""
Width
=
"197"
Margin
=
"79,105,181,412"
>
<TextBox.InputScope>
<InputScope>
<InputScopeName
NameValue
=
"Digits"
></InputScopeName>
</InputScope>
</TextBox.InputScope>
</TextBox>
En C# :
InputScope scope =
new
InputScope
(
);
InputScopeName name =
new
InputScopeName
(
);
// Saisir des dates
name.
NameValue =
InputScopeNameValue.
Date;
// Saisir un numéro de téléphone
name.
NameValue =
InputScopeNameValue.
TelephoneNumber;
// Saisir un montant
name.
NameValue =
InputScopeNameValue.
CurrencyAmount;
scope.
Names.
Add
(
name);
MyTextBox.
InputScope =
scope;
Il y a aussi DateDay, DateMonth, DateYear, Address, Chat, Digits, FileName, Number, OneChar, PostalCode, Text, Time, Url, Xml…
Voici quelques exemples :
Text : la première lettre tapée est en majuscule puis le clavier passe en minuscules.
Quand on tape au moins une lettre la zone au dessus du clavier propose des mots sur lesquels on peut taper.
En plus de ces suggestions de texte, il y a la correction automatique, l'auto-apostrophe, l'auto-accentuation et l'auto capitalisation.
Chat est le même clavier (contrairement à la version anglaise et a ce qui est dit par ailleurs).
Url :
permet de saisir des adresses Internet.
L'appui long sur « .com » donne accès à d'autres nom de domaine.
Digit :
pour saisir les chiffres de 0 à 9 et le point (même si on est en clavier français).
CurrencyAmmont et Number sont le même clavier en français.
CurrencyAmountAndSymbol :
permet de saisir chiffres et symboles.
Contrairement à ce qui est dit ailleurs les inputscope sont différents de ceux de la version anglaise.
Sous Mango, l'InputScope « Number », représente maintenant uniquement un clavier numérique, alors qu'auparavant c'était le clavier chiffre+symboles.
En cours de saisie, il ne faut pas oublier de filtrer les caractères tapés (voir chapitre « Comment faire »).
VI-E-3. Les RichTextBox▲
Rich Text veut dire Texte enrichi.
Le contrôle RichTextBox permet d'afficher, d'entrer et de manipuler du texte mis en forme. Il effectue les mêmes tâches que le contrôle TextBox, mais il peut également afficher des polices, des couleurs pour une partie du texte et des liens, charger du texte et des images incorporées à partir d'un fichier, ainsi que rechercher des caractères spécifiques.
En Wp RichTextBlox est ReadOnly, donc pas de possibilité d'écrire dedans ! ce qui lui enlève son intérêt.
Ce contrôle n'apparaît pas dans la liste d'outils ; il faut l'ajouter :
Dans la boîte à outils, clic droit sur « Windows Phone Controls », puis clic sur la ligne « Choisir les éléments ».
Là on peut cocher le contrôle « RichTextBox » à ajouter dans la liste de la boîte à outils.
En XAML :
on peut ajouter un texte dans la balise Paragraph, l'enrichir avec les balises Bold, Italic, Underline, Hyperlink.
On peut aller à la ligne avec LineBreak.
<RichTextBox
Name
=
"rtb"
Height
=
"169"
HorizontalAlignment
=
"Left"
Margin
=
"42,6,0,0"
VerticalAlignment
=
"Top"
Width
=
"348"
>
<Paragraph>
Un RichTextBox avec du texte en <Bold>
gras </Bold>
en
<Italic>
italique</Italic>
en
<Underline>
souligné</Underline>
<LineBreak/>
<Hyperlink
NavigateUri
=
"http://search.msn.com"
>
avec un lien"</Hyperlink>
.
</Paragraph>
</RichTextBox>
Noter la syntaxe du lien qui montre que dans la balise on peut ajouter des attributs.
On va voir un autre exemple avec un Border et l'utilisation d'attributs pour modifier la couleur et la taille des caractères :
<
RichTextBox Name=
"rtb"
Height=
"339"
HorizontalAlignment=
"Left"
Margin=
"42,6,0,0"
VerticalAlignment=
"Top"
Width=
"348"
BorderThickness=
"4"
>
<
RichTextBox.
BorderBrush>
<
SolidColorBrush Color=
"Red"
/>
</
RichTextBox.
BorderBrush>
<
Paragraph>
<
Run Foreground=
"Red"
>
RichTextBox avec du texte en rouge</
Run>
<
LineBreak/>
<
Run FontSize=
"50"
>
C'est beau.</Run>
</
Paragraph>
</
RichTextBox>
Cela donne :
En C# c'est un peu plus difficile :
On crée des « Run » (portion de texte) qu'on met dans la collection Inlines des « Paragraph ». Ensuite on met les paragraphes dans la collection Blocks du RichTextBox.
//Créer un RichTextBox
RichTextBox MyRTB =
new
RichTextBox
(
);
//VertalScrollBar à auto
MyRTB.
VerticalScrollBarVisibility =
ScrollBarVisibility.
Auto;
// Créer deux 'Run' de texte et un 'Bold' avec du texte en gras.
Run myRun1 =
new
Run
(
);
myRun1.
Text =
"Un RichTextBox avec "
;
Bold myBold =
new
Bold
(
);
myBold.
Inlines.
Add
(
"du texte en gras "
);
Run myRun2 =
new
Run
(
);
myRun2.
Text =
"dedans."
;
// Créer un 'Paragraph' et y ajouter les 2 Run et le Bold.
Paragraph myParagraph =
new
Paragraph
(
);
myParagraph.
Inlines.
Add
(
myRun1);
myParagraph.
Inlines.
Add
(
myBold);
myParagraph.
Inlines.
Add
(
myRun2);
// Ajouter le paragraph au RichTextBox.
MyRTB.
Blocks.
Add
(
myParagraph);
//Ajouter le RichTextBox à la grille.
ContentPanel.
Children.
Add
(
MyRTB);
VI-E-4. Les PasswordBox▲
Permet de saisir un mot de passe.
La propriété PasswordChar détermine le caractère affiché à la place des caractères tapés.
En XAML :
<PasswordBox
Name
=
"pwdBox"
MaxLength
=
"64"
PasswordChar
=
"#"
PasswordChanged
=
"PasswordChanged"
/>
Ici le fait de taper un mot de passe déclenche la fonction PasswordChanged.
En C# on récupère le mot de passe dans :
pwdBox.
Password
VI-F. Les cases à cocher et RadioButton▲
VI-F-1. Case à cocher▲
Créons une case à cocher.
C'est une CheckBox. L'utilisateur peut la cocher ou non en cliquant dessus.
Dans le designer, la propriété Content contient le texte à afficher à côté de la case.
Les évènements les plus utiles sont : Checked et Unchecked.
<!-- CheckBox à 2 états -->
<CheckBox
x
:
Name
=
"cb1"
Content
=
"CheckBox à 2 états"
Checked
=
"HandleCheck"
Unchecked
=
"HandleUnchecked"
Margin
=
"5"
/>
<TextBlock
x
:
Name
=
"text1"
Margin
=
"5"
/>
<!-- CheckBox à 3 états -->
<CheckBox
x
:
Name
=
"cb2"
Content
=
"CheckBox à 3 états"
IsThreeState
=
"True"
Checked
=
"HandleCheck"
Indeterminate
=
"HandleThirdState"
Unchecked
=
"HandleUnchecked"
Margin
=
"5"
/>
<TextBlock
x
:
Name
=
"text2"
Margin
=
"5"
/>
private
void
checkBox1_Checked
(
object
sender,
RoutedEventArgs e)
{
}
Dans le code XAML IsChecked="True" permet de cocher un CheckBox. Dans le code C#, la propriété IsChecked permet de voir si la case est cochée ou non.
if
(
MyradioButton1.
IsChecked ==
true
)
{
conv =
0
.
6
;
}
VI-F-2. RadioButton▲
Les RadioButton peuvent être cochés ou non.
Ils sont généralement regroupés pour offrir aux utilisateurs un choix unique parmi plusieurs options, un seul bouton à la fois peut être coché. Si on clique sur un RadioButton dans un groupe, on le sélectionne, cela désélectionne les autres.
Vous pouvez regrouper des contrôles RadioButton en les plaçant dans un parent commun ou en leur attribuant un nom de groupe (GroupName).
Quand un RadioButton est sélectionné, l'événement Checked est déclenché. Comme le montre l'exemple de code suivant, si votre application doit faire une action quand la sélection de RadioButton change, vous pouvez gérer l'événement Checked.
<RadioButton
Name
=
"MyRadioBUtton"
IsChecked
=
"True"
Checked
=
"Myroutine"
GroupName
=
"MyGroupe"
>
Texte
</RadioButton>
VI-G. Les ListBox▲
Une ListBox est un contrôle qui contient une collection de ListBoxItem. Chaque ListBoxItem a une propriété « Content ».
Créons une ListBox avec trois ListBoxItem en XAML :
<ListBox
Height
=
"176"
HorizontalAlignment
=
"Left"
Margin
=
"19,27,0,0"
Name
=
"listBox1"
VerticalAlignment
=
"Top"
Width
=
"400"
>
<ListBoxItem
Content
=
"Paris"
/>
<ListBoxItem
Content
=
"Lyon"
/>
<ListBoxItem
Content
=
"Marseille"
/>
</ListBox>
Créer en C# une ListBox puis ajouter des éléments à la ListBox :
ListBox ListBox1 =
new
ListBox
(
);
ListBox1.
Items.
Add
(
"Paris"
);
ListBox1.
Items.
Add
(
"Lyon"
);
ListBox1.
Items.
Add
(
"Marseille"
);
ContentPanel.
Children.
Add
(
ListBox1);
On peut créer en C#, une collection « Villes », y ajouter des éléments et ensuite faire un binding :
List<
string
>
Villes =
new
List<
string
>
{
"Paris"
,
"Lyon"
,
"Marseille"
};
listBox1.
ItemsSource =
Villes;
Dans ce cas dans le code XAML ItemsSource doit indiquer qu'il y a binding.
<ListBox
ItemsSource
=
"{Binding}"
Name
=
"listBox1"
/>
On peut effacer la liste.
ListBox.
Items.
Clear
(
);
SelectedIndex indique l'index de l'élément sélectionné (-1 si pas de sélection).
SelectedItem indique l'item (objet) sélectionné. On peut l'utiliser pour forcer par code la sélection.
ListBox.
SelectedItem =
ListBox.
Items[
2
];
On peut ajouter un bord autour du ListBox :
<ListBox
BorderThickness
=
"5"
BorderBrush
=
"Red"
/>
Maintenant on veut personnaliser chaque Item.
Pour cela, on va utiliser un style pour les ListBoxItem.
On va créer dans les ressources de la grille racine un style pour les ListBoxItem ; ce style définira un template qui affiche un bord pour chaque Item.
Enfin on créera la ListBox en utilisant pour chaque ListBoxItem le style précédent.
<Grid
x
:
Name
=
"ContentPanel"
Grid.
Row
=
"1"
Margin
=
"12,0,12,0"
>
<Grid.Resources>
<Style
x
:
Key
=
"ListBoxTemplate"
TargetType
=
"ListBoxItem"
>
<Setter
Property
=
"Template"
>
<Setter.Value>
<ControlTemplate
TargetType
=
"ListBoxItem"
>
<Border
BorderThickness
=
"3"
BorderBrush
=
"Azure"
Height
=
"50"
Margin
=
"4"
>
<ContentPresenter
HorizontalAlignment
=
"Center"
VerticalAlignment
=
"Center"
Content
=
"{TemplateBinding Content}"
/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<ListBox
BorderThickness
=
"5"
BorderBrush
=
"Red"
Height
=
"192"
HorizontalAlignment
=
"Left"
Margin
=
"19,27,0,0"
Name
=
"listBox1"
VerticalAlignment
=
"Top"
Width
=
"400"
SelectionChanged
=
"listBox1_SelectionChanged"
>
<ListBoxItem
Content
=
"Paris"
Style
=
"{StaticResource ListBoxTemplate}"
/>
<ListBoxItem
Content
=
"Lyon"
Style
=
"{StaticResource ListBoxTemplate}"
/>
<ListBoxItem
Content
=
"Marseille"
Style
=
"{StaticResource ListBoxTemplate}"
/>
</ListBox>
</Grid>
</Grid>
On remarque que le Template du ListBoxItem contient dans le Border un ContentPresenter ; dans ce ContentPresenter, on indique que le Content doit être lié au content du ListBoxItem.
On peut aussi modifier l'item template pour, au lieu d'afficher les items les uns au dessus des autres, les afficher de gauche à droite avec passage à la ligne (comme dans le Media Library). Il faut pour cela utiliser un WrapPanel (voir dans le chapitre sur le Toolkit).
Mettre des boutons, des cases à cocher dans une ListBox :
Les CheckedListBox n'existent pas en WP ? On va les créer dans une ListBox1 :
<ListBox
BorderThickness
=
"5"
BorderBrush
=
"Red"
Height
=
"192"
Name
=
"listBox2"
SelectionChanged
=
"listBox1_SelectionChanged"
>
<CheckBox
Content
=
"Option1"
></CheckBox>
<CheckBox
Content
=
"Option2"
></CheckBox>
</ListBox>
De la même manière, on peut créer une liste de boutons…
Utilisation du binding sur une ListBox.
On reprend l'exemple du chapitre sur le binding en le complétant.
Dans Class1.cs on crée une classe nommée « ElementDeListe ».
using System;
using System.ComponentModel;
using System.Diagnostics;
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 listboxbinding // Espace de noms = nom du programme
{
public class ElementDeListe // la classe se nomme 'ElementDeListe'
{
private string _Titre; // Variable privée
public string Titre // Variable public avec son get et son set
{
get
{
return _Titre;
}
set
{
if (value != _Titre)
{
_Titre = value;
}
}
}
private string _Formule;
public string Formule
{
get
{
return _Formule;
}
set
{
if (value != _Formule)
{
_Formule = value;
}
}
}
private string _Mode;
public string Mode
{
get
{
return _Mode;
}
set
{
if (value != _Mode)
{
_Mode = value;
}
}
}
public ElementDeListe(string t, string n, string m) { _Titre = t; _Formule = n; _Mode = m; }
}
}
Dans MainPage.xaml.cs on déclare une Collection nommée « ListMath » de type List, on y met quelques éléments.
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;
using
Microsoft.
Phone.
Controls;
namespace
listboxbinding
{
public
partial
class
MainPage :
PhoneApplicationPage
{
public
List<
ElementDeListe>
ListeMath {
get
;
set
;
}
//la collection sera public
// Constructeur
public
MainPage
(
)
{
InitializeComponent
(
);
ListeMath =
new
List<
ElementDeListe>(
);
//On va créer de nouveaux ElementDeliste en utilisant le constructeur à 3 paramètres.
ListeMath.
Add
(
new
ElementDeListe
(
"Francs-Euros"
,
"C"
,
"C"
));
ListeMath.
Add
(
new
ElementDeListe
(
"Celsius-Fahrenheit"
,
"Celsius"
,
"C"
));
ListeMath.
Add
(
new
ElementDeListe
(
"Celsius-Kelvin"
,
"Celsius"
,
"C"
));
listBox1.
DataContext =
ListeMath;
// en prime on ajoute un binding (une liaison) sur une listbox
}
}
}
En fin de code on lie la collection à la ListBox grâce à sa propriété DataContext.
Dans MainPage.xaml on crée une ListBox nommée « listBox1 », on indique que la source des items est une liaison.
<Grid
x
:
Name
=
"ContentPanel"
Grid.
Row
=
"1"
Margin
=
"12,0,12,0"
>
<ListBox
ItemsSource
=
"{ Binding}"
Height
=
"193"
HorizontalAlignment
=
"Left"
Margin
=
"40,32,0,0"
Name
=
"listBox1"
VerticalAlignment
=
"Top"
Width
=
"369"
/>
</Grid>
Cela donne :
La ListBox affiche les types !
C'est normal elle affiche ce que retourne la méthode ToString().
On a une première méthode pour éviter l'affichage du type : on surcharge la méthode ToString de la classe ElementdeListe :
public
override
string
ToString
(
)
{
return
Titre +
" - "
+
Formule;
}
Cela marche bien mais uniquement avec du texte.
Une autre méthode (plus générale) pour afficher Titre et Formule, on va ajouter un ItemTemplate contenant un StackPanel horizontal qui contient trois TextBlock. Le premier et le troisième sont liés au propriétés « Titre » et « Formule ».
<Grid
x
:
Name
=
"ContentPanel"
Grid.
Row
=
"1"
Margin
=
"12,0,12,0"
>
<ListBox
ItemsSource
=
"{ Binding}"
Height
=
"193"
HorizontalAlignment
=
"Left"
Margin
=
"40,32,0,0"
Name
=
"listBox1"
VerticalAlignment
=
"Top"
Width
=
"369"
>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel
Orientation
=
"Horizontal"
>
<TextBlock
Text
=
"{Binding Titre}"
/>
<TextBlock
Text
=
", "
/>
<TextBlock
Text
=
"{Binding Formule}"
/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Utilisation d'ItemTemplate complexe.
On veut afficher pour chaque Item une petite sphère, la propriété « Titre » en gros et la propriété « Formule » dessous en plus petit :
<ListBox
Name
=
"listBox1"
Margin
=
"10,10,23,-9"
ItemsSource
=
"{Binding}"
Height
=
"524"
Width
=
"400"
MouseLeftButtonUp
=
"ListBoxConversion_Appel"
>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel
Orientation
=
"Horizontal"
Margin
=
"0,0,0,17"
>
<!--La petite sphère-->
<Ellipse
Height
=
"30"
Width
=
"30"
Margin
=
"12,0,9,0"
>
<Ellipse.Fill>
<RadialGradientBrush
Center
=
"0.4 0.4"
GradientOrigin
=
"0.4 0.4"
>
<GradientStop
Offset
=
"0"
Color
=
"White"
/>
<GradientStop
Offset
=
"1"
Color
=
"Blue"
/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<StackPanel
Width
=
"311"
>
<!--Les 2 lignes Titre et Formule-->
<TextBlock
Foreground
=
"Azure"
Text
=
"{Binding Titre}"
TextWrapping
=
"Wrap"
Style
=
"{StaticResource PhoneTextLargeStyle}"
/>
<TextBlock
Text
=
"{Binding Formule}"
TextWrapping
=
"Wrap"
Margin
=
"12,-6,12,0"
Style
=
"{StaticResource PhoneTextSubtleStyle}"
/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Bien respecter les majuscules et minuscules dans les liaisons car si on se trompe d'une lettre, rien ne signale une erreur mais cela ne marche pas.
On voit que l'ItemTemplate est beaucoup plus puissant, on peut afficher dans la ListBox du texte mais aussi des images…
Et les évènements !
Il est indiqué partout d'utiliser l'évènement SelectionChanged :
<ListBox
ItemsSource
=
"{ Binding}"
Height
=
"193"
HorizontalAlignment
=
"Left"
Name
=
"listBox1"
SelectionChanged
=
"ListBoxSelChange"
/>
Ainsi quand l'utilisateur tape sur une ligne de la ListBox l'évènement SelectionChanged se produit et la routine suivante est exécutée.
private
void
ListBoxSelChange
(
object
sender,
RoutedEventArgs e)
{
if
(
e.
AddedItems.
Count >
0
)
string
TexteSelectionné =
e.
AddedItems[
0
].
ToString
(
);
}
L'inconvénient est que si je tape deux fois de suite sur le même item de la ListBox, la seconde fois ne déclenche rien puisque la sélection n'a pas changé.
J'utilise plutôt MouseLeftButtonUp.
<ListBox
ItemsSource
=
"{Binding}"
Height
=
"193"
HorizontalAlignment
=
"Left"
Name
=
"listBox1"
MouseLeftButtonUp
=
"ListBox_Appel"
/>
Quand l'utilisateur tape sur une ligne de la ListBox l'évènement MouveLeftButtonUp se produit et la routine suivante est exécutée.
Je peux utiliser l'item sélectionné : SelectedItem.
private
void
ListBoxConversion_Appel
(
object
sender,
RoutedEventArgs e)
{
//sender est l'objet qui a déclenché l'évènement, je le cast en listbox
ListBox list =
sender as
ListBox;
//SelectedItem est aussi un objet qui doit être casté
ElementDeListe ItemSelectionne =
list.
SelectedItem as
ElementDeListe;
if
(
ItemSelectionne ==
null
)
return
;
}
//....Ici on peut utiliser ItemSelectionne
}
VI-H. Les Slider▲
Un Slider est un curseur qu'on peut déplacer avec le doigt :
<StackPanel>
<Slider
Name
=
"Slider1"
Value
=
"5"
Maximum
=
"200"
Minimum
=
"0"
Margin
=
"0,294,0,172"
/>
<Rectangle
Fill
=
"Blue"
Stroke
=
"Red"
StrokeThickness
=
"3"
Width
=
"97"
Height
=
"{Binding ElementName=Slider1, Path=Value}"
/>
</StackPanel>
Ici on utilise un Slider pour modifier la hauteur d'un rectangle grâce au binding.
VI-I. Les MessageBox▲
Comment afficher un message pour l'utilisateur (sans sortir de la page) ?
MessageBox.
Show
(
"Erreur sur le format de la date"
);
Cela donne :
Il y a un bouton « Ok » par défaut pour sortir du MessageBox.
Sinon on peut ajouter un titre et un bouton « Annuler ».
MessageBox.
Show
(
"Poursuivre?"
,
"Exemple MessageBox"
,
MessageBoxButton.
OKCancel);
MessageBox peut retourner dans une variable de type MessageBoxResult le résultat de l'action de l'utilisateur :
A-t-il tapé sur Ok ou Annuler ?
MessageBoxResult.Ok
ou
MessageBoxResult.Cancel
sera retourné suivant le bouton qui a été tapé par l'utilisateur.
MessageBoxResult result =
MessageBox.
Show
(
"Poursuivre?"
,
"Exemple MessageBox"
,
MessageBoxButton.
OKCancel);
if
(
result ==
MessageBoxResult.
OK)
{
MessageBox.
Show
(
"Vous avez tapé sur ok."
);
}
En WP7 il n'y a que deux boutons possibles.
Les InputBox n'existent pas.
VI-J. Image, Vidéo, Son▲
On peut ajouter un contrôle « Image ».
Comment mettre une image dans un contrôle image ?
En C# :
(image qui est sur Internet puis image locale) :
using
System.
Windows.
Media;
using
System.
Windows.
Media.
Imaging;
//Image sur Internet
//On instancie un Uri adresse internet d'une image
Uri uri =
new
Uri
(
"http://www.MonSite/MonImage.jpg"
);
//On instancie un BitmapImage on charge l'image
BitmapImage bmp =
new
BitmapImage
(
uri);
//On met le Bitmap dans le contrôle image
Image.
Source =
bmp;
//Image locale (avec comme 'option de génération'= 'Contenu')
Image.
Source =
new
BitmapImage
(
new
Uri
(
"MyImage.jpg"
,
UriKind.
Relative));
//Image locale (avec comme 'option de génération'= 'Resource')
Image.
Source =
new
BitmapImage
(
new
Uri
(
"NomProjet;component/MyImage.jpg"
,
UriKind.
Relative));
Dans le code XAML :
<Image
x
:
Name
=
"Image"
Source
=
"/Images/MyImage.jpg"
Width
=
"60"
Height
=
"60"
/>
Ici l'image (option de génération = Contenu) est dans un répertoire « Images » du projet.
Si l'image n'existe pas, il n'y a pas de levée d'exception. Pas d'arrêt du logiciel avec un code d'erreur. Cool !
Par contre, si on veut, on peut intercepter l'erreur en s'abonnant à l'évènement ImageFailed.
L'image doit être mise dans le projet : menu « Projet », « Ajouter un élément existant », choisir l'image puis « Ok », elle apparaît dans la fenêtre de l'explorateur de solution à droite.
Dans ses propriétés en bas à droite, il faut mettre « Option de génération » à « Contenu » ou le laisser à « Resource » (et Copier… à « Copier si plus récent »).
On se souvient que le chemin de l'application est « C:\Users\Philippe\Documents\Visual Studio 2010\Projects\Mon application ».
Utiliser des fichiers JPEG plutôt que des PNG (le décodage des PNG se fait au niveau logiciel alors que celui des JPEG se fait au niveau matériel).
Par contre pas de transparence dans les JPEG.
Pas de GIF dans WP.
On peut donner un chemin absolu :
<Button
HorizontalAlignment
=
"Left"
Margin
=
"4,0,0,0"
Name
=
"Button1"
VerticalAlignment
=
"Top"
Width
=
"150"
Height
=
"100"
>
<Image
Source
=
"C:/test.JPG"
/>
</Button>
On peut aussi utiliser les ressources pour mettre l'image (voir chapitre Ressources).
On peut ajouter l'attribut Opacity dont la valeur va de 0 à 1.
<Image
Source
=
"C:/test.JPG"
Opacity
=
"0.5"
/>
L"image est semi-transparente.
L'attribut Stretch permet de gérer les dimensions de l'image ; par défaut elle a la valeur « Uniform », ainsi la totalité de l'image rentre dans le contrôle sans déformation.
'UniformToFill' conserve les proportions mais ne force pas la totalité de l'image a être affichée.
'Fill' adapte l'image au conteneur, mais il peut y avoir des déformations.
« None » respecte les dimensions en pixel de l'image, l'image peut être plus petite ou plus grande que le conteneur ; on peut ne pas la voir en totalité.
<Image
Margin
=
"10,10,10,10"
Source
=
"fr.png"
Stretch
=
"UniformToFill"
/>
StretchDirection = UpOnly ne permet que l'agrandissement, DownOnly permet le contraire. Par défaut sa valeur est égale à Both.
On peut appliquer une transformation à une image (ici une rotation de 90 degrés) :
<Rectangle
Width
=
"200"
Height
=
"100"
Stroke
=
"Black"
StrokeThickness
=
"1"
>
<Rectangle.Fill>
<ImageBrush
Stretch
=
"UniformToFill"
>
<ImageBrush.ImageSource>
<BitmapImage
UriSource
=
"sampleImages\myimage.jpg"
/>
</ImageBrush.ImageSource>
<ImageBrush.RelativeTransform>
<RotateTransform
CenterX
=
"0.5"
CenterY
=
"0.5"
Angle
=
"90"
/>
</ImageBrush.RelativeTransform>
</ImageBrush>
</Rectangle.Fill>
</Rectangle>
Pour le son, la vidéo : on peut lire des Windows Media Video (WMV), Windows Media Audio (WMA), et fichier MP3.
<MediaElement
Name
=
"media"
Source
=
"silverlight.wmv"
/>
On peut arrêter, mettre en pause, démarrer une vidéo :
private
void
StopMedia
(
object
sender,
RoutedEventArgs e)
{
media.
Stop
(
);
}
private
void
PauseMedia
(
object
sender,
RoutedEventArgs e)
{
media.
Pause
(
);
}
private
void
PlayMedia
(
object
sender,
RoutedEventArgs e)
{
media.
Play
(
);
}
On peut ajouter une propriété « Volume » avec une valeur allant de 0 à 1 (défaut=0.5) en échelle logarithmique.
On peut aussi ajouter une propriété « AutoPlay », elle est à true par défaut. Il y a aussi Stretch et IsMuted.
VI-K. Formes▲
Le rectangle
<Rectangle
Fill
=
"Blue"
Stroke
=
"Red"
StrokeThickness
=
"3"
Width
=
"97"
Heightc
=
"20"
/>
Fill : couleur de remplissage.
Stroke : couleur du bord.
StrokeThickness : épaisseur du bord.
RadiusX et RadiusY : arrondir les angles.
L'ellipse
exemple : une sphère, on remplit un cercle (une ellipse aussi haute que large) avec un RadialGradientBrush :
<Grid >
<Ellipse
Height
=
"200"
Width
=
"200"
Margin
=
"12,0,9,0"
>
<Ellipse.Fill>
<RadialGradientBrush
Center
=
"0.4 0.4"
GradientOrigin
=
"0.4 0.4"
>
<GradientStop
Offset
=
"0"
Color
=
"White"
/>
<GradientStop
Offset
=
"1"
Color
=
"YellowGreen"
/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
On peut ajouter un bord autour d'un conteneur (ou d'un contrôle) :
<Border
BorderBrush
=
"White"
BorderThickness
=
"2"
CornerRadius
=
"20"
Height
=
"47"
>
<TextBlock
Margin
=
"2,4"
>
Rectangle</TextBlock>
</Border>
L'attribut CornerRadius permet d'arrondir les angles.
Voici un exemple en code c# :
Ellipse monEllipse =
new
Ellipse
(
);
monEllipse.
Stroke =
new
SolidColorBrush
(
Colors.
Cyan);
monEllipse.
Fill =
new
SolidColorBrush
(
Colors.
DarkGray);
monEllipse.
HorizontalAlignment =
HorizontalAlignment.
Left;
monEllipse.
VerticalAlignment =
VerticalAlignment.
Center;
monEllipse.
Width =
70
;
monEllipse.
Height =
95
;
ContentPanel.
Children.
Add
(
monEllipse);
On remarque que pour modifier le bord, le tour de la forme, on utilise Stroke (couleur) et StrokeThickness (épaisseur).
Polygone
On définit des points, il y a une ligne entre un point et le suivant, le dernier point étant relié au tout premier.
<Polygon
Fill
=
"Blue"
Stroke
=
"Black"
StrokeThickness
=
"2"
Points
=
"10,200,60,140,130,140,180,200"
/>
Il y a une collection « PointCollection » dans lequel vous ajoutez les « Point » pour former la collection.
Polylines fait de même sauf que le dernier point n'est pas relié au premier.
Path (chemin)
Permet de dessiner un chemin complexe :
<Path
Stroke
=
"Pink"
StrokeThickness
=
"4"
Data
=
"M 140,200 C 100,25 400,350 400,175 V 140 H 140"
/>
Data contient :
M : coordonnées (absolu) du point de départ ('m' si coordonnées relative) ;
C : courbe de Bézier commençant à la position de départ, se terminant à 400, 175 (2 dernières valeurs) ;
Passant pas les points 100,25 et 400,350 ;
V : ligne vertical se terminant à l'ordonnée 140 ;
H : ligne horizontale se terminant à l'abscisse 140.
Exemple plus complexe : dans un bouton, dessiner une loupe, l'agrandir grâce à RenderTransform :
<
Button Name=
"btnStart"
Click=
"btnStart_Click"
Width=
"260"
Margin=
"98,284,98,239"
>
<
Button.
Content>
<
StackPanel Orientation=
"Horizontal"
>
<
Path Fill=
"Blue"
Data=
"F1 M 2.339,6.489 C 1.193,5.343 1.193,3.485 2.339,2.339 C 3.485,1.192 5.344,1.193 6.489,2.339
C 7
.
635
,
3
.
485
7
.
635
,
5
.
343
6
.
489
,
6
.
489
C 5
.
344
,
7
.
636
3
.
485
,
7
.
636
2
.
339
,
6
.
489
Z M 11
.
711
,
10
.
209
L 8
.
185
,
6
.
684
C 9
.
207
,
4
.
986
9
.
000
,
2
.
757
7
.
535
,
1
.
293
C 5
.
812
,-
0
.
431
3
.
017
,-
0
.
431
1
.
293
,
1
.
293
C -
0
.
431
,
3
.
017
-
0
.
431
,
5
.
812
1
.
293
,
7
.
536
C 2
.
757
,
8
.
999
4
.
988
,
9
.
206
6
.
685
,
8
.
185
L 10
.
209
,
11
.
710
L 11
.
711
,
10
.
209
Z" Margin="
0
,
0
,
5
,
0
" Height="
36
" Width="
17
">
<
Path.
RenderTransform>
<
ScaleTransform ScaleX=
"3"
ScaleY=
"3"
/>
</
Path.
RenderTransform>
</
Path>
<
TextBlock Foreground=
"White"
Text=
"Chercher"
Margin=
"20 0 0 0"
/>
</
StackPanel>
</
Button.
Content>
</
Button><
br/>
Line
Elle va du point X1,Y1 à X2,Y2.
En XAML :
<Line
StrokeThickness
=
"4"
X1
=
"150"
Y1
=
"150"
X2
=
"100"
Y2
=
"100"
/>
En C# :
maLine =
new
Line
(
);
maLine.
Stroke =
System.
Windows.
Media.
Brushes.
Blue;
maLine.
X1 =
2
;
maLine.
X2 =
55
;
maLine.
Y1 =
1
;
maLine.
Y2 =
60
;
maLine.
HorizontalAlignment =
HorizontalAlignment.
Left;
maLine.
VerticalAlignment =
VerticalAlignment.
Center;
maLine.
StrokeThickness =
2
;
maGrid.
Children.
Add
(
myLine);
VI-L. Barre System en haut▲
Le SystemTray est la bande en haut qui contient les icônes de charge, de réseau, de type de réseau, l'heure.
Elle fait 32 pixels en vue portrait et 72 pixels en vue paysage. En mode paysage la barre est sur le rebord gauche de l'écran et pas en haut.
Par défaut, elle est blanche ou noire en fonction du thème. La grille « LayoutRoot » commence dessous.
Dans le XAML, dans la balise « PhoneApplicationPage », on charge l'espace de noms « Microsoft.Phone.Shell » (il l'est pas défaut).
Puis on peut modifier le SystemTray.
On peut ne pas afficher le SystemTray.
<
phone
:
PhoneApplicationPage
xmlns
:
shell
=
"clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
..
shell
:
SystemTray.
IsVisible
=
"False"
>
Il est possible de modifier la couleur des icônes et du fond. Cela ne marche qu'à partir de WP7.1 (Mango).
shell:SystemTray.ForegroundColor="Red"
shell:SystemTray.BackgroundColor="Blue"
Il y a un bug et pour mettre du blanc il faut écrire : shell:SystemTray.ForegroundColor="#FEFEFE".
On peut modifier l'opacité (de 0 à 1).
shell:SystemTray.Opacity="0.5">
L'opacité n'a pas d'incidence sur les icônes.
Si on modifie l'opacité, la page débute sur le bord de l'écran (en arrière du SystemTray) on voit donc la page par transparence à travers le SystemTray.
Sinon la page débute en dessous du SystemeTray.
En C# on peut modifier l'opacité de la bande (0 à 1) et les couleurs :
using
Microsoft.
Phone.
Shell;
SystemTray.
SetIsVisible
(
this
,
false
);
SystemTray.
SetOpacity
(
this
,
0
.
5
);
SystemTray.
SetBackgroundColor
(
this
,
Colors.
Purple);
SystemTray.
SetForegroundColor
(
this
,
Colors.
Yellow);
Ici on indique la page en premier paramètre.
Il existe aussi GetIsVisible… pour lire la propriété.
Quand on a un arrière fond clair et si on a modifié la taille de la Grid LayoutRoot, cela fait une bande blanche en haut ; pour éviter cela, il ne faut pas afficher le System Tray et surtout ne pas donner de hauteur à la grille, ainsi elle occupera tout l'espace (on peut donner, sans le vouloir, une valeur en déplaçant par erreur la grille) :
shell:SystemTray.IsVisible="False"
<!--LayoutRoot est la grille racine où tout le contenu de la page est placé-->
<Grid
x
:
Name
=
"LayoutRoot"
>
On peut aussi ajouter un ProgressIndicator.
Si IsIndeterminate = true cela affiche les points qui bougent de gauche à droite.
Si IsIndeterminate = false cela affiche une barre rouge de gauche à droite. La valeur de « Value » donne donne la longueur de la barre : 0= pas de barre, 1= barre complète.
public
partial
class
MainPage :
PhoneApplicationPage
{
ProgressIndicator prog;
// Constructeur
public
MainPage
(
)
{
InitializeComponent
(
);
prog =
new
ProgressIndicator
(
);
SystemTray.
SetIsVisible
(
this
,
true
);
SystemTray.
SetBackgroundColor
(
this
,
Colors.
Gray);
SystemTray.
SetForegroundColor
(
this
,
Colors.
Yellow);
prog.
IsVisible =
true
;
prog.
IsIndeterminate =
true
;
//Affiche les points qui bougent de gauche à droite
//false nécessite de donner des valeurs croissantes à 'Value'
prog.
Text =
"Clicker..."
;
SystemTray.
SetProgressIndicator
(
this
,
prog);
}
VI-M. Application Barre▲
L'application Barre permet de mettre une barre en bas avec des icônes (quatre maximum) et même d'ajouter un menu qu'on ouvre (avec les trois petits points).
Le code de l'ApplicationBar est déjà donné par Microsoft (il est en commentaire en bas de la page), j'ai ajouté la gestion des clics.
<!--Exemple de code illustrant l'utilisation d'ApplicationBar-->
<
phone
:
PhoneApplicationPage.ApplicationBar>
<
shell
:
ApplicationBar
IsVisible
=
"True"
IsMenuEnabled
=
"True"
>
<
shell
:
ApplicationBarIconButton
IconUri
=
"ApplicationBar.Cancel.png"
Text
=
"Annuler"
Click
=
"bouton1"
/>
<
shell
:
ApplicationBarIconButton
IconUri
=
"ApplicationBar.Check.png"
Text
=
"Ok"
Click
=
"bouton2"
/>
<
shell
:
ApplicationBar.MenuItems>
<
shell
:
ApplicationBarMenuItem
Text
=
"Menu 1"
Click
=
"menu1"
/>
<
shell
:
ApplicationBarMenuItem
Text
=
"Menu 2"
Click
=
"menu2"
/>
</
shell
:
ApplicationBar.MenuItems>
</
shell
:
ApplicationBar>
</
phone
:
PhoneApplicationPage.ApplicationBar>
</
phone
:
PhoneApplicationPage>
private
void
menu2
(
object
sender,
EventArgs e)
{
MessageBox.
Show
(
"menu2"
);
}
private
void
menu1
(
object
sender,
EventArgs e)
{
MessageBox.
Show
(
"menu1"
);
}
private
void
bouton1
(
object
sender,
EventArgs e)
{
MessageBox.
Show
(
"bouton1"
);
}
private
void
bouton2
(
object
sender,
EventArgs e)
{
MessageBox.
Show
(
"bouton2"
);
}
L'option de génération des fichiers images doit avoir la valeur « Contenu » et l'option « Copier dans… » la valeur « Copier si plus récent ».
Les icônes n'apparaîssent pas dans l'IDE, il faut tester avec l'émulateur.
On peut trouver des icônes dans le SDK, ici "C:\Program Files\Microsoft SDKs\Windows Phone\v7.1\Icons\dark", utiliser uniquement le répertoire dark, WP se chargera d'adapter l'image au thème.
On peut en trouver aussi sur Internet ou les dessiner soi-même. Microsoft conseille des images de 48 x 48 px avec le fond graphique au centre de 26 x 26 px. Couleur d'avant plan blanche et fond transparent ; pas de cercle qui sera dessiné par WP sur le bouton.
Si on veut désactiver le second bouton dans le code-behind :
//Inclure l'espace de noms
using
Microsoft.
Phone.
Shell;
(
this
.
ApplicationBar.
Buttons[
1
]
as
ApplicationBarIconButton).
IsEnabled =
false
;
VI-N. AdControl pour la publicité▲
À partir de Mango, on peut ajouter dans une application de la publicité rémunérée proposée par Microsoft.
Aller sur https://pubcenter.microsoft.com pour s'inscrire.
Une fois inscrit vous devrez choisir la taille de votre bannière (480*80 ou 300*50) et vous obtiendrez deux identifiants (ApplicationId et AdUnitId).
À partir de la boîte à outils glisser/déposer un contrôle AdControl :
Cela donne dans l'XAML :
<
my
:
AdControl
AdUnitId
=
"Image480_80"
ApplicationId
=
"test_client"
Height
=
"80"
Margin
=
"-12,179,0,0"
Name
=
"adControl1"
Width
=
"480"
/>
Bien mettre les Id récupérés sur le site.
Le contrôle ici a une taille de 480*80.
Il est impératif de respecter la taille et de ne pas modifier l'opacité.
VI-O. Le Toolkit▲
Le Silverlight Toolkit pour Windows Phone est un projet open source où l'équipe Microsoft Silverlight partage de nouveaux composants et fonctionnalités qui ne sont pas dans le noyau de Silverlight pour Windows Phone.
Le Toolkit ajoute donc des contrôles indispensables.
Se rendre sur le site codeplex :
http://silverlight.codeplex.com/.
Charger Silverlight for Windows Phone Toolkit pour Mango 7.1.
Ajouter la référence (la DLL) du ToolKit au projet. Dans l'explorateur de solution à droite, clic droit sur référence puis dans le menu clic sur « Ajouter une référence ».
Puis cliquer sur « Microsoft.Phone.Controls.ToolKit ».
Dans le code XAML ajouter l'espace de noms « Microsoft.Phone.Controls.Toolkit » :
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
Maintenant on peut ajouter un contrôle du ToolKit directement dans le code XAML :
<
toolkit
:
DatePicker />
On peut si on le désire ajouter le contrôle dans la boîte à outils. Dans celle-ci, click droit sur « Windows Phone Controls », puis dans le menu « Choisir les éléments ».
Là on peut cocher le contrôle à ajouter dans la liste de la boîte à outils.
Le ToolKit (version d'octobre 2011) fournit les contrôles suivant :
AutoCompleteBox, ContextMenu, DateTimePicker, DateTimeConverters, ExpanderView, GestureService/GestureListener, HeaderedItemsControl, HubTile, ListPicker, LocalizedResources, LockablePivot, LongListSelector, MultiselectList, Page Transitions, PerformanceProgressBar, PhoneTextBox, TiltEffect, TimePicker, ToggleSwitch, WrapPanel, LockablePivots .
AutoCompleteBox permet d'avoir une TextBox proposant une liste de mots dès qu'on tape des lettres.
<
toolkit
:
AutoCompleteBox
Margin
=
"25,42,0,0"
Name
=
"autoCompleteBox1"
/>
On va charger la liste des mots dans le code-behind :
List<
string
>
villes =
new
List<
string
>(
);
villes.
Add
(
"Barcelona"
);
villes.
Add
(
"Bélize"
);
villes.
Add
(
"Beaune"
);
villes.
Add
(
"Londres"
);
villes.
Add
(
"Paris"
);
villes.
Add
(
"Prague"
);
villes.
Add
(
"Madrid"
);
villes.
Add
(
"Rome"
);
this
.
autoCompleteBox1.
ItemsSource =
villes;
On peut modifier quelques propriétés :
//La liste apparaît après la frappe de 3 caractères
this
.
autoCompleteBox1.
MinimumPrefixLength =
3
;
//Tient compte de la casse de la première lettre
this
.
autoCompleteBox1.
FilterMode =
AutoCompleteFilterMode.
StartsWithCaseSensitive;
On peut ajouter un filtre, afficher des images… voir le libre blanc.
Le DatePicker permet de saisir une date.
<
toolkit
:
DatePicker
x
:
Name
=
"datePicker"
Value
=
"2/4/2012"
/>
En C# :
using
Microsoft.
Phone.
Controls;
DatePicker datePicker =
new
DatePicker
(
);
On a dans la page ce contrôle :
Quand on clique dessus, la page de saisie de date s'ouvre :
Il faut mettre dans le répertoire « Toolkit.Content » les fichiers « ApplicationBar.Cancel.png » et « ApplicationBar.Check.png ».
Où trouver les fichiers ? Aller sur le site http://silverlight.codeplex.com/releases. Dans « Other Available Downloads » charger le ZIP « Source Code Silverlight for Windows Phone Toolkit Source and Sample - Nov 2011.zip ». Dans le ZIP les fichiers PNG des icônes sont dans « Source and Samples\PhoneToolkitSample\Toolkit.Content ».
Il faut créer avec l'explorer, un répertoire « Toolkit.Content » à la racine du projet et y mettre les icônes « ApplicationBar.Cancel.png » et « ApplicationBar.Check.png » puis ajouter le répertoire au projet (dans l'explorateur de solution, clic sur l'icône « Afficher tous les fichiers », clic droit sur le répertoire puis « Ajouter », « Ajouter le répertoire ») ; enfin dans les propriétés de chaque fichier image, « Action de génération » doit avoir la valeur « contenu ». Copier doit avoir la valeur « Copier si plus récent ».
ToggleSwitch est un interrupteur :
<
toolkit
:
ToggleSwitch
x
:
Name
=
"toggle"
Content
=
"ToggleSwitch est on"
IsChecked
=
"True"
Header
=
"DemoToggleSwitch"
/>
Ici on le met à On et on ajoute un petit titre au-dessus :
En C# :
ToggleSwitch toggleSwitch =
new
ToggleSwitch
(
);
On peut ajouter les EventHandler « Checked » et « Unchecked » et les fonctions correspondantes qui modifient le texte et la couleur du contrôle en fonction de son état « on » « off» :
namespace
PhoneApp2
{
public
partial
class
MainPage :
PhoneApplicationPage
{
// Constructeur
public
MainPage
(
)
{
InitializeComponent
(
);
this
.
toggle.
Checked +=
new
EventHandler<
RoutedEventArgs>(
toggle_Checked);
this
.
toggle.
Unchecked +=
new
EventHandler<
RoutedEventArgs>
(
toggle_Unchecked);
}
void
toggle_Unchecked
(
object
sender,
RoutedEventArgs e)
{
this
.
toggle.
Content =
"ToggleSwitch est off"
;
this
.
toggle.
SwitchForeground =
new
SolidColorBrush
(
Colors.
Red);
}
void
toggle_Checked
(
object
sender,
RoutedEventArgs e)
{
this
.
toggle.
Content =
"ToggleSwitch est on"
;
this
.
toggle.
SwitchForeground =
new
SolidColorBrush
(
Colors.
Green);
}
}
}
On peut simplement tester l'état du ToggleSwitch :
if
(
this
.
toggle.
IsChecked ==
true
)
{
MessageBox.
Show
(
"On"
);
}
Dans le Toolkit il y a aussi le WrapPanel qui est un conteneur où les éléments sont mis à la suite l'un de l'autre mais où il y a "retour à la ligne" quand on atteint la limite du conteneur.
Les éléments se positionnent de gauche à droite et de haut en bas.
C'est pratique pour afficher une série de photos comme dans la Media Library de WP.
Exemple du blog d'Audrey Petit, il faut rajouter les binding.
Le template par défaut d'une ListBox n'est autre qu'un StackPanel avec une orientation verticale.
C'est pour cela que les items d'une ListBox se positionnent par défaut les uns en dessous des autres. Nous allons donc modifier ce template afin de lui faire utiliser un WrapPanel et positionner nos éléments les uns à côté des autres, avec passage à la ligne lorsqu'une ligne est complète.
xmlns:
toolkit=
"clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
<
phone:
PhoneApplicationPage.
Resources>
<
DataTemplate x:
Key=
"DataTemplatePhoto"
>
<
Grid Width=
"150"
Height=
"150"
>
<
Image x:
Name=
"imageItem"
Margin=
"5"
/>
</
Grid>
</
DataTemplate>
<
ItemsPanelTemplate x:
Key=
"PanelTemplatePhoto"
>
<
toolkit:
WrapPanel />
</
ItemsPanelTemplate>
</
phone:
PhoneApplicationPage.
Resources>
<
ListBox x:
Name=
"collectionPhoto"
ItemTemplate=
"{StaticResource DataTemplatePhoto}"
ItemsPanel=
"{StaticResource PanelTemplatePhoto}"
/>
La Toolbox permet aussi d'ajouter des effets comme le 'Tilt' effect, effet d'appui sur un élément tapé. Cela rend visible les contrôles tapés par le doigt.
<ListBox
toolkit
:
TiltEffect.
IsTiltEnabled
=
"True"
>
Le Toolkit ajoute aussi une gestion des gesrures (voir chapitre sur la saisie tactile et les gestures).
Consulter la bible (en anglais) du ToolKit, il y a tout en détail :http://www.windowsphonegeek.com/upload/ebooks/Windows%20Phone%20Toolkit%20Aug%202011%20in%20depth-v1.pdf.
VI-P. MessageBox▲
Comment afficher un message pour l'utilisateur sans sortir de la page ?
En utilisant la méthode Show de MessageBox.
MessageBox.
Show
(
"Erreur sur le format de la date"
);
Cela donne :
Il y a un bouton « Ok » par défaut pour sortir du MessageBox.
Sinon on peut ajouter un titre et un bouton annuler.
MessageBox.
Show
(
"Poursuivre?"
,
"Exemple MessageBox"
,
MessageBoxButton.
OKCancel);
MessageBox peut retourner dans une variable de type MessageBoxResult :
MessageBoxResult.Ok ou MessageBoxResult.Cancel, suivant le bouton qui a été tapé par l'utilisateur.
MessageBoxResult result =
MessageBox.
Show
(
"Poursuivre?"
,
"Exemple MessageBox"
,
MessageBoxButton.
OKCancel);
if
(
result ==
MessageBoxResult.
OK)
{
MessageBox.
Show
(
"Vous avez tapé sur ok."
);
}
En WP7 il n'y a que deux boutons possible.
VII. Grandes fonctions WP▲
VII-A. Données▲
VII-A-1. État de l'application▲
On peut enregistrer temporairement des données simples (de type clé/valeur) dans le dictionnaire d'état qui est temporaire (elles sont conservées en désactivation et en tombstoned, on perd les infos si le logiciel s'arrête).
Le dictionnaire d'état est accessible par la classe PhoneApplicationService et permet de conserver l'état de l'application (données, Web Service, etc.).
Voir le chapitre sur le tombstone.
Il faut au préalable inclure l'espace de noms Microsoft.Phone.Shell.
using Microsoft.Phone.Shell;
C'est aussi bien pratique, comme on l'a vu, pour passer des données simples d'une page à l'autre.
On enregistre (avec la clé « ToDo ») :
private
void
todoTb_TextChanged
(
object
sender,
TextChangedEventArgs e)
{
PhoneApplicationService.
Current.
State[
"Todo"
]
=
todoTb.
Text;
}
Pour récupérer les informations, on peut le faire dans le constructeur de l'autre page par exemple :
MainPage.
xaml.
cs
public
MainPage
(
)
{
InitializeComponent
(
);
if
(
PhoneApplicationService.
Current.
State.
ContainsKey
(
"CurrentTodo"
))
todoTb.
Text =
(
string
)PhoneApplicationService.
Current.
State[
"Todo"
];
...
}
Autre exemple : pour conserver l'état d'une page, on peut aussi l'enregistrer dans le dictionnaire d'état.
Là on va enregistrer dans la surcharge de la méthode OnNavigatedFrom et lire dans la surcharge de la méthode OnNavigatedTo.
En haut de la classe MainPage, on instancie MyappService de type PhoneApplicationService.
Pour lire, on utilise la méthode TryGetValue qui permet d'éviter les problèmes si la clé n'existe pas.
public
partial
class
MainPage :
PhoneApplicationPage
{
PhoneApplicationService MyappService =
PhoneApplicationService.
Current;
// Constructeur
public
MainPage
(
)
{
InitializeComponent
(
);
}
protected
override
void
OnNavigatedFrom
(
System.
Windows.
Navigation.
NavigationEventArgs args)
{
MyappService.
State[
"LeText"
]
=
MyTextBox.
Text;
base
.
OnNavigatedFrom
(
args);
}
protected
override
void
OnNavigatedTo
(
System.
Windows.
Navigation.
NavigationEventArgs args)
{
object
text;
if
(
MyappService.
State.
TryGetValue
(
"LeText"
,
out
text))
MyTextBox.
Text =
text as
string
;
base
.
OnNavigatedTo
(
args);
}
}
VII-A-2. Isolated Storage▲
Pour enregistrer des données, il est préférable d'utiliser l'Isolated Storage.
L'enregistrement est permanent.
'Isoladed' car seule votre application aura accès aux données, pas les autres applications.
Votre application ne pourra pas lire les données d'autres applications.
On peut utiliser 200 Mo par application.
Il y a deux manières d'utiliser l'Isolated Storage :
- l'IsolatedStorageSetting pour enregistrer des clé/valeurs ;
- l'IsolatedStorageFile pour enregistrer des répertoires et des fichiers.
Il faut au préalable inclure l'espace de noms :
using System.IO.IsolatedStorage;
L'IsolatedStorageSetting pour enregistre des clé/valeurs.
Exemple : enregistrer un nom dans le Setting sous la clé « name ».
Il faut instancier un objet de type IsolatedStorageSettings.ApplicationSettings. La méthode Add permet ensuite d'ajouter une clé/valeur. On peut ensuite lire la valeur correspondant à la clé.
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;
using
Microsoft.
Phone.
Controls;
using
System.
IO.
IsolatedStorage;
// Ajouter cette ligne
namespace
IsolatedStorage
{
public
partial
class
MainPage :
PhoneApplicationPage
{
//Instanciation de userSettings+++++++++++++++++
private
IsolatedStorageSettings userSettings =
IsolatedStorageSettings.
ApplicationSettings;
// Constructeur
public
MainPage
(
)
{
InitializeComponent
(
);
}
private
void
Enregistrer_Click
(
object
sender,
RoutedEventArgs e)
{
userSettings.
Add
(
"name"
,
"Philippe"
);
// On ajoute la clé/valeur
}
private
void
Lire_Click
(
object
sender,
RoutedEventArgs e)
{
string
name =
(
string
)userSettings[
"name"
];
//On lit la valeur de la clé "name"
textBlock1.
Text=
name;
}
}
}
On peut voir si une clé existe :
if
(
userSettings.
Contains
(
"name"
))
{
textBlock1.
Text=
"clé 'name' présente"
;
}
On peut ensuite modifier la valeur d'une clé :
userSettings[
"name"
]
=
"Paul"
;
On peut effacer une clé :
userSettings.
Remove
(
"name"
);
On peut effacer toutes les clés ou compter le nombre de clés.
userSettings.
Clear
(
);
tbResults.
Text =
"Count: "
+
userSettings.
Count
(
);
Exemple complet
On enregistre :
private
void
btnSaveSetting_Click
(
object
sender,
RoutedEventArgs e)
{
IsolatedStorageSettings settings =
IsolatedStorageSettings.
ApplicationSettings;
// txtInput is a TextBox defined in XAML.
if
(!
settings.
Contains
(
"userData"
))
{
settings.
Add
(
"userData"
,
txtInput.
Text);
}
else
{
settings[
"userData"
]
=
txtInput.
Text;
}
settings.
Save
(
);
}
Les données qui sont dans le Setting sont enregistrées automatiquement quand l'application (ou la page) qui utilise la classe se termine. On peut forcer l'enregistrement immédiat avec la méthode Save (voir dernière ligne de code qui précède).
On peut aussi enregistrer des objets. Attention, les objets doivent être « serializables ». La sérialisation consiste à transformer l'état d'une information qui est en mémoire sous la forme d'une suite d'informations qui pourra être enregistrée ou transportée.
Si on écrit soi-même la classe, il faut la rendre serializable : mettre [DataContract] avant la classe et [DataMember] avant les champs publics.
Il faut ajouter :
using
System.
Runtime.
Serialization;
[DataContract]
public
class
ElementDeListe
{
private
string
_Titre;
[DataMember]
public
string
Titre
{
get
{
return
_Titre;
}
set
{
if
(
value
!=
_Titre)
{
_Titre =
value
;
}
}
}
Exemple :
soit une classe « ElementDeListe » permettant d'instancier un objet currentCalcul.
On va enregistrer currentCalcul (dans OnNavigatedFrom par exemple) :
ElementDeListe currentCalcul;
private
IsolatedStorageSettings userSettings =
IsolatedStorageSettings.
ApplicationSettings;
if
(
userSettings.
Contains
(
"currentCalcul"
))
{
userSettings.
Remove
(
"currentCalcul"
);
}
userSettings.
Add
(
"currentCalcul"
,
currentCalcul);
// On ajoute la clé/valeur
userSettings.
Save
(
);
On va lire currentCalcul (dans OnNavigatedTo par exemple) :
currentCalcul =
(
ElementDeListe)userSettings[
"currentCalcul"
];
//On lit la valeur de la clé "name"
L'IsolatedStorageFile pour enregistrer des fichiers.
Pour pouvoir utiliser l'Isolated Storage il faut récupérer une référence vers le conteneur dédié à votre application. Cela se fait avec la méthode statique GetUserStoreForApplication de la classe IsolatedStorageFile.
À partir d'une instance de la classe IsolatedStorageFile, il est possible de manipuler répertoires et fichiers grâce aux méthodes.
FileExists.
CreateFile.
OpenFile.
DeleteFile.
DirectoryExists.
CreateDirectory.
DeleteDirectory.
Remove.
On peut écrire et lire des fichiers avec des IsolatedStorageFileStream.
Un « Stream » est un flux de données.
Vous pouvez lire à partir des flux. La lecture est le transfert de données d'un flux vers une structure de données (du texte avec ReadLine, par exemple).
Vous pouvez écrire dans les flux. L'écriture est le transfert de données d'une structure de données vers un flux (du texte avec ReadLine, par exemple).
using
System.
IO.
IsolatedStorage;
using
System.
IO;
private
void
EnregistreTexte_Button_Click
(
object
sender,
RoutedEventArgs e)
{
//Obtenir une référence de l'Isolated Storage
IsolatedStorageFile fileStorage =
IsolatedStorageFile.
GetUserStoreForApplication
(
);
//Créer un nouveau subdirectory
fileStorage.
CreateDirectory
(
"textFiles"
);
//Créer un nouveau StreamWriter pour écrire
StreamWriter fileWriter =
new
StreamWriter
(
new
IsolatedStorageFileStream
(
"textFiles
\\
newText.txt"
,
FileMode.
OpenOrCreate,
fileStorage));
//Ecrire le contenu de MonTexte.Text dans le fichier.
fileWriter.
WriteLine
(
MonTexteText.
Text);
//Fermer le StreamWriter.
fileWriter.
Close
(
);
}
private
void
LitTexte_Button_Click
(
object
sender,
RoutedEventArgs e)
{
//Obtenir une référence de l'Isolated Storage
IsolatedStorageFile fileStorage =
IsolatedStorageFile.
GetUserStoreForApplication
(
);
//Créer un nouveau StreamReader
StreamReader fileReader =
null
;
try
{
//Lire le fichier.
fileReader =
new
StreamReader
(
new
IsolatedStorageFileStream
(
"textFiles
\\
newText.txt"
,
FileMode.
Open,
fileStorage));
//Lire la ligne.
string
textFile =
fileReader.
ReadLine
(
);
//Mettre la ligne lue dans le textBlock.
MonTexte.
Text =
textFile;
fileReader.
Close
(
);
}
catch
{
//Si on lit avant d'avoir enregistrer!!.
viewText.
Text =
"Le fichier n'existe pas."
;
}
}
VII-A-3. LINQ to SQL, données sur le Web▲
Il est possible d'utiliser une base de données locale et de l'interroger avec LINQ to SQL.
Il y a plusieurs réseaux et technologies Web service que vous pouvez utiliser pour récupérer des données distantes :
HTTP classes ;
WCF services ;
WCF Data Services (OData services) ;
Windows Azure Services.
VII-B. Activation, désactivation, Tombstone.▲
Terminer une application
On se souvient que, sur la page principale (la première page) d'une application, si on fait « Retour » (Back bouton de gauche), on sort de l'application elle est fermée.
Si on veut utiliser de nouveau l'application, il faut la relancer.
Suspendre une application
Si par, contre, il y a un appel téléphonique ou si on fait « Démarrer » (bouton du milieu avec logo Windows), l'application est désactivée.
L'utilisateur est censé y revenir et poursuivre l'utilisation de l'application.
Avec le bouton « Back », on peut revenir dans l'application et poursuivre.
(Si on clique sur l'icône du programme, l'application est relancée et redémarre à zéro.)
Durant la désactivation, pendant un certain temps WP conserve toutes les données (c'est l'état dormant) ; si on utilise « Back », on va réactiver l'application et se retrouver dans la même page avec les données affichées dans les TextBox par exemple.
État Tombstone
Il n'est pas possible que toutes les applications désactivées restent au stade désactivé (dormant) éternellement.
Donc après un certain temps, et sans prévenir, quand WP a besoin de place, il fait une désactivation totale dite Tombstone (pierre tombale) ; l'OS tue le process ; et là, si ensuite on fait « Back », on se retrouve dans la page qu'on avait quittée mais on a perdu les informations contenues dans la page (et les données de l'application) qui est réactivée.
En effet, Windows Phone enregistre la pile de retour d'une application lors d'une désactivation Tombstone. Au moment de l'activation, il restaure uniquement la dernière page qui était active avant la désactivation Tombstone de l'application (mais pas les données, les objets ni les contenus des contrôles, des TextBox…).
L'état persistant de l'application (le contenu des contrôles visuels, les données, les objets) doit être enregistré par l'application avant la désactivation. C'est au programmeur de le faire.
Voici le cycle de vie d'une application WP donné par Microsoft :
Si on veut réactiver une application qui est tombstoned et poursuivre là où on était, l'OS se chargera de réafficher la dernière page mais il appartient au programmeur d'enregistrer l'état de la page (Page State= contenu des contrôles de la page) et les données de l'application (Application State) lors de la désactivation et de les restituer à la réactivation.
Voyons les évènements que propose WP pour faire cela.
A - Activated, Desactivated de l'application
Dans App.xaml.cs
Les évènement Launching (lancement) et Closing (fermeture) sont exécutés au lancement et à la fermeture de l'application. C'est classique.
Les évènement Activated (activé) et Desactivated (désactivé) sont moins habituels, ils sont exécutés quand on retourne à l'application et, au cours de l'exécution de votre application, quand on utilise le bouton « démarrer » (bouton du milieu) ou quand le téléphone sonne.
// 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)
{
}
Si l'application est lancée (launching) Application_Activated n'est pas exécuté. L'inverse est vrai.
Idem pour Deactivated et Closing.
Utilisez les événements Deactivated et Activated de l'application pour les données et objets de l'application.
On utilise dans ce cas l'application Setting.
Bien se souvenir que le stockage dans l'application Setting est temporaire et ne dure que le temps pendant lequel l'application est tombstoned. Quand l'application est totalement arrêtée, on perd l'application Setting. Si on veut un enregistrement persistant il faut utiliser l'IsolatedStorage.
Exemple simple utilisant l'ApplicationSettings :
private
void
Application_Deactivated
(
object
sender,
DeactivatedEventArgs e)
{
PhoneApplicationService.
Current.
State[
"MonObjet"
]
=
MonObjet ;
}
Pour la réactivation on peut utiliser « private void Application_activated ».
private
void
Application_Activated
(
object
sender,
DeactivatedEventArgs e)
{
if
(
PhoneApplicationService.
Current.
State.
ContainsKey
(
"MonObjet"
))
{
MonObjet =
(
string
)PhoneApplicationService.
Current.
State[
"MonObjet"
];
}
}
B - OnNavigatedFrom, OnNavigatedFrom de la page
On a dans la page les évènement OnNavigatedFrom et OnNavigatedTo que l'on peut surcharger.
OnNavigatedTo est exécuté lors de toutes les navigations vers la page (lorsque l'utilisateur arrive sur la page).
OnNavigatedFrom est exécuté lors de toutes les navigations sortant de la page (lorsque l'utilisateur quitte la page).
Le constructeur de page est appelé, lui, lors de la première navigation sur cette page (appelé une seule fois).
using
Microsoft.
Phone.
Shell;
using
System.
Threading;
namespace
CalculeTout
{
public
partial
class
PageMath :
PhoneApplicationPage
{
public
PageMath
(
)
{
//constructeur de la page, exécuté lors de la PREMIERE navigation vers la page
InitializeComponent
(
);
}
protected
override
void
OnNavigatedTo
(
System.
Windows.
Navigation.
NavigationEventArgs e)
{
//exécuté lors de toutes les navigations vers la page
base
.
OnNavigatedTo
(
e);
}
protected
override
void
OnNavigatedFrom
(
System.
Windows.
Navigation.
NavigationEventArgs e)
{
//exécuté lors de toutes les navigations sortant de la page
base
.
OnNavigatedFrom
(
e);
}
}
}
On utilise OnNavigatedFrom et OnNavigatedTo pour l'état de page (contenu des contrôles).
Je l'utilise aussi pour les objets propres à la page.
Exemple :
protected
override
void
OnNavigatedFrom
(
System.
Windows.
Navigation.
NavigationEventArgs e)
{
if
(
phoneApplicationPage.
State.
ContainsKey
(
"MyText"
))
{
phoneApplicationPage.
State.
Remove
(
"MyText"
);
}
// sauvegarder le contenu de textbox1
phoneApplicationPage.
State.
Add
(
MyText,
textbox1.
text);
base
.
OnNavigatedFrom
(
e);
}
protected
override
void
OnNavigatedTo
(
System.
Windows.
Navigation.
NavigationEventArgs e)
{
//Restaurer
if
(
phoneApplicationPage.
State.
ContainsKey
(
"MyText"
))
{
//Remettre le texte dans la textbox1
textbox1.
text=
phoneApplicationPage.
State[
"MyText];
}
base
.
OnNavigatedTo
(
e);
}
Comment savoir si l'application désactivée a un état Tombstone ?
Avec la méthode IsApplicationInstancePreserved :
private
void
Application_Activated
(
object
sender,
ActivatedEventArgs e)
{
if
(
e.
IsApplicationInstancePreserved)
{
// instance de l'application préservée, pas de tombstone, donc pas de récupération de données.
}
else
{
//Etat tombstone: il faut récupérer l'état
// Teste si une clé est dans State dictionary.
if
(
PhoneApplicationService.
Current.
State.
ContainsKey
(
"ApplicationDataObject"
))
{
//
ApplicationDataObject =
PhoneApplicationService.
Current.
State[
"ApplicationDataObject"
]
as
string
;
}
}
Dans le cas où on utilise un pattern MVVM, on peut sauvegarder et restaurer l'objet ViewModel lui-même.
public
partial
class
MainPage :
PhoneApplicationPage
{
public
MainPageViewModel MainPageViewModel {
get
;
set
;
}
private
bool
isFirstInstance;
// Constructor
public
MainPage
(
)
{
InitializeComponent
(
);
if
(!
IsolatedStorageSettings.
ApplicationSettings.
Contains
(
"ViewModel"
))
{
MainPageViewModel=
new
MainPageViewModel
(
);
DataContext =
MainPageViewModel;
isFirstInstance =
true
;
}
}
protected
override
void
OnNavigatedFrom
(
NavigationEventArgs e)
{
IsolatedStorageSettings.
ApplicationSettings[
"ViewModel"
]
=
MainPageViewModel;
base
.
OnNavigatedFrom
(
e);
}
protected
override
void
OnNavigatedTo
(
NavigationEventArgs e)
{
if
(
isFirstInstance) {
return
;
}
MainPageViewModel =
IsolatedStorageSettings.
ApplicationSettings[
"ViewModel"
]
as
MainPageViewModel;
DataContext =
MainPageViewModel;
base
.
OnNavigatedTo
(
e);
}
}
Le site CodePlex fourni en open Source TombstoneHelper.dll qui permet de sauvegarder et restaurer automatiquement l'état de la page, le contenu des contrôles d'une page .
Voir : tombstonehelper
Il faut charger tombstonehelper.dll dans le projet. Comme elle vient d'Internet et que Windows interdit d'utiliser une DLL non sure, Visual Studio refuse de l'utiliser, il faut donc cliquer droit sur la DLL dans l'explorateur, choisir « propriétés » ; en bas il y a un bouton qui débloque la DLL à vos risques et périls (attention, il y a des copies de la DLL dans les répertoires bin et release du projet, il faut les débloquer aussi si on ne la pas fait au départ).
Ensuite il faut ajouter la référence au projet : clic droit sur « Références» dans l'explorateur de solution puis « Ajouter une référence » ; ajouter tombstonehelper.dll.
Enfin il faut ajouter l'espace de noms nécessaire :
using
TombstoneHelper;
Pour sauver et restaurer la totalité des contrôles (TextBox, PasswordBoxe, CheckBoxe, RadioButton, Slider, ListBoxe et ScrollViewer, PAS les TextBlock !) c'est simple :
using
TombstoneHelper;
protected
override
void
OnNavigatingFrom
(
NavigatingCancelEventArgs e)
{
this
.
SaveState
(
e);
// <- first line
}
protected
override
void
OnNavigatedTo
(
NavigationEventArgs e)
{
this
.
RestoreState
(
);
// <- second line
}
Pour un type de contrôle :
this
.
SaveState
(
typeof
(
ScrollViewer));
//ou
this
.
SaveState
(
typeof
(
TextBox),
typeof
(
PasswordBox),
typeof
(
CheckBox));
//ou
this
.
SaveState<
TextBox,
PasswordBox,
CheckBox>(
);
Attention, les contrôles doivent avoir un nom (attribut « Name »).
On se souvient que les TextBlock ne sont pas sauvés (pour certains résultats j'ai préféré utiliser des TextBox avec l'attribut IsReadOnly à true plutôt que des TextBlock).
Microsoft.Phone.Shell.PhoneApplicationService.Current.ApplicationIdleDetectionMode = Microsoft.Phone.Shell.IdleDetectionMode.Disabled :
permet à votre application de ne pas se faire tombstonner quand le téléphone se met en veille, en clair votre application tourne derrière le lockscreen. C'est le comportement le plus proche d'un thread d'arrière-plan.
Microsoft.Phone.Shell.PhoneApplicationService.Current.UserIdleDetectionMode = Microsoft.Phone.Shell.IdleDetectionMode.Disabled :
permet de désactiver purement et simplement le lockscreen !
Pour tester dans l'émulateur l'effet Tombstone il faut passer par le menu « projet » puis « propriété de », onglet « déboguer ».
Si on ne coche pas, il y a désactivation sans Tombstone.
VII-C. Le pattern Model-View-ViewModel▲
Un pattern est un modèle de structure d'une application.
Le pattern M-V-VM (Model-View-ViewModel) permet une séparation entre
la couche dédiée aux objets métiers (Model),
à l'interface graphique (View),
à la logique (ViewModel).
C'est ce pattern qu'il est conseillé d'utiliser sur WP.
Il y a de très bon article sur le Web :
http://www.aymericlagier.com/2010/12/20/wp7-bien-commencer-a-developper-pour-windows-phone-7/.
Je dois vous avouer que, pour moi, cela semble très obscur, complexe et difficile à gérer. Mais cela n'engage que moi !
VII-D. Orientation▲
Le WP peut fonctionner :
en Portrait ou en LandScape (paysage).
Dans le code XAML de la page, on a les orientations supportées (Portrait, LandScape, PortraitOrLandscape).
Il y a aussi l'orientation initiale(Portrait, LandScape).
SupportedOrientations="Portrait"
Orientation="Portrait"
Il est possible de détecter un changement d'orientation en surchargeant la méthode OnOrientationChanged et en regardant l'OrientationChangedEventArgs.
public
partial
class
MainPage :
PhoneApplicationPage
{
// Constructeur
public
MainPage
(
)
{
InitializeComponent
(
);
}
protected
override
void
OnOrientationChanged
(
OrientationChangedEventArgs e)
{
OrientationTextBlock.
Text =
"On passe en mode
" + e.Orientation ;
base
.
OnOrientationChanged
(
e);
}
}
e.Orientation a une des valeurs de l'énumération PageOrientation (Bit Flags) :
- PageOrientation.PortraitUp ;
- PageOrientation.PortraitDown ;
- PageOrientation.LandscapeLeft ;
- PageOrientation.LandscapeRight.
L'énumération comporte aussi les valeurs PageOrientation.Portrait et PageOrientation.Landscape.
En utilisant un « ou » entre e.Orientation et PageOrientation.Landscape on determine si on est en LandscapeLeft ou LandscapeRight.
if
((
e.
Orientation &
PageOrientation.
Landscape) !=
0
)
{
}
C'est l'équivalent de :
if
(
e.
Orientation ==
PageOrientation.
Landscape ||
e.
Orientation ==
PageOrientation.
LandscapeLeft ||
e.
Orientation ==
PageOrientation.
LandscapeRight)
{
}
C'est l'endroit parfait pour modifier les dimensions et positions des contrôles en fonction de l'orientation.
protected
override
void
OnOrientationChanged
(
OrientationChangedEventArgs e)
{
// Landscape
if
((
e.
Orientation &
PageOrientation.
Landscape) !=
0
)
{
//Positionner en mode paysage
}
// Portrait
else
{
//Positionner en mode portrait
}
base
.
OnOrientationChanged
(
e);
}
Le plus simple pour positionner les contrôles dans les deux orientations est de les mettre dans un StackPanel qui lui-même sera dans un ScrollViewer. Comme cela, en mode paysage, les contrôles peuvent déborder en bas.
VII-E. Lanceur d'applications internes▲
Impossible de lancer, à partir de votre application, une de vos autres applications ou même une application présente sur votre WP comme Internet Explorer (sécurité oblige).
Seules exceptions : Les Launchers (lanceurs) et Choosers (sélecteurs) permettent d'accéder aux Windows Phone applications. Par exemple, si vous voulez chercher un contact à partir de votre application, il faut utiliser EmailAddressChooserTask.
On peut ainsi, à partir de votre application, envoyer un mail ou un coup de téléphone, prendre une photo, ouvrir une page Web.
La différence entre Launchers et Choosers est que les Launchers ne retournent pas de données contrairement aux Choosers. L' EmailComposeTask Launcher par exemple démarre l'email application qui se fermera simplement. La CameraCaptureTask Chooser démarre l'application « camera », à sa sortie cette application fournit la photo qui à été prise.
Il faut ajouter :
using
Microsoft.
Phone.
Tasks;
Launchers (lanceur). Voici les lanceurs :
EmailComposeTask permet d'envoyer un mail ;
MarketplaceDetailTask permet de lancer le « Windows Phone Marketplace client application » et affiche le détail d'un produit du Market Place ;
MarketplaceHubTask Permet de lancer le « Windows Phone Marketplace client application » ;
MarketplaceSearchTask permet de lancer le « Windows Phone Marketplace client application » et de voir le résultat d'une recherche sur un thème ;
MediaPlayerLauncher permet de lancer le media player ;
PhoneCallTask permet de lancer la « Phone application » et de faire un appel téléphonique ;
SearchTask permet de lancer le « web search application » pour rechercher sur le Web ;
SmsComposeTask permet de lancer le « Messaging application » et de faire un nouveau message SMS ;
WebBrowserTask permet de lancer le browser Internet.
Il faut instancier le lanceur, renseigner certaines propriétés puis appliquer la méthode Show.
Exemple 1 : appeler un numéro à partir de votre application.
// Instancier le launcher.
PhoneCallTask phoneCallTask =
new
PhoneCallTask
(
);
// Renseigner les propriétés.
phoneCallTask.
PhoneNumber =
"01234567"
;
phoneCallTask.
DisplayName =
"Philippe"
;
// Lancer la 'phone dialer application'.
phoneCallTask.
Show
(
);
On a l'écran :
Puis la page habituelle du téléphone.
Exemple 2 : faire une recherche sur le Web.
// Instancier le launcher.
SearchTask searchTask =
new
SearchTask
(
);
// Renseigner la propriété SearchQuery avec le texte à chercher.
searchTask.
SearchQuery =
"Cours Windows Phone"
;
// Lancer la recherche.
searchTask.
Show
(
);
On a l'écran :
On a ensuite les réponses à la recherche "cours Windows Phone" sur le Web :
Choosers (sélecteurs). Voici les Choosers
CameraCaptureTask lance la « Camera application ». Permet de récupérer la photo prise ;
EmailAddressChooserTask lance la « Contacts application ». On récupère l'adresse du contact sélectionné par l'utilisateur ;
PhoneNumberChooserTask lance la « Contacts application ». On récupère le numéro de téléphone du contact sélectionné par l'utilisateur ;
PhotoChooserTask lance la « Photo Chooser application ». Retourne la photo sélectionnée ;
SaveEmailAddressTask permet de sauvegarder une adresse mail ;
SavePhoneNumberTask permet de sauvegarder un numéro de téléphone ;
GameInviteTask permet d'accepter un joueur dans un jeu multi joueur ;
SaveRingtoneTask utilise le « save ringtone task » pour permettre à l'utilisateur de sauvegarder un fichier audio file dans le « system ringtones » list (les sonneries).
Il faut instancier le Chooser, instancier un EventHandle sur l'évènement Completed du Chooser, renseigner certaines propriétés puis appliquer la méthode Show.
Il faut récupérer la valeur retournée par le Chooser dans la fonction évènement déclenchée par Completed (Completed survient quand l'application Chooser est terminée).
Exemple 1 : récupérer un numéro de téléphone dans les contacts.
public
partial
class
MainPage :
PhoneApplicationPage
{
// Instanciation d'un PhoneNumberChooserTask
PhoneNumberChooserTask numberChooser;
// Constructor
public
MainPage
(
)
{
InitializeComponent
(
);
numberChooser =
new
PhoneNumberChooserTask
(
);
// Instanciation d'un EventHandler sur l'évènement Completed du Chooser
numberChooser.
Completed +=
new
EventHandler<
PhoneNumberResult>(
numberChooser_Completed);
}
void
numberChooser_Completed
(
object
sender,
PhoneNumberResult e)
{
// Est exécuté lorsque l'évènement Completed sur le Chooser survient.
// Check if TaskResult is a success
if
(
e.
TaskResult ==
TaskResult.
OK)
{
// Affiche le numéro de téléphone dans le TextBlock txtPhoneNumber
txtPhoneNumber.
Text +=
e.
PhoneNumber;
//Récupérer le numéro de téléphone du contact
}
}
//Lancer la liste des contacts pour récuperer un numéro de téléphone
private
void
ButtonChooser_Click
(
object
sender,
RoutedEventArgs e)
{
try
{
// Démarre le Chooser.
numberChooser.
Show
(
);
}
catch
(
System.
InvalidOperationException ex)
{
// Catch l' exception, pas besoin de traitement.
}
}
}
Exemple 2 : à partir de mon application, prendre une photo puis dans mon application, l'afficher.
//Instanciation d'un CameraCaptureTask
CameraCaptureTask PhotoCaptureTask;
PhotoCaptureTask =
new
CameraCaptureTask
(
);
// Instanciation de l' EventHandler sur Completed
PhotoCaptureTask.
Completed +=
new
EventHandler<
PhotoResult>(
PhotoCaptureTask_Completed);
//Lancer la prise de photo.
try
{
PhotoCaptureTask.
Show
(
);
}
catch
(
System.
InvalidOperationException ex)
{
MessageBox.
Show
(
"Erreur, impossible de prendre la photo."
);
}
Maintenant, on a la fonction évènement qui survient quand la tache « photo » est terminée.
void
PhotoCaptureTask_Completed
(
object
sender,
PhotoResult e)
{
if
(
e.
TaskResult ==
TaskResult.
OK)
{
//Message box indiquant la longueur de l'image
MessageBox.
Show
(
e.
ChosenPhoto.
Length.
ToString
(
));
//Afficher l'image prise dans l'image controle nommé myImage.
System.
Windows.
Media.
Imaging.
BitmapImage bmp =
new
System.
Windows.
Media.
Imaging.
BitmapImage
(
);
bmp.
SetSource
(
e.
ChosenPhoto);
myImage.
Source =
bmp;
}
}
Exemple 3 : à partir de mon application, enregistrer un contact dans les contacts.
//Instanciation d'un SaveContactTask
SaveContactTask saveContactTask;
saveContactTask =
new
SaveContactTask
(
);
// Instanciation de l' EventHandler sur Completed
saveContactTask.
Completed +=
new
EventHandler<
SaveContactResult>(
saveContactTask_Completed);
//Lancer l'enregistrement du contact.
try
{
saveContactTask.
FirstName =
"Philippe"
;
saveContactTask.
LastName =
"Lasserre"
;
saveContactTask.
MobilePhone =
"012345678"
;
saveContactTask.
Show
(
);
}
catch
(
System.
InvalidOperationException ex)
{
MessageBox.
Show
(
"Impossible d'enregister le contact ."
);
}
Maintenant, on a la fonction évènement qui survient quand la tache est terminée.
void
saveContactTask_Completed
(
object
sender,
SaveContactResult e)
{
switch
(
e.
TaskResult)
{
//contact enregistré
case
TaskResult.
OK:
MessageBox.
Show
(
"Contact enregistré."
);
break
;
//Annuler par l'utilisateur
case
TaskResult.
Cancel:
MessageBox.
Show
(
"Enregistrement annulé."
);
break
;
//Impossible d'enregistrer
case
TaskResult.
None:
MessageBox.
Show
(
"Impossible d'enregister."
);
break
;
}
}
Dans le chapitre « Utiliser un WebBrowser » il y a un exemple d'utilisation du WebBrowseTask pour visionner des pages du Web.
VII-F. Les thèmes▲
Dans les paramètres du Windows Phone on peut choisir :
l'arrière plan light ou dark (clair ou sombre),
la couleur d'accentuation (11 couleurs proposées).
Voici les 10 couleurs version 7.1 (en 7.0 magenta et lime sont légèrement différents), en plus il y a une onzième couleur réservée à l'opérateur ou au fabriquant (sur le mien c'est « Orange F »).
Ces couleurs se retrouvent dans les ressources Windows Phones : la couleur de fond est : PhoneBackgroundColor.
La couleur d'accentuation est : PhoneAccentColor.
Pour le texte : PhoneForegroundColor.
Dans le code XAML quand on utilise des ressources comme couleur, ce sont les « Brush » qu'il faut utiliser et pas les couleurs.
PhoneAccentBrush :Brush d'accentuation définie par le thème.
PhoneForegroundBrush :Brush utilisée pour les éléments de premier plan tels que le texte ou les icônes.
PhoneBackgroundBrush :Brush utilisée pour les éléments d'arrière-plan.
PhoneContrastBackgroundBrush :Brush de fond utilisée pour mettre en contraste (fond des menus contextuels par exemple).
PhoneContrastForegroundBrush :Brush de premier plan utilisée pour les éléments à mettre en contraste. Par exemple les textes des menus contextuels.
PhoneDisabledBrush :Brush des éléments désactivés.
PhoneSubtleBrush :Brush partiellement transparente qui permet de mettre en retrait des éléments visuels moins importants.
PhoneBorderBrush :Brush de bordure des contrôles TextBox, CheckBox, PasswordBox, et RadioButton.
PhoneSemitransparentBrush :Brush presque transparente permettant de faire ressortir des éléments de couleurs similaires (par exemple du texte blanc sur une image claire).
Exemple :
<TextBlock
Height
=
"434"
Name
=
"TextLong"
Foreground
=
"{StaticResource PhoneAccentBrush} />"
On peut aussi utiliser les styles :
PhoneTextNormalStyle qui utilise judicieusement une couleur (PhoneForegroundBrush) qui contraste bien avec la PhoneBackgroundColor du thème. Si le background est dark, PhoneTextNormalStyle donnera du texte blanc (FontSize : 20).
Il y a aussi PhoneTextTitle1Style (FontSize : 72, PhoneForegroundBrush), PhoneTextTitle2Style (FontSize : 32, PhoneForegroundBrush)…
<TextBox
Name
=
"resultat"
Style
=
"{StaticResource PhoneTextNormalStyle}"
/>
On se rend compte qu'à partir de la couleur d'accentuation et du fond, les styles s'adaptent pour être lisibles et cohérents.
Sélecteur de ressource : dans la fenêtre « Propriétés », pour donner une valeur ressource à la propriété d'un contrôle (BackGround par exemple), on peut ouvrir le sélecteur de ressource en cliquant sur le carré à côté du nom de la propriété :
Dans le menu, choisir « Appliquer la ressource ».
Double-cliquer sur la ressource désirée.
Comment utiliser les couleurs du thème choisi par l'utilisateur ?
On va créer une page avec un fond dégradé à partir des deux couleurs PhoneBackgroundColor et PhoneAccentColor.
Le titre de la page utilisera le style PhoneAccentColor. Le texte affiché aura le Style PhoneTextNormalStyle.
<!--
LayoutRoot est la grille racine où tout le contenu de la page est placé-->
<
Grid x:
Name=
"LayoutRoot"
Background=
"Transparent"
>
<
Grid.
RowDefinitions>
<
RowDefinition Height=
"Auto"
/>
<
RowDefinition Height=
"*"
/>
</
Grid.
RowDefinitions>
<!--
TitlePanel contains the name of the application and page title-->
<
Rectangle Stroke=
"Black"
Grid.
RowSpan=
"2"
>
<
Rectangle.
Fill>
<
LinearGradientBrush EndPoint=
"0.5,1"
StartPoint=
"0.5,0"
>
<
GradientStop Color=
"{StaticResource PhoneBackgroundColor}"
Offset=
"0"
/>
<
GradientStop Color=
"{StaticResource PhoneAccentColor}"
Offset=
"1"
/>
</
LinearGradientBrush>
</
Rectangle.
Fill>
</
Rectangle>
<!--
TitlePanel contains the name of the application and page title-->
<
StackPanel x:
Name=
"TitlePanel"
Grid.
Row=
"0"
Margin=
"12,17,0,28"
>
<
TextBlock x:
Name=
"ApplicationTitle"
Text=
"Windows Phone"
Style=
"{StaticResource PhoneTextNormalStyle}"
/>
<
TextBlock x:
Name=
"PageTitle"
Text=
"Les thèmes"
Margin=
"9,-7,0,0"
Style=
"{StaticResource PhoneTextTitle1Style}"
>
<
TextBlock.
Foreground>
<
SolidColorBrush Color=
"{StaticResource PhoneAccentColor}"
/>
</
TextBlock.
Foreground>
</
TextBlock>
</
StackPanel>
<!--
ContentPanel -
place additional content here-->
<
Grid x:
Name=
"ContentPanel"
Grid.
Row=
"1"
Margin=
"12,0,12,0"
>
<
TextBlock Height=
"601"
TextWrapping=
"Wrap"
HorizontalAlignment=
"Left"
Margin=
"0,6,0,0"
x:
Name=
"textBlock1"
Style=
"{StaticResource PhoneTextNormalStyle}"
Text=
"Il y a le 'designer' à gauche qui permet de dessiner l'interface que verra l'utilisateur.
Le designer génère le code XAML correspondant,
on
le voit à droite,
il décrit l'interface en XAML.
On peut aussi écrire directement du XAML à droite,
ce qui modifie l'interface dans le designer.."
VerticalAlignment=
"Top"
Width=
"468"
/>
</
Grid>
</
Grid>
Voici le résultat : avec un fond foncé et une couleur d'accentuation marron puis avec un fond clair et une couleur d'accentuation bleue.
Le résultat est parfait, le texte toujours lisible quelque soit le choix du fond et de la couleur d'accentuation.
Si on n'indique rien comme style ou couleur, par défaut le thème courant est utilisé : texte blanc si le fond est « dark » et texte noir si le fond est « light » plus couleur d'accentuation.
Si on indique des couleurs, pour le fond par exemple, il faut bien veiller à ce que la couleur du texte soit lisible et tester son application avec les différents fonds et couleurs d'accentuation.
Comment savoir si on a un Background Dark ou Light ?
// Determine la visibilité du dark background.
Visibility darkBackgroundVisibility =
(
Visibility)Application.
Current.
Resources[
"PhoneDarkThemeVisibility"
];
// Afficher dans un textbox le theme background .
if
(
darkBackgroundVisibility ==
Visibility.
Visible)
{
textBlock1.
Text =
"background = dark"
;
}
else
{
textBlock1.
Text =
"background = light"
;
}
Comment connaître la couleur d'accentuation ?
Color currentAccentColorHex =
(
Color)Application.
Current.
Resources[
"PhoneAccentColor"
];
VII-G. Vibreur▲
Il faut inclure l'espace de noms Microsoft.Devices et instancier un VibrateControler avec la méthode static Default.
using
Microsoft.
Devices;
VibrateController vc =
VibrateController.
Default;
vc.
Start
(
TimeSpan.
FromMilliseconds
(
100
));
Il y a une exception si l'argument de Start est négatif ou supérieur à cinq secondes.
On a aussi la méthode Stop.
Combien de temps faire vibrer ?
100 ms pour signaler la pression d'une touche.
300 ms pour attirer l'attention de l'utilisateur.
2 s : non !
VII-H. Localisation▲
Le Windows Phone utilise trois moyens pour se localiser :
- avec les relais émetteurs cellulaires ;
- avec la Wi-Fi ;
- avec les satellites GPS.
Avec les relais c'est rapide mais peu précis. Avec le GPS c'est précis mais lent et cela ne marche pas à l'intérieur. Avec la WiFi, il faut être en ville.
Les informations des relais et de la Wi-Fi arrivent en quelques secondes ; pour le GPS c'est quelques minutes.
Le WP utilise les trois (il faut, dans les paramètres du WP, que la localisation soit activée).
Comment trouver sa localisation (latitude, longitude, vitesse, orientation, altitude) ?
Il faut charger la référence (la DLL) System.Device (clic droit sur « Références » dans l'explorateur de projet puis « Ajouter une référence »).
Puis ajouter l'espace de noms System.Device.Localisation.
Il faut instancier un GeoCoordinateWatcher, créer un EventHandler sur l'évènement PositionChanged.
À chaque fois que la position du WP change, l'évènement PositionChanged est exécuté et donc la fonction « gcw_PositionChanged ».
Il faut démarrer la localisation avec la méthode Start.
On affiche ensuite la latitude, la longitude, la vitesse, la direction en degrés par rapport au nord géographique, l'altitude (dans cinq TextBlock).
using
System.
Device.
Location;
namespace
localisation
{
public
partial
class
MainPage :
PhoneApplicationPage
{
GeoCoordinateWatcher GeoCoordinater;
// Constructeur
public
MainPage
(
)
{
InitializeComponent
(
);
GeoCoordinater=
new
GeoCoordinateWatcher
(
);
GeoCoordinater.
PositionChanged +=
new
EventHandler<
GeoPositionChangedEventArgs<
GeoCoordinate>>(
gcw_PositionChanged);
GeoCoordinater.
Start
(
);
}
void
gcw_PositionChanged
(
object
sender,
GeoPositionChangedEventArgs<
GeoCoordinate>
e)
{
//Coordonnées
latitude.
Text =
e.
Position.
Location.
Latitude.
ToString
(
);
longitude.
Text =
e.
Position.
Location.
Longitude.
ToString
(
);
//Vitesse
vitesse.
Text=
e.
Position.
Location.
Speed.
ToString
(
"0.0"
) +
" métres par seconde"
;
//Direction en degrés par rapport au nord géographique.
course.
Text =
e.
Position.
Location.
Course.
ToString
(
"0.0"
);
//Altitude
altitude.
Text =
e.
Position.
Location.
Altitude.
ToString
(
"0.0"
)+
" métres"
;
}
}
}
Pour tester l'application dans l'émulateur, il faut ouvrir la fenêtre suivante grâce au bouton « >> » situé à droite de l'émulateur, puis cliquer sur l'onglet « Localisation » :
Dans la zone de recherche, en haut à gauche, il faut saisir un lieu, cela affiche une carte. Le fait de cliquer sur la carte affiche en bas les coordonnées du lieu.
Ces coordonnées seront utilisées dans l'émulateur (pas de vitesse, direction et altitude).
Afin d'éviter les plantages, on peut gérer le Status du GeoCoorditaneWatcher afin de savoir si la localisation est activée, si le WP reçoit des données :
Il faut créer un évènement :
// Ajouter en dessous du précédent EventHandler
GeoCoordinater.
StatusChanged +=
new
EventHandler<
GeoPositionStatusChangedEventArgs>(
watcher_StatusChanged);
//
static
void
watcher_StatusChanged
(
object
sender,
GeoPositionStatusChangedEventArgs e)
{
switch
(
e.
Status)
{
case
GeoPositionStatus.
Initializing:
System.
Diagnostics.
Debug.
WriteLine
(
"Localisation en cours"
);
break
;
case
GeoPositionStatus.
Ready:
System.
Diagnostics.
Debug.
WriteLine
(
"Location effectuée"
);
break
;
case
GeoPositionStatus.
NoData:
System.
Diagnostics.
Debug.
WriteLine
(
"Pas de données"
);
break
;
case
GeoPositionStatus.
Disabled:
System.
Diagnostics.
Debug.
WriteLine
(
"Localisation désactivée"
);
break
;
}
}
On peut ajouter un paramètre lors de l'initialisation pour forcer à plus de précision :
GeoCoordinateWatcher GeoCoordinater;
GeoCoordinater =
new
GeoCoordinateWatcher
(
GeoPositionAccuracy.
High);
La valeur par défaut est « Default ».
La précision High peut nuire aux performances.
On peut aussi indiquer la distance de déplacement pour déclencher PositionChanged :
GeoCoordinater.
MovementThreshold =
10
.
0f
;
VII-I. Accéléromètre▲
Windows Phone contient un espace de noms dédié à la gestion et l'exploitation en temps réel des données de l'accéléromètre du téléphone. L'accéléromètre mesure l'intensité et la direction de la force d'accélération appliquée sur le téléphone. La valeur de cette force suivant les axes X, Y, Z, se retrouve dans une variable décimale (valeurs de -1.0 à 1.0), l'unité étant le « g » (1g = attraction de la force terrestre).
Voici le sens des vecteurs X, Y, Z :
L'attraction terrestre ayant la valeur 1, voici les valeurs x y z pour les divers positions du phone.
Dans le code il faut inclure l'espace de noms nécessaire :
using
Microsoft.
Devices.
Sensors;
Il faut ensuite instancier l'accéléromètre et ajouter un EventHandler sur l'évènement :
public
partial
class
MainPage :
PhoneApplicationPage
{
// Constructor
Accelerometer monaccelerometer =
new
Accelerometer
(
);
monaccelerometer.
Start
(
);
monaccelerometer.
ReadingChanged +=
new
EventHandler<
AccelerometerReadingEventArgs>(
myHandler);
void
myHandler
(
object
sender,
AccelerometerReadingEventArgs e)
{
Deployment.
Current.
Dispatcher.
BeginInvoke
((
) =>
updateMyScreen
(
e));
}
void
updateMyScreen
(
AccelerometerReadingEventArgs e)
{
// updates the textblocks
xreadout.
Text =
e.
X.
ToString
(
"0.00"
);
yreadout.
Text =
e.
Y.
ToString
(
"0.00"
);
zreadout.
Text =
e.
Z.
ToString
(
"0.00"
);
}
Pour tester l'application dans l'émulateur, il faut ouvrir la fenêtre suivante grâce au bouton'>>" situé à droite de l'émulateur puis cliquer sur l'onglet « Accéléromètre » :
En déroulant la liste « Orientation » en bas à gauche, on peut choisir différentes valeurs de X, Y, Z.
VII-J. Internet, WebBrowser, WebClient▲
Le Windows Phone est-il connecté à internet ?
using
Microsoft.
Phone.
Net.
NetworkInformation;
/...
MessageBox.
Show
(
NetworkInterface.
NetworkInterfaceType.
ToString
(
));
NetworkInterfaceType retourne :
None si pas de connexion ;
Wireless80211 si connexion Wi-Fi ;
Ethernet ;
MobileBroadbandGSM ou MobileBroadbandCDMA si réseau téléphone mobile.
Comment charger dans un Browser une page qui est sur le Web ?
On peut utiliser un lanceur de tache pour utiliser l'application « WebBrowser ». Il faut ajouter un espace de noms :
using
Microsoft.
Phone.
Tasks;
Ensuite il faut utiliser un WebBrowserTask :
WebBrowserTask webBrowserTask =
new
WebBrowserTask
(
);
webBrowserTask.
Uri =
new
Uri
(
"http://msdn.microsoft.com"
,
UriKind.
Absolute);
webBrowserTask.
Show
(
);
On peut mettre un contrôle « WebBrowser » dans la page.
En allant le chercher dans la boîte à outils :
<
phone
:
WebBrowser
Height
=
"426"
HorizontalAlignment
=
"Left"
Margin
=
"26,49,0,0"
Name
=
"webBrowser1"
VerticalAlignment
=
"Top"
Width
=
"407"
/>
En ajoutant la source :
<
phone
:
WebBrowser
Height
=
"426"
HorizontalAlignment
=
"Left"
Margin
=
"26,49,0,0"
Name
=
"webBrowser1"
VerticalAlignment
=
"Top"
Width
=
"407"
Source
=
"http://www.bing.com"
/>
ou en instanciant un WebBrowser dans le code C# :
using
Microsoft.
Phone.
Controls;
WebBrowser webBrowser1 =
new
WebBrowser
(
);
Ensuite on peut naviguer vers une page.
webBrowser1.
Navigate
(
new
Uri
(
"http://msdn.microsoft.com"
,
UriKind.
Absolute));
Pas de GoBack, GoFoward...
Dans ce WebBrowser on peut aussi afficher du HTML grâce à NavigateToString :
webBrowser1.
NavigateToString
(
"<html><head><meta name='viewport' content='width=480, user-scalable=yes' />
</
head><
body>
Du texte en HTML</
body></
html>
");
SaveToString retourne une string contenant le code HTML de la page.
Pour charger un fichier situé sur Internet, on peut utiliser un WebClient.
Un WebClient a des méthodes pour l'envoi de données à une ressource locale, intranet ou Internet identifiée par un URI ou pour la réception de données en provenance de cette ressource.
Ici on va charger une image :
{
WebClient MywebClient =
new
WebClient
(
);
MywebClient.
OpenReadCompleted +=
OnWebClientOpenReadCompleted;
MywebClient.
OpenReadAsync
(
new
Uri
(
"http://www.mysite.com/Media/myimage.jpg"
));
}
void
OnWebClientOpenReadCompleted
(
object
sender,
OpenReadCompletedEventArgs args)
{
if
(!
args.
Cancelled &&
args.
Error==
null
)
{
BitmapImage bmp =
new
BitmapImage
(
);
bmp.
SetSource
(
args.
Result);
image.
Source =
bmp;
}
}
VII-K. Radio FM▲
Simple pour mettre en marche la radio FM.
using
Microsoft.
Devices.
Radio;
puis
FMRadio.
Instance.
PowerMode=
RadioPowerMode.
On;
FMRadio.
Instance.
Frequency=
100
.
3
;
VII-L. Minuterie▲
On peut utiliser une minuterie grâce à la classe DispatcherTimer de espace de noms System.Windows.Threading du framework.
Elle déclenche un évènement Tick tous les « Interval » de temps.
Créons une application qui affiche date, heure, minute, seconde et se met à jour toutes les secondes.
using
System.
Windows.
Threading;
//..
//Instanciation d'un timer.
DispatcherTimer dt =
new
DispatcherTimer
(
);
//On indique l'intervalle de temps entre les évènements Tick, ici 1 s.
dt.
Interval =
TimeSpan.
FromSeconds
(
1
);
//On indique quelle fonction exécuter quand le Timer déclenche Tick.
dt.
Tick +=
OnTimerSeconde;
//On démarre le Timer
tmr.
Start
(
);
void
OnTimerSeconde
(
object
sender,
EventArgs args)
//Fonction exécutée toutes les secondes
{
//On affiche dans le textBlock nommé 'Clock' la date et heure, minute, seconde
//Mise à jour toutes les secondes donc.
Clock.
Text =
DateTime.
Now.
ToString
(
);
}
Les opérations DispatcherTimer sont placées dans la file d'attente Dispatcher. Le moment d'exécution de l'opération DispatcherTimer dépend des autres travaux de la file d'attente et de leur priorité ; ainsi l'évènement Tick se produira peut-être pas exactement durant l'intervalle de temps défini, au moins après un intervalle, parfois plus.
Il s'exécute dans le thread interface utilisateur (UI).
Il existe un autre Timer dans l'espace de noms System.Threading :
Il fonctionne dans un thread d'arrière-plan.
using
System.
Threading;
Timer tm =
new
Timer
(
TimerCallBack);
// TimerCallBack est la méthode de rappel à exécuter
tm.
Change
(
100
,
1000
);
//Premier paramètre :
//Délai d'attente, en millisecondes ou en TimeSpan, avant l'appel de la méthode de rappel
//spécifiée au moment de la construction de Timer.
//Spécifiez Timeout.Infinite pour empêcher le redémarrage de la minuterie.
//Spécifiez zéro (0) pour redémarrer la minuterie immédiatement.
//Second paramètre:
//Intervalle de temps, en millisecondes ou en TimeSpan, entre les appels de la méthode de rappel
//...
public
void
TimerCallBack
(
object
state)
{
//méthode de rappel exécutée toutes les secondes
this
.
Dispatcher.
BeginInvoke
(
delegate
(
) {
OnTimer
(
);
}
);
}
void
OnTimer
(
)
{
// Méthode affichant l'heure
Clock.
Text =
DateTime.
Now.
ToString
(
);
}
Si on avait voulu afficher l'heure dans la méthode TimerCallBack, il y aurait eu levée d'une exception « Invalid cross-thread access » car le Timer est dans un thread différent du thread de l'interface. Le thread du Timer doit déléguer le travail au Dispatcher associé au thread d'interface utilisateur grâce à BeginInvoke.
System.Threading.Timer n'est pas recommandé pour les scénarios dans lesquels l'interface d'utilisateur doit être actualisée, parce que ses callback ne se produisent pas sur le thread d'interface d'utilisateur. Système.Windows.DispatcherTimer est un meilleur choix dans ces scénarios, parce que ses événements sont levés sur le thread d'interface d'utilisateur.
VII-M. Applications en tâche de fond : alarme, rappel▲
La classe « Alarme » de l'espace de noms « Microsoft.Phone.Scheduler » permet de créer une alarme.
On va créer une alarme nommée « MonAlarme » ; elle se déclenchera dans 20 s et affichera "Debout".
using
Microsoft.
Phone.
Scheduler;
Alarm alarm =
new
Alarm
(
"MonAlarme"
);
alarm.
BeginTime =
DateTime.
Now.
AddSeconds
(
20
);
alarm.
RecurrenceType =
RecurrenceInterval.
Daily;
alarm.
Content =
"Debout."
;
alarm.
Sound =
new
Uri
(
"sound.wav"
,
UriKind.
Relative)
ScheduledActionService.
Add
(
alarm);
RecurrenceInterval peut être Daily, Weekly, Monthly, Yearly, None, EndOfMonth.
ExpirationTime indique à quel moment arrêter le service.
Sound permet d'ajouter l'URI d'un fichier son qui sera exécuté lors de l'alarme. Le fichier son doit être dans le répertoire source et chargé dans l'application comme contenu.
Si on relance l'application une seconde fois et qu'on veut créer de nouveau une alarme nommée « MonAlarme », il y a levée d'une exception car elle existe toujours (même si on a quitté l'application).
Il est possible de détruire cette alarme :
ScheduledActionService.
Remove
(
"MonAlarme"
);
On peut aussi utiliser un Reminder ou rappel : chaque 2 juin à 21 h 40 rappeler que c'est l'anniversaire de « Mimi ».
Reminder reminder =
new
Reminder
(
"Anniverssaire"
)
{
BeginTime =
new
DateTime (
2012
,
6
,
2
,
21
,
40
,
0
) ,
Content =
"Anniverssaire de Mimi"
,
Title =
"Anniversaire"
,
RecurrenceType =
RecurrenceInterval.
Yearly,
NavigationUri =
new
Uri
(
"/MainPage.xaml"
,
UriKind.
Relative)
};
ScheduledActionService.
Add
(
reminder);
VII-N. Informations diverses▲
Grâce à DeviceExtendedProperties de l'espace de noms Microsoft.Phone.Info on peut lire des informations sur le téléphone : fabricant, nom, version du Firmware et du Hardware, mémoire totale, mémoire utilisée par l'application, « ApplicationPeakMemoryUsage », ID du téléphone.
using
Microsoft.
Phone.
Info;
//Fabriquant du téléphone
MessageBox.
Show (
DeviceExtendedProperties.
GetValue
(
"DeviceManufacturer"
).
ToString
(
));
//Nom du téléphone
MessageBox.
Show (
DeviceExtendedProperties.
GetValue
(
"DeviceName"
).
ToString
(
));
//Version du Firmware
MessageBox.
Show (
DeviceExtendedProperties.
GetValue
(
"DeviceFirmwareVersion"
).
ToString
(
));
//Version du Harsware
MessageBox.
Show (
DeviceExtendedProperties.
GetValue
(
"DeviceHardwareVersion"
).
ToString
(
));
//Mémoire total du portable
MessageBox.
Show (
DeviceExtendedProperties.
GetValue
(
"DeviceTotalMemory"
).
ToString
(
));
//retourne un long
//Mémoire utilisée par l'application
MessageBox.
Show (
DeviceExtendedProperties.
GetValue
(
"ApplicationCurrentMemoryUsage"
).
ToString
(
));
//retourne un long
object
tryValue;
if
(
DeviceExtendedProperties.
TryGetValue
(
"ApplicationPeakMemoryUsage"
,
out
tryValue))
{
MessageBox.
Show (
tryValue.
ToString
(
));
}
//retourne un tableau de 20 bytes correspondant à l'ID unique du téléphone
MessageBox.
Show (
DeviceExtendedProperties.
GetValue
(
"DeviceUniqueId"
).
ToString
(
));
//A faire : caster le tableau pour le rendre affichable
Il existe aussi DeviceStatus (à partir de WP 7.1) qui permet de voir toutes les informations précédentes avec une syntaxe plus simple.
Mais en plus :
PowerSource qui retourne Battery ou External (secteur) ;
ApplicationMemoryUsageLimit (mémoire que l'application peut utiliser) ;
IsKeyboardPresent IsKeyboardDeployed.
//On retrouver le précédentes information avec une syntaxe plus simple
MessageBox.
Show
(
DeviceStatus.
ApplicationCurrentMemoryUsage.
ToString
(
));
//En plus
MessageBox.
Show
(
DeviceStatus.
PowerSource.
ToString
(
));
MessageBox.
Show
(
DeviceStatus.
ApplicationMemoryUsageLimit.
ToString
(
));
MessageBox.
Show
(
DeviceStatus.
IsKeyboardPresent.
ToString
(
));
//et IsKeyboardDeployed
Le portable supporte-t-il le smooth streaming des multi-resolution encoded video ?
MessageBox.
Show
(
MediaCapabilities.
IsMultiResolutionVideoSupported.
ToString
(
));