A la découverte d'Avalon.
Partie III : Les contrôles usuels dans Avalon.
Date de publication : 30/09/2005
Par
Jean-Alain Baeyens (autres articles)
Après avoir découvert dans les articles précédents comment installer et utiliser WinFX
avec XAML et .NET, nous allons explorer les contrôles usuels sous
"Windows Presentation Foundation" (Avalon). Dans cette partie, nous entrons
de plein pied dans le monde des API WINFX d'Avalon et dans le concept XAML.
Au terme de ce tutoriel, excepté les menus qui seront abordés ultérieurement,
vous devriez être capable de créer vous même les interfaces utilisateurs
les plus courants.
I. Avertissement
II. Remerciements
III. Introduction
IV. Le contrôle de type "Label"
V. Le contrôle de type "TextBox"
VI. Le contrôle de type "TextBlock"
VII. Le contrôle de type "Button"
VIII. Le contrôle de type "RadioButton"
IX. Le contrôle de type "CheckBox"
X. Le contrôle de type "ListBox"
XI. Le contrôle de type "ComboBox"
XII. Le contrôle de type "Image"
XIII. Le binding
A. Dans le code C#
B. Dans le code XAML
XIII. Conclusion
I. Avertissement
Cet article fait partie d'un ensemble sur Avalon ("Windows Presentation Foundation").
Ceux-ci, bien qu'écrits séparément, forment un tout. A la manière
des chapitres d'un livre, vous pouvez accéder directement au sujet
qui vous intéresse mais pour un aperçu complet, il est préférable de
commencer la lecture au premiere article.
II. Remerciements
Je remercie la redaction .NET de developpez.com pour
son soutien dans la réalisation de cet article.
III. Introduction
Il ne s'agit pas ici de découvrir toutes les possibilités des différents
contrôles possibles mais bien de parcourir les contrôles courants
dans leur utilisation la plus usuelle.
Si vous souhaitez reproduire l'exemple du chapitre, commencez par créer
un nouveau projet de type "Avalon Application".
IV. Le contrôle de type "Label"
Nous avons déjà vu dans la deuxième partie, l'utilisation du contrôle Label.
Dans les exemples qui vont suivre en lieu et place du positionnement avec
un objet de type Grid, nous allons utiliser un objet de type Canvas.
Cela nous permettra de définir la position exacte du contrôle.
| Utilisation d'un label avec un canvas |
<Window x:Class="AvalonApplication4.Window1"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
Text="Les contôles standard en XAML"
Width="500"
Height="300"
>
<Canvas>
<Label Name="lblNom" Canvas.Top="10" Canvas.Left="10">
Nom:
</Label>
</Canvas>
</Window> |
Pour positionner un contrôle avec un Canvas, nous pouvons utiliser
les propriétés Canvas.Top, Canvas.Left, Canvas.Right
et Canvas.Bottom. Pour le dimensionner, nous utiliserons les
propriétés Width et Height.
V. Le contrôle de type "TextBox"
Une "TextBox" se réalise au moyen de l'élément TextBox.
Deux façons différentes d'initialiser le contenu directement
dans le fichier XAML vous sont présentées dans l'exemple qui suit.
| Ajout d'une TextBox à notre fenêtre |
<Window x:Class="AvalonApplication4.Window1"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
Text="Les contôles standards en XAML"
Width="500"
Height="300"
>
<Canvas>
<Label Name="lblNom" Canvas.Top="10" Canvas.Left="10">
Nom:
</Label>
<TextBox Name="txtNom" Text="texte par défaut" Canvas.Top="10"
Canvas.Left="100" Width="150" Height="24"/>
<Label Name="lblPrenom" Canvas.Top="40"
Canvas.Left="10">Prénom:</Label>
<TextBox Name="txtPrenom" Canvas.Top="40" Canvas.Left="100"
Width="150" Height="24">texte par défaut</TextBox>
</Canvas>
</Window> |
Vous devrez probablement initialiser la valeur des TextBox
depuis votre code. Cela peut se faire dans la méthode nommée dans
l'exemple "windowLoaded" et associée à l'évènement Loaded de
la fenêtre. Cette association se fait dans le noeud Window.
| Le noeud Window modifié |
<Window x:Class="AvalonApplication4.Window1"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
Text="Les contôles standards en XAML"
Width="500"
Height="300"
Loaded="windowLoaded"
> |
| La méthode associée à l'évènement Loaded de la fenêtre |
private void windowLoaded(object sender, RoutedEventArgs e)
{
this.txtNom.Text = "Dupont";
this.txtPrenom.Text = "Louis";
} |
VI. Le contrôle de type "TextBlock"
L'origine du TextBlock est plûtot Web que WinForm. Il fait pourtant son
entrée dans l'API disponible pour les applications windows classiques.
Contrairement à Label, TextBlock n'hérite pas
de la classe controle. Texblock est optimizée
pour l'affichage de longs textes.
| Utilisation d'un TextBlock |
<Window x:Class="AvalonApplication4.Window1"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
Text="Les contôles standards en XAML"
Width="500"
Height="300"
>
<Canvas>
<Label Name="lblNom" Canvas.Top="10" Canvas.Left="10">
Nom:
</Label>
<TextBox Name="txtNom" Text="texte par défaut" Canvas.Top="10"
Canvas.Left="100" Width="150" Height="24"/>
<Label Name="lblPrenom" Canvas.Top="40" Canvas.Left="10">
Prénom:
</Label>
<TextBox Name="txtPrenom" Canvas.Top="40" Canvas.Left="100" Width="150"
Height="24">texte par défaut</TextBox>
<TextBlock Name="txtLogo" Background="Gray" Canvas.Top="5"
Canvas.Left="300" Width="150" Height="100"
TextWrap="Wrap" TextAlignment="center" Foreground="blue"
FontWeight="Bold">
www.developpez.com
Section dotnet
</TextBlock>
</Canvas>
</Window> |
Si vous désirez initialiser le contenu du TextBlock dans votre
code C#, par exemple pour afficher un texte variable, vous devrez utiliser
une instruction de ce type:
this.txtLogo.TextContent =
"www.developpez.com Le meilleur site pour les développereurs
francophones: Section .NET"; |
Dans l'exmple, je fais cette initialisation dans la méthode "windowLoaded".
VII. Le contrôle de type "Button"
Comme nous avons déjà abordé les boutons dans le chapitre précédent et
que leurs utilisations est des plus simple, nous allons en profiter pour voir
comment les centrer sans effort malgré que nous ayons choisi de
travailler avec un Canvas.
La solution la plus simple est de définir une grille. Il est
en effet tout à fait possible de mixer les deux techniques.
Nous allons donc définir une grille de 2 lignes et 2 colonnes.
La ligne du bas est fixée à une hauteur de 60 pixels. Nous positionons
le Canvas dans la première ligne et les boutons dans la deuxième,
respectivement dans la première et la deuxième colonne. La grille
fait le reste.
| Positionnement des boutons avec une grille. |
<Window x:Class="AvalonApplication4.Window1"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
Text="Les contôles standard en XAML"
Width="500"
Height="300"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Canvas Grid.Row="0">
<Label Name="lblNom" Canvas.Top="10" Canvas.Left="25">
Nom:
</Label>
<TextBox Name="txtNom" Text="texte par défaut" Canvas.Top="10"
Canvas.Left="100" Width="150" Height="24"/>
<Label Name="lblPrenom" Canvas.Top="40" Canvas.Left="25">
Prénom:
</Label>
<TextBox Name="txtPrenom" Canvas.Top="40" Canvas.Left="100"
Width="150" Height="24">texte par défaut</TextBox>
<TextBlock Name="txtLogo" Background="Gray" Canvas.Top="5"
Canvas.Left="300" Width="150" Height="100"
TextWrap="Wrap" TextAlignment="center" Foreground="blue"
FontWeight="Bold">
www.developpez.com
Section dotnet
</TextBlock>
</Canvas>
<Button Name="btnOk" Grid.Row="1" Grid.Column="0" Height="20"
Width="80">Ok</Button>
<Button Name="btnCancel" Grid.Row="1" Grid.Column="1" Height="20"
Width="80">Annuler</Button>
</Grid>
</Window> |
Le code C# ci-après est associé aux évènements Click des boutons.
Remarquez que pour permettre d'assigner une valeur à DialogResult,
nous devons afficher la fenêtre au moyen de la méthode ShowDialog
et non plus Show. Vous trouverez l'instruction à changer dans la
méthode "AppStartingUp" de la classe "MyApp" dans le fichier "MyApp.xaml.cs".
Dans la pratique, vous appelerez rarement une fenêtre de dialogue directement
lors du chargement de l'application.
| Le code C# associé |
private void clickOk(object sender, RoutedEventArgs e)
{
this.DialogResult = DialogResult.OK;
this.Close();
}
private void clickCancel(object sender, RoutedEventArgs e)
{
this.DialogResult = DialogResult.Cancel;
this.Close();
} |
Il est temps pour nous de découvrir ce que nous avons créé.
VIII. Le contrôle de type "RadioButton"
Les RadioButton sont généralement groupés pour offrir un
choix. Nous devons donc les inclures dans un ensemble plus grand
le RadioButtonList. Les RadioButton sont alors des
noeuds fils.
<RadioButtonList Canvas.Top="100" Canvas.Left="30">
<RadioButton Name="rbFemme" Height="20" FontSize="10"
IsChecked="True">Madame</RadioButton>
<RadioButton Name="rbHomme" FontSize="10">Monsieur</RadioButton>
</RadioButtonList> |
 |
