Vous êtes sur la page 1sur 10

Module : Programmation .NET / C# 2ATEL A.

U 2020-2021

Tutoriel 4 : Les contrôles utilisateurs avec WPF

1. Introduction
Les contrôles utilisateur permettent de créer ses propres contrôles composites, basés sur les
éléments de la plateforme (ici WPF, mais ce concept existe également avec ASP ou Windows
Form). Nous verrons également par l'exemple un concept important de l'interaction
vue/code-behind, les propriétés de dépendance, ou Dependency Properties).

2. Présentation des contrôles utilisateurs


Un contrôle utilisateur est un contrôle composite, c'est à dire lui-même composé d'un ou
plusieurs contrôles. Il possède sa propre balise avec ses propres attributs et possède son
propre fonctionnement. Les avantages des contrôles utilisateur sont multiples :
Réutiliser ce contrôle dans plusieurs pages et ainsi factoriser le code. On peut prendre
l'exemple d'une zone "Panier" sur une application marchande, ou d'une barre de statut
affichée à différents endroits de l'application.
Créer un élément indépendant de l'application embarquant toute sa logique interne pour
faciliter la maintenabilité.

3. Création de l’application
Pour réaliser un contrôle utilisateur, il suffit d'ajouter un nouvel élément "User Control" dans
le projet Visual Studio.
3.1. Créer un projet WPF
- Créez un nouveau projet WPF.
- Donnez le nom « PortableBoutique» a votre projet
3.2. Créer l’interface avec XAML
Avant de nous lancer dans le XAML, nous allons expliquez notre application,
PortableBoutique est une application de vente des Smartphones.
Pour notre application nous allons utiliser les contrôles suivants :
 Listbox : c'est un ItemsControl , ce qui signifie qu’il peut contenir une collection
d’objets de n’importe quel type (par exemple, une chaîne, une image ou un panneau).
 Border : dessine une bordure, un arrière-plan ou les deux autour d'un autre
élément.
 StackPanel : dispose des éléments enfants sur une seule ligne orientée
horizontalement ou verticalement.
 2 Boutons dans le StackPanel
 Contrôle Utilisateur

1/10
Module : Programmation .NET / C# 2ATEL A.U 2020-2021

XAML :
<Window x:Class="PortableBoutique.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PortableBoutique"
mc:Ignorable="d"
Title="Boutique Farah" Height="350" Width="525">
<Grid Background="#FF1D456F">
<ListBox x:Name="L_prod" Margin="0,0,324,0"/>

<Border x:Name="B_prod" CornerRadius="5" Height="230" BorderThickness="3"


BorderBrush="White" Margin="194,12,0,61" HorizontalAlignment="Left" Width="303"/>

<StackPanel Orientation="Horizontal" Margin="196,255,6,10">

<Button x:Name="B_commander" Content="Commander"/>

<Button x:Name="B_acheter" Content="Acheter"/>

</StackPanel>

</Grid>
</Window>

Voici l’interface de ce code :

L’interface est moche !


Appliquons un peu de style :
- Ajoutez
Style="{StaticResource Style_bouton}" au contrôle Button
- Ensuite ajoutez le code suivant entre la balise <Grid> </Grid>
XAML :

2/10
Module : Programmation .NET / C# 2ATEL A.U 2020-2021

WPF introduit un concept très pratique : La possibilité de sauvegarder des données en tant que
ressource, aussi bien localement pour un contrôle, que localement pour la fenêtre entière ou encore
globalement pour l'application entière. Ce concept est beaucoup utilisé pour les styles et les
modèles.
- Regardez l’interface après avoir appliqué les propriétés du style :

Voici l’intégralité du code de l’interface :


<Window x:Class="PortableBoutique.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PortableBoutique"
mc:Ignorable="d"
Title="Boutique 2TEL" Height="350" Width="525">
<Grid Background="#FF1D456F">
<Grid.Resources>
<Style TargetType="{x:Type Button}" x:Key="Style_bouton">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="40"/>
<Setter Property="Margin" Value="5,0,88,0"/>
<Setter Property="BorderBrush" Value="Azure"/>
<Setter Property="Foreground" Value="#FF1D456F"/>
<Setter Property="Background" Value="White"/>
<Setter Property="FontFamily" Value="Geogia"/>
</Style>
</Grid.Resources>
<ListBox x:Name="L_prod" Margin="0,0,324,0"/>

<Border x:Name="B_prod" CornerRadius="5" Height="230" BorderThickness="3"


BorderBrush="White" Margin="194,12,0,61" HorizontalAlignment="Left" Width="303"/>

