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.

1er partie: Installation
2ème partie: Ma première fenêtre avec Avalon
3ème partie: Les contrôles courants
4ème partie: Le menu

5ème partie: Les modèles "Avalon Express Application" et "Navigation Application"

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
Sélectionnez

<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
Sélectionnez

<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é
Sélectionnez

<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
Sélectionnez

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
Sélectionnez

<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:

 
Sélectionnez

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.
Sélectionnez

<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é
Sélectionnez

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éé.

Image non disponible

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.

 
Sélectionnez

<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
Sélectionnez

rbFemme.IsChecked = true;
En utilisant SelectedIndex
Sélectionnez

rblSexe.SelectedIndex = 0;

IX. Le contrôle de type "CheckBox"

L'utilisation d'une CheckBox se fait très simplement depuis le code XAML.

 
Sélectionnez

<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.

 
Sélectionnez

<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:

 
Sélectionnez

<ListBoxItem>Français</ListBoxItem>
<ListBoxItem>Anglais</ListBoxItem>
<ListBoxItem>Allemand</ListBoxItem>
<ListBoxItem>Néerlandais</ListBoxItem>

par le code C# suivant:

 
Sélectionnez

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:

 
Sélectionnez

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.

 
Sélectionnez

<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.

 
Sélectionnez

<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#
Sélectionnez

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é.

Image non disponible

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.
Sélectionnez

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
Sélectionnez

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
Sélectionnez

<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
Sélectionnez

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).

 
Sélectionnez

<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
Sélectionnez

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.