IsChecked est optionnel mais permet de définir une valeur par défaut.
A la place, vous pouvez utiliser la propriété SelectedIndex
du RadioButtonList pour initialiser la valeur. Dans cet
exemple, nous l'aurions initialisé à 0.
|
 |
Si vous ne plaçez pas les RadioButton dans un
RadioButtonList, ils fonctionnent indépendamment les uns
des autres à la manière des CheckBox.
|
Vous pouvez également initialiser un RadioButtonList depuis le code C#.
| En utilisant IsChecked |
rbFemme.IsChecked = true; |
| En utilisant SelectedIndex |
rblSexe.SelectedIndex = 0; |
IX. Le contrôle de type "CheckBox"
L'utilisation d'une CheckBox se fait très simplement depuis
le code XAML.
<CheckBox Name="chkNewsLetter" Canvas.Top="170" Canvas.Left="30"
Height="24">S'abonner à la lettre d'information</CheckBox> |
Comme pour le RadioButton, vous pouvez utiliser la propriété IsChecked
pour initialiser votre contrôle que ce soit dans le code XAML ou le code C#.
X. Le contrôle de type "ListBox"
Pour créer une ListBox, on utilise le tag du même nom. Les différents
éléments de la ListeBox, sont définis par des noeuds fils de type
ListBoxItem.
<ListBox Name="lstLangue" Canvas.Top="100" Canvas.Left="200">
<ListBoxItem>Français</ListBoxItem>
<ListBoxItem>Anglais</ListBoxItem>
<ListBoxItem>Allemand</ListBoxItem>
<ListBoxItem>Néerlandais</ListBoxItem>
</ListBox> |
Pour initialiser une valeur par défaut, vous pouvez utiliser la propriété
SelectedIndex soit dans le code XAML, soit dans le code C#.
Si vous désirez charger la liste des valeurs de la ListBox
dans l'évènement Loaded (dans l'exemple, la méthode "windowLoaded"),
vous pouvez remplaçer le code XAML:
<ListBoxItem>Français</ListBoxItem>
<ListBoxItem>Anglais</ListBoxItem>
<ListBoxItem>Allemand</ListBoxItem>
<ListBoxItem>Néerlandais</ListBoxItem> |
par le code C# suivant:
lstLangue.Items.Add("Français");
lstLangue.Items.Add("Anglais");
lstLangue.Items.Add("Allemand");
lstLangue.Items.Add("Néerlandais"); |
Si les valeurs possibles sont déjà contenues dans une collection, par
exemples un ArrayList nommé "langues", vous pouvez
également utiliser cette syntaxe:
lstLangue.ItemsSource = langues; |
XI. Le contrôle de type "ComboBox"
Une ComboBox fonctionne sur le même pricipe qu'une ListBox
excepté le fait que l'on utilise les classe ComboBox et ComboBoxItem.
<Label Name="lblType" Canvas.Top="190" Canvas.Left="25">
Activité:
</Label>
<ComboBox Name="cboType" Canvas.Top="190" Canvas.Left="100">
<ComboBoxItem>Développement</ComboBoxItem>
<ComboBoxItem>Systèmes d'exploitation</ComboBoxItem>
<ComboBoxItem>Réseaux</ComboBoxItem>
<ComboBoxItem>Bases de données</ComboBoxItem>
<ComboBoxItem>Autres</ComboBoxItem>
</ComboBox> |
XII. Le contrôle de type "Image"
Il est possible d'inclure une image dans votre fenêtre; Pour ce faire,
utilisez la classe Image.
<Image Name="imgLogo" Canvas.Top="110" Canvas.Left="310">
<Image.Source>
<Binding Source="logodvp.gif"/>
</Image.Source>
</Image> |
Il est également possible de charger l'image depuis le code C#.
| Charger l'image dans le code C# |
private void windowLoaded(object sender, RoutedEventArgs e)
{
BitmapImage logo = new BitmapImage(new Uri(@"logodvp.gif"));
this.imgLogo.Source = logo;
} |
Découvrons notre exemple ainsi complèté.
XIII. Le binding
Plutôt que de charger vous même les valeurs dans les contrôles de
votre fenêtre, vous désirerez surement utiliser le binding.
Pour l'exemple, nous allons effectuer le binding des contrôles écrans
avec un objet contenant les données. Il est, dans le cadre de l'example,
extrémement simplifié.
| Classe pour l' objet contenant les données. |
class DataClass
{
private string nom = "Mon nom";
public string Nom
{
get { return nom; }
set { nom = value; }
}
private string prenom = "Mon prenom";
public string Prenom
{
get { return prenom; }
set { prenom = value; }
}
private int sexe = 1;
public int Sexe
{
get { return sexe; }
set { sexe = value; }
}
private int langue = 3;
public int Langue
{
get { return langue; }
set { langue = value; }
}
private int sujet = 3;
public int Sujet
{
get { return sujet; }
set { sujet = value; }
}
private bool news = true;
public bool News
{
get { return news; }
set { news = value; }
}
} |
A. Dans le code C#
Il est possible de réaliser le binding de vos données en utilisant
la méthode SetBinding.
 |