3/10
Module : Programmation .NET / C# 2ATEL A.U 2020-2021

<StackPanel Orientation="Horizontal" Margin="196,255,6,10">


<Button x:Name="B_commander" Content="Commander" Style="{StaticResource
Style_bouton}"/>
<Button x:Name="B_acheter" Content="Acheter" Style="{StaticResource
Style_bouton}"/>
</StackPanel>
</Grid>
</Window>

Maintenant, nous allons désactivez le bouton qui permet de réduire, et agrandir notre
fenêtre :
- Ajoutez ce code à l’intérieur de la balise Window, après la propriété Width :
WindowStartupLocation="CenterScreen" WindowStyle="ToolWindow"

3.4.1 Ajouter des Images


Dans cette partie nous allons ajouter les différents produits dans notre Listbox, ces produits
sont des images des téléphones.
- Créez un dossier dans lequel nous allons ajouter nos images,

- Donnez un nom à votre dossier « ImagesTelephones»


- Ajoutons nos images dans le dossier « ImagesTelephones», faites un clic-droit sur
Images Phones, puis sélectionnez Add > Existing Item.. enfin sélectionnez vos images
dans l’ordinateur.
Vous aurez la situation suivante :

4/10
Module : Programmation .NET / C# 2ATEL A.U 2020-2021

- Insérez les images, en ajoutant à l’intérieur de la balise « Listbox » le code suivant:

<Image Source="/ImagesTelephones/iphone.png" Height="100" Width="150"/>


<Image Source="/ImagesTelephones/N8.png" Height="100" Width="150"/>
<Image Source="/ImagesTelephones/OVI.png" Height="100" Width="150"/>
<Image Source="/ImagesTelephones/WP7.png" Height="100" Width="150"/>
<Image Source="/ImagesTelephones/xperia.png" Height="100" Width="150"/>

Voici l’interface après l’ajout de ce code :

4. Création du contrôle utilisateur avec des propriétés de


dépendances
La solution que nous allons aborder ici est de créer un seul contrôle utilisateur ayant des
propriétés de dépendances.

- Créez un contrôle utilisateur TelPortable ayant une interface contenant les contrôles
suivants :
 Label
 Image

Pour créer un contrôle utilisateur aller sur le menu projet cliquer sur Add>User Control..

5/10
Module : Programmation .NET / C# 2ATEL A.U 2020-2021

Vous aurez ceci :

- Donnez un nom à votre contrôle « TelPortable».

6/10
Module : Programmation .NET / C# 2ATEL A.U 2020-2021

XAML :
<UserControl x:Class="PortableBoutique.TelPortable"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PortableBoutique"
mc:Ignorable="d"
d:DesignHeight="450" Loaded="UserControl_Loaded"
SizeChanged="UserControl_SizeChanged" Width="350">
<Grid Height="170" Width="100">
<Grid>
<Label Content="{Binding Path=Prix}" Height="30" Foreground="White"
HorizontalAlignment="Center" Margin="25,140,20,0" Name="label1"
VerticalAlignment="Top" Width="55" FontSize="16" />

<Image Source="{Binding Path=Photo, RelativeSource={RelativeSource


TemplatedParent}}" Name="image1" Stretch="Fill"
HorizontalAlignment="Left" Width="100" Margin="0,0,0,30"/>

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

4.1. Les dependency properties


Les dependency properties permettent aux objets d'avoir des propriétés dont la valeur peut
dépendre de nombreuses choses. Par exemple, du data binding avec une autre propriété, ou
d'une animation. En plus, elles fournissent un support pour l'auto validation et les valeurs
par défaut. Les classes dérivées peuvent modifier le comportement d'une dependency
property héritée très simplement.
4.2. Créer une DependencyProperty
La création d'une propriété de dépendance étant relativement complexe, nous le ferons en
plusieurs étapes. Nous allons créer les propriétés de dépendance Prix et Photo dans notre
contrôle utilisateur TelPortable.
La première étape consiste à créer une propriété de type DependencyProperty dans notre
contrôle utilisateur :
Ajoutez le code suivant dans TelPortable.xaml.cs
public static readonly DependencyProperty PrixProperty =
DependencyProperty.Register(
"Prix",
typeof(string),
typeof(TelPortable),
new FrameworkPropertyMetadata(string.Empty)
);
public static readonly DependencyProperty PhotoProperty =
DependencyProperty.Register(
"Photo",
typeof(ImageSource),
typeof(TelPortable),
new FrameworkPropertyMetadata(null)
);

7/10
Module : Programmation .NET / C# 2ATEL A.U 2020-2021

