PowerShell et XAML
Introduction
Dans le deuxième chapitre, nous avons vu ce qu’était le cœur de notre interface, XAML.
Nous avons également vu comment créer et éditer un fichier XAML.
Dans ce chapitre, nous allons voir comment lier notre interface avec notre code PowerShell.
Nous allons également voir comment ajouter des actions sur nos Controls afin de créer une interactivité avec l’utilisateur.
Il est important de bien comprendre le rôle de chaque partie dans son projet WPF et PowerShell.
Ce projet est composé de deux parties :
-
PowerShell
-
XAML
Rôles des fichiers
1. XAML pour notre interface
La partie XAML, comme mentionné au chapitre XAML, le cœur de notre interface, représentera la partie graphique, et uniquement graphique, de notre projet.
Nous intégrerons dans cette partie tous nos Controls et aspects graphiques.
2. PS1 pour notre code
La partie PowerShell quant à elle représentera la partie code de notre projet. C’est la partie qui permettra de gérer toutes les actions sur les Controls liées à notre interface.
3. Comment organiser son projet ?
Les deux parties XAML et PS1 peuvent s’utiliser de deux façons :
-
Deux fichiers distincts (méthode que je recommande pour une meilleure lisibilité et davantage de maniabilité).
-
Tout inclure dans le fichier PowerShell.
Ces deux méthodes seront traitées dans ce chapitre.
4. Notre projet dans ce chapitre
Le projet qui servira d’exemple dans ce chapitre aura pour nom MonProjet.
L’interface sera telle que ci-dessous :
Cette interface est représentée par le code XAML ci-dessous :
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Interface WPF - Chapitre 4" Width="380" Height="200">
<Grid>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" ...
Première méthode : deux fichiers distincts
Notre projet sera composé de deux fichiers tels que ci-dessous :
-
MonProjet.xaml : notre interface
-
MonProjet.ps1 : notre code
1. Lier PowerShell et XAML
Ouvrons donc le fichier PowerShell et ajoutons-y le code suivant afin de charger notre fichier MonProjet.xaml :
[xml]$MonXAML = get-content -path "MonProjet.xaml"
$Reader=(New-Object System.Xml.XmlNodeReader $MonXAML)
$Interface = [Windows.Markup.XamlReader]::Load($Reader)
$Interface.ShowDialog() | Out-Null
Que fait ce code ?
-
Nous allons d’abord transformer notre XAML en un objet XML en utilisant System.Xml.XmlNodeReader.
-
Ensuite, nous chargeons ce dernier en utilisant [Windows.Markup.XamlReader]::Load.
-
Enfin, nous affichons notre interface en utilisant $Interface.ShowDialog().
Si nous lançons le fichier PowerShell, nous obtenons l’erreur suivante :
Pourquoi ?
La raison est simple, il nous manque l’assembly permettant le fonctionnement de WPF.
Présentation des assemblies
L’assembly à utiliser ici est l’assembly presentationframework et se présente sous la forme d’un fichier .dll.
C’est cette assembly qui contiendra tous les Controls que nous voulons utiliser.
C’est également par elle que notre interface WPF pourra s’afficher.
Dans le chapitre XAML, le cœur de notre interface, nous avons retrouvé une référence à cette assembly à deux reprises.
En effet, lors de la création d’un projet WPF via Visual Studio, en cliquant sur [F12] sur un Control, par exemple un TextBox, nous obtenons l’information ci-dessous :
Si vous cherchez des informations sur un Control sur le site de Microsoft, par exemple un Button, vous obtiendrez l’information ci-dessous.
Vous trouverez également une explication sur ces assemblies au chapitre Interface graphique et PowerShell.
Ce qui nous amène donc à notre seconde étape qui en réalité est donc la première.
2. Chargement de l’assembly
a. Comment charger l’assembly ?
Pour charger l’assembly presentationframework, nous utiliserons la ligne ci-dessous :
[System.Reflection.Assembly]::LoadWithPartialName
('presentationframework')
En exécutant cette ligne dans une console PowerShell, nous obtenons le résultat suivant :...
Deuxième méthode : Tout dans le PS1
Dans cette seconde méthode, notre fichier XAML sera intégré dans le fichier PS1.
La seule chose qui changera par rapport à la méthode 1 sera la partie chargement du XAML.
Concernant les étapes ci-dessous, elles sont identiques à la première méthode :
-
Déclaration de l’assembly
-
Déclaration des Controls
-
Affichage de l’interface
Comment charger le XAML dans le PS1 ?
Pour cela, nous allons intégrer notre contenu XAML dans une variable en utilisant ce modèle :
[xml]$Form = @"
MON CODE XAML
"@
Notre fichier PowerShell MonProjet.ps1 sera alors tel que ci-dessous :
[System.Reflection.Assembly]::LoadWithPartialName
('presentationframework') | out-null
[xml]$MonXAML = @"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Interface WPF - Chapitre 4" Width="380" Height="200">
<Grid>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center"
Margin="0,10,0,0">
<Label Content="Notre interface WPF" FontSize="20"
HorizontalAlignment="Center"/>
<GroupBox Header="Chargement du dossier"...
Déclarations de nos Controls
Nous pouvons à présent lancer notre interface depuis notre fichier PowerShell.
Cependant, si nous cliquons sur un Control, aucune action ne sera exécutée.
Pourquoi ?
La raison est simple, il faut déclarer les Controls situés dans le fichier XAML, dans notre fichier PS1.
Pour cela, nous allons utiliser le modèle ci-dessous :
$MonControl = $MonInterface.FindName("MonControl")
Déclarons donc nos Controls en suivant ce modèle.
Quels Controls avons-nous ?
Comme mentionné dans le chapitre XAML, le cœur de notre interface, afin de pouvoir exécuter une action sur un Control, il faut nommer ce Control en utilisant l’attribut Name suivi du nom à lui donner.
Il faut donc déterminer les Controls sur lesquels nous voulons ajouter une action.
Dans le fichier XAML, nous avons les Controls ci-dessous :
<Button Name="MonBouton" Content="Browse" Width="80" Height="20"/>
<TextBox Name="MonTextBox" Width="200" Height="20"/>
Nous avons deux Controls à déclarer en utilisant l’attribut Name.
Chaque nom devra donc être déclaré dans le fichier PowerShell.
Voici le code déclarant nos Controls :
$MonBouton = $MonInterface.FindName("MonBouton")
$MonTextBox = $MonInterface.FindName("MonTextBox")...
Des actions sur les Controls
Jusqu’à présent, nous avons construit notre interface puis lié celle-ci à notre fichier PowerShell.
Ce fichier servira pour notre partie code.
Cependant, il manque une dernière étape afin de pouvoir ajouter une action sur nos Controls.
Il s’agit de l’ajout des blocs d’évènements (events) sur ces Controls.
Ce bloc d’évènement permettra de contenir le code exécutant l’action souhaitée, par exemple la copie d’un fichier lors d’un clic sur un bouton.
Pour rappel, notre interface est la suivante :
Ce que nous voulons dans notre interface :
-
Lorsque nous cliquons, ou passons le curseur de la souris sur le bouton Browse, cela doit afficher une fenêtre permettant de charger le contenu d’un dossier local sur un dossier localisé sur votre PC.
-
Une fois que nous avons choisi le dossier, le chemin sera affiché dans le TextBox.
-
Un clic droit ou un double clic dans le TextBox devra permettre d’en effacer le contenu.
Comme vu précédemment, nous avons donc les deux Controls :
-
Notre bouton Browse : $MonBouton
-
Notre TextBox : $MonTextBox
Nous avons parlé d’évènements, mais comment les traduire ?
Lorsque l’utilisateur clique sur le bouton Browse, cela va ouvrir une fenêtre permettant de charger le contenu d’un dossier local...
Controls et Events
Comme mentionné précédemment, les actions effectuées sur des Controls sont appelées évènements ou events.
Il existe différents évènements disponibles pour un même Control.
Tous ces évènements sont inclus dans l’assembly presentationframework.dll.
Pour chaque action que vous souhaitez exécuter, par exemple sur un bouton, il existe un évènement.
On peut parfois trouver différents évènements pour une même action.
Vous trouverez dans cette section une liste des évènements les plus souvent utilisés ou qui peuvent être utiles dans vos projets.
Ces évènements seront définis par rapport à une action que nous voulons effectuer.
1. Events les plus courants
a. Action après un simple clic (gauche) sur un Control
Pour cela, il existe l’évènement Click, qui s’utilise de la manière suivante dans PowerShell :
$MonBouton.Add_Click({
# CODE POUR MON ACTION
})
b. Action après avoir effectué un clic droit sur un Control
Pour cela, il existe l’évènement MouseRightButtonDown, qui s’utilise de la manière suivante dans PowerShell :
$MonBouton.Add_MouseRightButtonDown({
# CODE POUR MON ACTION
})
c. Action après avoir relâché...
Cycle de vie d’une interface
Une interface WPF est divisée en deux parties :
-
Une partie cliente
-
Une partie non-cliente
La partie non-cliente est la partie commune à la plupart des applications existantes. Celle-ci comprend les éléments suivants :
-
Des bordures
-
Un titre
-
Une icône
-
Différents boutons : minimiser, redimensionner, agrandir, fermer
La partie cliente, quant à elle, constitue la zone que nous modifions, celle où nous ajoutons notre contenu, bouton, zone de saisie, texte…
Nous allons maintenant étudier le cycle de vie de notre interface et comment celle-ci évolue à partir de son chargement et jusqu’à sa fermeture.
Ce point est important à comprendre.
En effet, une fois que vous aurez maîtrisé cela, vous pourrez gérer aisément le moment où une action doit s’effectuer.
Un exemple concret serait : je veux que telle ou telle action soit exécutée lors de la fermeture de l’interface, c’est-à-dire au moment où l’on clique sur le bouton de fermeture.
Comme nous l’avons déjà vu, notre interface est représentée par la classe Window.
C’est en effet à l’intérieur de cette même balise <Window> que l’on intègre tout le contenu de notre interface.
Comme chaque Control, notre Window possède des attributs et des évènements.
Comme pour les Controls, ces évènements permettent d’interagir avec l’objet en question, ici donc notre interface principale.
Ces évènements constituent le cycle de vie de la fenêtre.
Nous pouvons en avoir un aperçu en reprenant le code de la section Lier PowerShell et XAML, ci-dessous :
[xml]$MonXAML = get-content -path "MonProjet.xaml"
$Reader=(New-Object System.Xml.XmlNodeReader $MonXAML)
$Interface = [Windows.Markup.XamlReader]::Load($Reader)
$Interface.ShowDialog() | Out-Null
Nous allons simplement enlever la partie $Interface.ShowDialog afin d’afficher les évènements contenus dans notre interface.
Pour cela, nous allons effectuer un get-member sur l’objet de notre interface, tel que ci-dessous :
$Interface | gm | where {$_.MemberType -eq "Event"} |
select Name, MemberType
Nous obtenons alors...
Minimiser et afficher depuis le PowerShell
Il peut être intéressant dans votre code de minimiser votre interface, c’est-à-dire ne plus l’afficher. Cela peut par exemple être utile si vous souhaitez exécuter une action qui prend du temps. L’interface va alors disparaître après avoir cliqué sur un bouton spécifique puis être affichée de nouveau à la fin de l’exécution du code.
Ci-dessous le code pour minimiser l’interface :
$Form.WindowState = [System.Windows.Forms.FormWindowState]::Minimized
Ci-dessous le code pour afficher l’interface :
$Form.WindowState = [System.Windows.Forms.FormWindowState]::Normal
Il est également possible d’afficher ou non la possibilité d’afficher l’interface, depuis la barre des tâches.
Pour cela, il faut utiliser la ligne suivante :
$Form.ShowInTaskbar = $true
$Form.WindowState = [System.Windows.Forms.FormWindowState]::Minimized