Vous pouvez constater qu'il est possible
de faire un bind sur n'importe quelle propriété de votre contrôle.
On peut parfaitement grâce au binding, changer la couleur du font
sur base de vos données.
|
| Méthode associée à l'évènement Loaded |
private void windowLoaded(object sender, RoutedEventArgs e)
{
Binding bindNom = new Binding("Nom");
bindNom.Source = dataObject;
this.txtNom.SetBinding(TextBox.TextProperty, bindNom);
Binding bindPrenom = new Binding("Prenom");
bindPrenom.Source = dataObject;
this.txtPrenom.SetBinding(TextBox.TextProperty, bindPrenom);
Binding bindLangue = new Binding("Langue");
bindLangue.Source = dataObject;
this.lstLangue.SetBinding(ListBox.SelectedIndexProperty, bindLangue);
Binding bindType = new Binding("Sujet");
bindType.Source = dataObject;
this.cboType.SetBinding(ComboBox.SelectedIndexProperty, bindType);
Binding bindSexe = new Binding("Sexe");
bindSexe.Source = dataObject;
this.rblSexe.SetBinding(RadioButtonList.SelectedIndexProperty, bindSexe);
Binding bindNews = new Binding("News");
bindNews.Source = dataObject;
this.chkNewsLetter.SetBinding(CheckBox.IsCheckedProperty, bindNews);
this.txtLogo.TextContent =
"www.developpez.com Le meilleur site pour les développereurs
francophones: Section .NET";
} |
Il est également possible de définir une source pour un ensemble
de contrôles. Nous pouvons par exemple définir la source pour le
Canvas. Pour cela nous devons en premier lieu le nommer.
| Nommer le Canvas |
<Canvas Grid.Row="0" Name="dataZone"> |
Une fois cette opération réalisée, il ne reste plus qu'a utiliser
la propriété DataContext de l'objet Canvas.
Grâce à cela, il n'est plus nécessaire d'assigner la propriété
Source des objets Binding.
| Renseigner la source pour l'ensemble du Canvas |
private void windowLoaded(object sender, RoutedEventArgs e)
{
dataZone.DataContext = dataObject;
Binding bindNom = new Binding("Nom");
this.txtNom.SetBinding(TextBox.TextProperty, bindNom);
Binding bindPrenom = new Binding("Prenom");
this.txtPrenom.SetBinding(TextBox.TextProperty, bindPrenom);
Binding bindLangue = new Binding("Langue");
this.lstLangue.SetBinding(ListBox.SelectedIndexProperty, bindLangue);
Binding bindType = new Binding("Sujet");
this.cboType.SetBinding(ComboBox.SelectedIndexProperty, bindType);
Binding bindSexe = new Binding("Sexe");
this.rblSexe.SetBinding(RadioButtonList.SelectedIndexProperty, bindSexe);
Binding bindNews = new Binding("News");
this.chkNewsLetter.SetBinding(CheckBox.IsCheckedProperty, bindNews);
this.txtLogo.TextContent =
"www.developpez.com Le meilleur site pour les développereurs
francophones: Section .NET";
} |
B. Dans le code XAML
Plutôt que de réaliser le Binding dans le code dotnet, nous
pouvons le réaliser au niveau du code XAML. Vous pouvez le faire
en ajoutant des noeuds fils à votre contrôle (voir la TextBox "Nom") soit
par inclusion dans les attributs du noeud existant (les autres contrôles).
<Window x:Class="AvalonApplication4.Window1"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
Text="Les contôles standard en XAML"
Width="500"
Height="300"
Loaded="windowLoaded"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Canvas Grid.Row="0" Name="dataZone">
<Label Name="lblNom" Canvas.Top="10" Canvas.Left="25">
Nom:
</Label>
<TextBox Name="txtNom" Canvas.Top="10" Canvas.Left="100"
Width="150" Height="26">
<TextBox.Text>
<Binding Path="Nom"/>
</TextBox.Text>
</TextBox>
<Label Name="lblPrenom" Canvas.Top="40" Canvas.Left="25">
Prénom:
</Label>
<TextBox Name="txtPrenom" Text="{Binding Path=Prenom}"
Canvas.Top="40" Canvas.Left="100" Width="150" Height="24">
texte par défaut
</TextBox>
<TextBlock Name="txtLogo" Background="Gray" Canvas.Top="5"
Canvas.Left="300" Width="150" Height="100"
TextWrap="Wrap" TextAlignment="Center"
Foreground="blue" FontWeight="Bold">
www.developpez.com
Section dotnet
</TextBlock>
<RadioButtonList Name="rblSexe" SelectedIndex="{Binding Path=Sexe}"
Canvas.Top="100" Canvas.Left="30">
<RadioButton Name="rbFemme" Height="20" FontSize="10"
IsChecked="True">
Madame
</RadioButton>
<RadioButton Name="rbHomme" FontSize="10">
Monsieur
</RadioButton>
</RadioButtonList>
<Label Name="lblLangue" Canvas.Top="95" Canvas.Left="140">
Langue:
</Label>
<ListBox Name="lstLangue" SelectedIndex="{Binding Path=Langue}"
Canvas.Top="100" Canvas.Left="200" Loaded="lstLangueLoaded">
<ListBoxItem>Français</ListBoxItem>
<ListBoxItem>Anglais</ListBoxItem>
<ListBoxItem>Allemand</ListBoxItem>
<ListBoxItem>Néerlandais</ListBoxItem>
</ListBox>
<CheckBox Name="chkNewsLetter" IsChecked="{Binding Path=News}"
Canvas.Top="170" Canvas.Left="30" Height="24">
S'abonner à la lettre d'information
</CheckBox>
<Label Name="lblType" Canvas.Top="190" Canvas.Left="25">
Activité:
</Label>
<ComboBox Name="cboType" SelectedIndex="{Binding Path=Sujet}"
Canvas.Top="190" Canvas.Left="100">
<ComboBoxItem>Développement</ComboBoxItem>
<ComboBoxItem>Systèmes d'exploitation</ComboBoxItem>
<ComboBoxItem>Réseaux</ComboBoxItem>
<ComboBoxItem>Bases de données</ComboBoxItem>
<ComboBoxItem>Autres</ComboBoxItem>
</ComboBox>
<Image Name="imgLogo" Canvas.Top="110" Canvas.Left="310">
<Image.Source>
<Binding Source="logodvp.gif"/>
</Image.Source>
</Image>
</Canvas>
<Button Name="btnOk" Grid.Row="1" Grid.Column="0" Height="20"
Width="80" Click="clickOk">Ok</Button>
<Button Name="btnCancel" Grid.Row="1" Grid.Column="1" Height="20"
Width="80" Click="clickCancel">Annuler</Button>
</Grid>
</Window> |
Notre méthode exécutée au chargement de la fenêtre s'en trouve
fortement simplifiée.
| La méthode windowLoad déchargée de la gestion du Binding |
private void windowLoaded(object sender, RoutedEventArgs e)
{
dataZone.DataContext = dataObject;
this.txtLogo.TextContent =
"www.developpez.com Le meilleur site pour les développereurs
francophones: Section .NET";
} |
 |
Remarquez que l'assignation du texte à la propriété TextContent
aurrait aussi pu se faire via le binding.
|
XIII. Conclusion
Bien sur, nous n'avons vu qu'un aperçu du potentiel de ces
différentes classes et des nouvelles techniques associées à
XAML. Toutefois, excepté les menus que nous découvrirons dans
le prochain chapitre, cette partie permet déjà de réaliser un bon
nombre des interfaces utilisateurs et je ne doute pas qu'avec
un peu de perspicacité, vous découvrirez comment utiliser les
nombreuses autres propriétés et méthodes de ces classes.
J'espère vous compter encore parmis les lecteurs pour la suite
à paraitre très prochainement.


Les sources présentées sur cette page sont libres de droits,
et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation
constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright ©
2005 Jean-Alain Baeyens. Aucune reproduction,
même partielle, ne peut être faite de ce site et de l'ensemble de son contenu :
textes, documents, images, etc sans l'autorisation expresse de l'auteur.
Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
Cette page est déposée à la
SACD.