L'affectation de la propriété Prix est prise en charge par la méthode


DependencyProperty.Register, appel constitué des éléments suivants :
- "Prix": La propriété concernée, définie dans le contrôle utilisateur.

- typeof(string): Type de la propriété concernée, ici string.

- typeof(TelPortable): Type du contrôle utilisateur, ici Produit.


- new FrameworkPropertyMetadata : Un objet permettant de suivre les modifications de
la propriété. L’argument définit la valeur de notre propriété avant tout changement
(ici une chaîne vide, string.Empty),
La deuxième étape consiste à créer une propriété CLR (toujours dans le fichier
TelPortable.xaml.cs)
4.3. Déclarer une propriété CLR encapsulant cette DependencyProperty
Pour que cette propriété soit utilisable depuis le code de façon totalement invisible (sans
que l'on ait à se préoccuper qu'il s'agisse d'une DependencyProperty ou d'une propriété
CLR), on définit une propriété CLR.
public string Prix
{
get => (string)GetValue(PrixProperty); set => SetValue(PrixProperty, value);
}

public ImageSource Photo


{
get => (ImageSource)GetValue(PhotoProperty); set => SetValue(PhotoProperty, value);
}

3.4.2 Propriétés de dépendance et Bindings


Comme dit précédemment, les propriétés de dépendance disposent d'un système
d'événement intégré et compatibles avec les Bindings. Le but des contrôles utilisateur est de
fonctionner également avec les Bindings, pour offrir une facilité de développement et une
gestion simplifiée au changement des valeurs.
<Label Content="{Binding Path=Prix}" Height="30" Foreground="White"
HorizontalAlignment="Center" Margin="25,140,20,0" Name="label1"
VerticalAlignment="Top" Width="55" FontSize="16" />

<Image Source="{Binding Path=Photo, RelativeSource={RelativeSource TemplatedParent}}"


Name="image1" Stretch="Fill" HorizontalAlignment="Left" Width="100"
Margin="0,0,0,30"/>

Pour que la valeur initiale du label1 et image1.Source du Contrôle soit effectivement prise
en compte dans le Prix et Photo, il faut simplement rafraîchir la valeur. Mais comme celle ci
est déjà dans sont état final et qu’elle ne bougera pas à moins d’avoir une valeur différente,
on va la forcer à prendre une valeur par défaut puis on lui réaffectera sa valeur initiale.
On effectuera ce changement dans l’évènement Loaded du contrôle utilisateur afin que les
valeurs initiales externes soit bien fixées.

8/10
Module : Programmation .NET / C# 2ATEL A.U 2020-2021

Enfin pour ne pas permettre le redimensionnement du user control Produit ajoutez le code
suivant :

Déboguez le projet, vous devez trouver le contrôle TelPortabe installé dans la boîte à outils.

5. Utilisation du contrôle utilisateur


Ajoutez un contrôle utilisateur TelPortable dans le Border

5.1.1. Code Behind


Nous pouvons maintenant utiliser notre contrôle utilisateur
Dans le fichier MainWindow.xaml.cs, ajoutez le code suivant dans le gestionnaire
d’événement SelectionChanged du ListBox

9/10
Module : Programmation .NET / C# 2ATEL A.U 2020-2021

private void L_prod_SelectionChanged(object sender, SelectionChangedEventArgs e)


{
var TP = new TelPortable();
switch (L_prod.SelectedIndex)
{
case 0: { TP.Prix = "850$"; TP.Photo = new BitmapImage(
new Uri(@"/ImagesTelephones/iphone.png", UriKind.Relative)); };
break;
case 1: { TP.Prix = "620$"; TP.Photo = new BitmapImage(
new Uri(@"/ImagesTelephones/N8.png", UriKind.Relative)); }; break;
case 2: { TP.Prix = "420$"; TP.Photo = new BitmapImage(
new Uri(@"/ImagesTelephones/OVI.png", UriKind.Relative)); };
break;
case 3: { TP.Prix = "550$"; TP.Photo = new BitmapImage(
new Uri(@"/ImagesTelephones/WP7.png", UriKind.Relative)); };
break;
case 4: { TP.Prix = "735$"; TP.Photo = new BitmapImage(
new Uri(@"/ImagesTelephones/xperia.png", UriKind.Relative)); };
break;
}
B_prod.Child = TP;
}

5.1.2. XALM
Dans XAML cible définir le Namespace:
xmlns:USERCONTROL="clr-namespace:Namespace"
Dans notre exemple :

Puis dans le XAML l’appeler de la sorte :

10/10

Vous aimerez peut-être aussi