Vue d’ensemble du langage XAML (WPF .NET)

Cet article décrit les fonctionnalités du langage XAML et montre comment utiliser XAML pour écrire des applications Windows Presentation Foundation (WPF). Cet article décrit en particulier le langage XAML tel qu’il est implémenté par WPF. Le XAML lui-même est un concept de langage plus vaste que WPF.

Important

La documentation du Guide du bureau pour .NET 7 et .NET 6 est en cours de construction.

Qu’est-ce que XAML ?

XAML est un langage de balisage déclaratif. Comme appliqué au modèle de programmation .NET, XAML simplifie la création d’une interface utilisateur pour une application .NET. Vous pouvez créer des éléments d'interface utilisateur visibles dans la balise XAML déclarative, puis séparer la définition de l'interface utilisateur de la logique au moment de l'exécution en utilisant les fichiers code-behind, joints à la balise par le biais de définitions de classe partielles. XAML représente directement l’instanciation d’objets dans un ensemble spécifique de types de stockage définis dans des assemblys. C’est ce qui le différencie de la plupart des autres langages de balisage, qui sont en général des langages interprétés sans un lien aussi direct à un système de type de stockage. XAML permet un flux de travail dans lequel des parties distinctes peuvent travailler sur l’interface utilisateur et la logique d’une application avec des outils pouvant être différents.

Représentés sous forme de texte, les fichiers XAML sont des fichiers XML qui ont généralement l’extension .xaml. Les fichiers peuvent être encodés par un encodage XML, même si UTF-8 est l’encodage classique.

L’exemple suivant montre comment vous pouvez créer un bouton dans une IU. Cet exemple est destiné à vous donner une idée de la manière dont le XAML représente les métaphores de programmation courantes de l’IU (ce n’est pas un exemple exhaustif).

<StackPanel>
    <Button Content="Click Me"/>
</StackPanel>

Syntaxe XAML en bref

Les sections suivantes expliquent les bases de la syntaxe XAML et donnent un court exemple de balisage. Ces sections ne visent pas à fournir des informations complètes sur toutes les formes de syntaxe, telles que représentées dans le système de types de stockage. Pour plus d’informations sur les spécificités du XAML, consultez Syntaxe XAML en détail.

La plupart des informations présentées dans les sections suivantes peuvent vous paraître élémentaires si vous connaissez déjà le langage XML. C’est une conséquence d’un des principes de base de la conception du langage XAML. Le XAML définit ses propres concepts, mais ces concepts fonctionnent dans le format du langage et du balisage XML.

Éléments objet XAML

Un élément objet déclare généralement une instance d’un type. Ce type est défini dans les assemblys référencés par la technologie utilisant le XAML comme langage.

La syntaxe d’un élément objet commence toujours par un signe « inférieur à » (<). Le nom du type dans lequel vous souhaitez créer une instance suit. (Le nom peut inclure un préfixe, un concept qui sera expliqué plus tard.) Après cela, vous pouvez éventuellement déclarer des attributs sur l’élément objet. Pour terminer la balise de l’élément objet, finissez par un signe « supérieur à » (>). Sinon, vous pouvez utiliser une forme de fermeture automatique sans contenu en ajoutant à la balise une barre oblique suivie d’un signe « supérieur à » (/>). Par exemple, réexaminez l’extrait de code de balisage présenté précédemment.

<StackPanel>
    <Button Content="Click Me"/>
</StackPanel>

Deux éléments objet sont spécifiés : <StackPanel> (avec du contenu et suivi d’une balise de fermeture) et <Button .../> (avec plusieurs attributs et la forme de fermeture automatique). Les éléments objet StackPanel et Button mappent chacun au nom d’une classe qui est définie par WPF et qui fait partie des assemblys WPF. Lorsque vous spécifiez une balise d’élément objet, vous créez une instruction de traitement XAML qui crée une nouvelle instance du type sous-jacent. Chaque instance est créée en appelant le constructeur sans paramètre du type sous-jacent lors de l’analyse et du chargement du code XAML.

Syntaxe d’attribut (Propriétés)

Les propriétés d’un objet peuvent souvent être exprimées en tant qu’attributs de l’élément objet. La syntaxe d’attribut nomme la propriété d’objet qui est définie, et la fait suivre de l’opérateur d’assignation (=). La valeur d’un attribut est toujours spécifiée sous la forme d’une chaîne comprise entre guillemets.

La syntaxe d’attribut est la syntaxe de définition de propriétés la plus simple et la plus intuitive pour les développeurs ayant déjà utilisé des langages de balisage. Par exemple, le balisage suivant crée un bouton qui se compose d’un texte en rouge et d’un arrière-plan bleu avec un texte d’affichage de Content.

<Button Background="Blue" Foreground="Red" Content="This is a button"/>

Syntaxe des éléments de la propriété

Pour certaines propriétés d’un élément objet, la syntaxe d’attribut n’est pas possible parce que l’objet ou les informations nécessaires pour fournir la valeur de propriété ne peuvent pas être correctement exprimés dans les guillemets et les restrictions de chaîne de la syntaxe d’attribut. Pour ces cas particuliers, vous pouvez utiliser une autre syntaxe appelée syntaxe des éléments de propriété.

La syntaxe de la balise de début de l’élément de propriété est <TypeName.PropertyName>. En règle générale, le contenu de cette balise est un élément objet du type que la propriété prend comme valeur. Après avoir spécifié le contenu, vous devez fermer l’élément de propriété avec une balise de fin. La syntaxe de la balise de fin est </TypeName.PropertyName>.

Si une syntaxe d’attribut est possible, son utilisation est généralement plus pratique et permet un balisage plus compact, mais il s’agit souvent d’une simple question de style et non d’une restriction technique. L’exemple suivant montre les mêmes propriétés définies comme dans l’exemple de la syntaxe d’attribut précédent, mais cette fois-ci la syntaxe des éléments de propriété est utilisée pour toutes les propriétés de Button.

<Button>
    <Button.Background>
        <SolidColorBrush Color="Blue"/>
    </Button.Background>
    <Button.Foreground>
        <SolidColorBrush Color="Red"/>
    </Button.Foreground>
    <Button.Content>
        This is a button
    </Button.Content>
</Button>

Syntaxe de collection

Le langage XAML offre quelques optimisations qui permettent une meilleure lecture des balises. Par exemple, si une propriété particulière utilise un type de collection, les éléments que vous déclarez dans le balisage en tant qu’éléments enfants dans cette valeur de propriété deviennent partie intégrante de la collection. Dans ce cas, une collection d’éléments objet enfants est la valeur définie pour la propriété de collection.

L’exemple suivant montre la syntaxe de collection pour définir des valeurs de la propriété GradientStops.

<LinearGradientBrush>
    <LinearGradientBrush.GradientStops>
        <!-- no explicit new GradientStopCollection, parser knows how to find or create -->
        <GradientStop Offset="0.0" Color="Red" />
        <GradientStop Offset="1.0" Color="Blue" />
    </LinearGradientBrush.GradientStops>
</LinearGradientBrush>

Propriétés de contenu XAML

XAML spécifie une fonctionnalité de langage dans laquelle une classe peut désigner précisément une de ses propriétés comme étant la propriété de contenu XAML. Les éléments enfants de cet élément objet sont utilisés pour définir la valeur de cette propriété de contenu. En d’autres termes, pour la propriété de contenu uniquement, vous pouvez omettre un élément de propriété lors de la définition de cette propriété dans le balisage XAML et produire une métaphore parent/enfant plus visible dans le balisage.

Par exemple, Border spécifie une propriété contenu de Child. Les deux éléments Border suivants sont traités de façon identique. Le premier tire parti de la syntaxe de la propriété de contenu et omet l’élément de propriété Border.Child. Le deuxième affiche Border.Child explicitement.

<Border>
    <TextBox Width="300"/>
</Border>
<!--explicit equivalent-->
<Border>
    <Border.Child>
        <TextBox Width="300"/>
    </Border.Child>
</Border>

En tant que règle du langage XAML, la valeur d’une propriété de contenu XAML doit figurer soit entièrement avant soit entièrement après tous les autres éléments de propriété sur cet élément objet. Par exemple, le balisage suivant n’est pas compilé.

<Button>I am a
  <Button.Background>Blue</Button.Background>
  blue button</Button>

Pour plus d’informations sur les spécificités du XAML, consultez Syntaxe XAML en détail.

Contenu textuel

Un petit nombre d’éléments XAML peuvent traiter directement du texte comme étant leur contenu. Pour ce faire, un des cas suivants doit se vérifier :

  • La classe doit déclarer une propriété de contenu et cette propriété de contenu doit être d’un type assignable à une chaîne (le type peut être Object). Par exemple, tous les ContentControl utilisent Content comme propriété de contenu et son typeObject, et cela prend en charge l’utilisation suivante sur un ContentControlcomme par exemple un Button : <Button>Hello</Button>.

  • Le type doit déclarer un convertisseur de type, auquel cas le contenu de texte est utilisé comme texte d’initialisation pour ce convertisseur de type. Par exemple, <Brush>Blue</Brush> convertit la valeur de contenu d’un Blue en pinceau. Ce cas est moins courant dans la pratique.

  • Le type doit être une primitive de langage XAML connue.

Combinaison des propriétés de contenu et de la syntaxe des collections

Considérez cet exemple.

<StackPanel>
    <Button>First Button</Button>
    <Button>Second Button</Button>
</StackPanel>

Ici, chaque Button est un élément enfant de StackPanel. Il s’agit d’un balisage simple et intuitif qui omet deux balises pour deux raisons différentes.

  • Élément de propriété StackPanel.Children omis :StackPanel dérive de Panel. Panel définit Panel.Children comme sa propriété de contenu XAML.

  • L’élément objet UIElementCollection omis : La propriété Panel.Children prend le type UIElementCollection, qui implémente IList. La balise de l’élément de la collection peut être omise, conformément aux règles XAML de traitement des collections, telles que IList. (Dans ce cas, UIElementCollection ne peut pas être instancié, car il n’expose pas de constructeur sans paramètre et c’est pourquoi l’élément objet UIElementCollection est affiché commenté).

<StackPanel>
    <StackPanel.Children>
        <!--<UIElementCollection>-->
        <Button>First Button</Button>
        <Button>Second Button</Button>
        <!--</UIElementCollection>-->
    </StackPanel.Children>
</StackPanel>

Syntaxe des attributs (événements)

La syntaxe des attributs peut également servir pour les membres qui sont des événements plutôt que des propriétés. Dans ce cas, le nom de l’attribut est le nom de l’événement. Dans l’implémentation WPF d’événements pour XAML, la valeur de l’attribut est le nom d’un gestionnaire qui implémente le délégué de l’événement. Par exemple, le balisage suivant affecte un gestionnaire pour l’événement Click à un Button créé dans le balisage :

<Button Click="Button_Click" >Click Me!</Button>

Il existe plus d’événements et de code XAML dans WPF que cet exemple de syntaxe des attributs. Par exemple, vous vous demandez peut-être ce que le ClickHandler référencé ici représente et comment il est défini. C’est expliqué dans la section Événements et code-behind XAML, plus loin dans cet article.

Casse et espaces blancs en XAML

En général, XAML respecte la casse. Pour la résolution des types de stockage, XAML WPF respecte la casse en suivant les mêmes règles que celles que respecte le CLR. Les éléments objet, les éléments de propriété et les noms d’attribut doivent tous être spécifiés en respectant la casse quand leurs noms sont comparés au type sous-jacent dans l’assembly ou à un membre d’un type. Les primitives et les mots clés du langage XAML respectent également la casse. Par contre, les valeurs ne respectent pas toujours la casse. Pour les valeurs, le respect de la casse varie selon le comportement du convertisseur de type associé à la propriété qui prend la valeur ou le type de valeur de la propriété. Par exemple, les propriétés qui prennent le type Boolean peuvent également accepter true ou True en tant que valeurs équivalentes, mais c’est uniquement parce que la conversion du type d’analyseur XAML WPF natif de chaîne en Boolean les autorise déjà comme équivalents.

Les sérialiseurs et les processeurs XAML WPF doivent ignorer ou supprimer tous les espaces blancs non significatifs et normaliser tout espace blanc significatif. Cette pratique est conforme aux recommandations du comportement par défaut des espaces blancs dans la spécification XAML. Ce comportement ne porte à conséquence que lorsque vous spécifiez des chaînes dans les propriétés de contenu XAML. Dit plus simplement, le XAML convertit espaces, sauts de ligne et tabulations en espaces, puis conserve un seul espace trouvé aux extrémités d’une chaîne contiguë. L’explication complète de la gestion des espaces blancs en XAML n’est pas couverte dans cet article. Pour plus d'informations, consultez Traitement de l'espace blanc en XAML.

Extensions de balisage

Les extensions de balisage forment un concept de langage XAML. Lorsqu’elles sont utilisées pour fournir la valeur d’une syntaxe d’attributs, les accolades ({ et }) indiquent une extension de balisage. Cette utilisation ordonne au traitement XAML de se soustraire au traitement général des valeurs d’attribut, soit en tant que chaîne littérale, soit en tant que valeur convertible en chaîne.

Les extensions de balisage les plus courantes qui sont utilisées dans la programmation d’applications sont Binding, utilisée pour les expressions de liaison de données, et les références aux ressources StaticResource et DynamicResource. Grâce aux extensions de balisage, vous pouvez utiliser la syntaxe d’attributs pour fournir des valeurs aux propriétés, même si en général cette propriété ne prend pas en charge cette syntaxe. Les extensions de balisage utilisent souvent des types d’expression intermédiaires pour activer des fonctionnalités, telles que le traitement différé des valeurs ou le référencement d’autres objets qui sont uniquement présents au moment de l’exécution.

Par exemple, le balisage suivant définit la valeur de la propriété Style à l’aide de la syntaxe d’attributs. La propriété Style prend une instance de la classe Style, qui par défaut n’a pas pu être instanciée par une chaîne de syntaxe d’attribut. Dans ce cas, par contre, l’attribut fait référence à une extension de balisage particulière, StaticResource. Lorsque cette extension de balisage est traitée, elle retourne une référence à un style qui a été instancié précédemment en tant que ressource indexée dans un dictionnaire de ressources.

<Window x:Class="index.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="100" Width="300">
    <Window.Resources>
        <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
        <Style TargetType="Border" x:Key="PageBackground">
            <Setter Property="BorderBrush" Value="Blue"/>
            <Setter Property="BorderThickness" Value="5" />
        </Style>
    </Window.Resources>
    <Border Style="{StaticResource PageBackground}">
        <StackPanel>
            <TextBlock Text="Hello" />
        </StackPanel>
    </Border>
</Window>

Pour obtenir la liste de référence de toutes les extensions de balisage XAML spécifiquement implémentées dans WPF, consultez Extensions XAML WPF. Pour obtenir une liste de référence des extensions de balisage définies par System.Xaml et qui sont plus largement disponibles pour les implémentations XAML .NET, consultez les fonctionnalités du langage de l’espace de noms XAML (x :). Pour plus d’informations sur les concepts d’extension de balisage, consultez Extensions de balisage et XAML WPF.

Convertisseurs de type

La section Syntaxe XAML en bref indique que la valeur d’attribut doit pouvoir être définie par une chaîne. La gestion native de base appliquée à la conversion des chaînes en d’autres types d’objets ou de valeurs primitives repose sur le type String lui-même, en plus du traitement natif de certains types tels que DateTime ou Uri. Cependant, plusieurs types WPF ou membres de ces types étendent le comportement de traitement des attributs de chaîne de base, de telle sorte que les instances de types d’objets plus complexes peuvent être spécifiées comme des chaînes et des attributs.

La structure Thickness est un exemple de type qui a une conversion de type activée pour les utilisations XAML. Thickness indique les mesures dans un rectangle imbriqué et est utilisée comme valeur pour les propriétés telles que Margin. En plaçant un convertisseur de type sur Thickness, toutes les propriétés qui utilisent Thickness sont plus faciles à spécifier en XAML, car elles peuvent être spécifiées en tant qu’attributs. L’exemple suivant utilise une conversion de type et la syntaxe d’attributs pour fournir une valeur à Margin :

<Button Margin="10,20,10,30" Content="Click me"/>

L’exemple de syntaxe d’attributs précédent est équivalent à l’exemple suivant qui est plus détaillé, où Margin est plutôt défini par la syntaxe des éléments de propriété contenant un élément objet Thickness. Les quatre propriétés principales de Thickness sont définies comme attributs sur la nouvelle instance :

<Button Content="Click me">
    <Button.Margin>
        <Thickness Left="10" Top="20" Right="10" Bottom="30"/>
    </Button.Margin>
</Button>

Remarque

Il existe également un nombre limité d’objets pour lesquels la conversion de type est la seule manière publique de définir une propriété pour le type voulu, sans impliquer une sous-classe, car le type lui-même n’a pas de constructeur sans paramètre. par exemple Cursor.

Pour plus d’informations sur la conversion de type, consultez TypeConverters et XAML.

Éléments racines et espaces de noms

Un fichier XAML ne doit avoir qu’un seul élément racine afin d’être à la fois un fichier XML correctement structuré et un fichier XAML valide. Pour les scénarios WPF classiques, vous utilisez un élément racine qui a une signification importante dans le modèle d’application WPF (par exemple, Window ou Page pour une page, ResourceDictionary pour un dictionnaire externe ou Application pour la définition de l’application). L’exemple suivant montre l’élément racine d’un fichier XAML type pour une page WPF, avec l’élément racine de Page.

<Page x:Class="index.Page1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="Page1">

</Page>

L’élément racine contient également les attributs xmlns et xmlns:x. Ces attributs indiquent à un processeur XAML les espaces de noms XAML contenant les définitions de types pour les types de stockage qui vont être référencés en tant qu’éléments par le balisage. L’attribut xmlns indique explicitement l’espace de noms XAML par défaut. Dans l’espace de noms XAML par défaut, les éléments objet dans le balisage peuvent être spécifiés sans préfixe. Pour la plupart des scénarios d’application WPF et pour presque tous les exemples donnés dans les sections WPF du kit SDK, l’espace de noms XAML par défaut est mappé à l’espace de noms WPF http://schemas.microsoft.com/winfx/2006/xaml/presentation. L’attribut xmlns:x indique un espace de noms XAML supplémentaire qui mappe l’espace de noms du langage XAML http://schemas.microsoft.com/winfx/2006/xaml.

Cette utilisation de xmlns pour définir une étendue de l’utilisation et le mappage d’une portée de nom est conforme à la spécification XML 1.0. Les portées de nom XAML se distinguent des portées de nom XML uniquement parce qu’elles renseignent aussi sur la façon dont les éléments de la portée de nom sont stockés par les types lors d’une résolution de type et d’une analyse du code XAML.

Les attributs xmlns ne sont strictement nécessaires que sur l’élément racine de chaque fichier XAML. Les définitions xmlns s’appliquent à tous les éléments descendants de l’élément racine (ce comportement est encore une fois conforme à la spécification XML 1.0 pour xmlns), tandis que les attributs xmlns sont également autorisés sur d’autres éléments situés sous la racine et s’appliquent à tous les éléments descendants de l’élément de définition. Toutefois, si vous définissez/redéfinissez fréquemment les espaces de noms XAML, le style de balisage XAML peut devenir difficile à lire.

L’implémentation WPF de son processeur XAML inclut une infrastructure qui a connaissance des assemblys principaux WPF. Les assemblys principaux WPF sont connus pour contenir les types qui prennent en charge les mappages WPF à l’espace de noms XAML par défaut. Cette option est activée par le biais de la configuration faisant partie du fichier de build de votre projet et des systèmes de projet et de build WPF. Par conséquent, déclarer l’espace de noms XAML par défaut comme xmlns par défaut est la seule chose à faire pour référencer les éléments XAML provenant des assemblys WPF.

Le préfixe x

Dans l’exemple d’élément racine précédent, le préfixe x: a été utilisé pour mapper l’espace de noms XAML http://schemas.microsoft.com/winfx/2006/xaml, qui est l’espace de noms XAML dédié prenant en charge les constructions du langage XAML. Ce préfixe x: est utilisé pour mapper cet espace de noms XAML dans les modèles de projets, les exemples et dans la documentation de ce kit SDK. L’espace de noms XAML du langage XAML contient plusieurs constructions de programmation que vous allez être amené à utiliser fréquemment dans votre XAML. Voici une liste de constructions de programmation avec le préfixe x: parmi les plus courantes que vous allez utiliser :

  • x:Key : définit une clé unique pour chaque ressource dans un ResourceDictionary (ou des concepts de dictionnaires semblables dans d’autres frameworks). x:Key représente probablement 90 % des utilisations de x: que vous pouvez voir dans le balisage classique d’une application WPF.

  • x:Class : spécifie l’espace de noms CLR et le nom de la classe qui fournit le code-behind pour une page XAML. Vous devez disposer d’une telle classe pour prendre en charge le code-behind selon le modèle de programmation WPF, et c’est la raison pour laquelle vous voyez presque toujours x: mappé, même s’il n’ y a aucune ressource.

  • x:Name : spécifie un nom d’objet d’exécution pour l’instance qui existe dans le code d’exécution après le traitement d’un élément objet. En général, vous êtes amené à utiliser fréquemment une propriété équivalente définie par WPF pour x:Name. Ces propriétés mappent spécifiquement à une propriété de stockage CLR et sont donc plus pratiques pour la programmation d’applications, où vous utilisez fréquemment du code d’exécution pour rechercher les éléments nommés à partir du XAML initialisé. La propriété la plus courante est FrameworkElement.Name. Vous pouvez encore utiliser x:Name lorsque la propriété équivalente Name de niveau framework WPF n’est pas prise en charge dans un type particulier. Ce cas se présente dans certains scénarios d’animation.

  • x:Static : active une référence qui retourne une valeur statique qui, sinon, n’est pas une propriété compatible XAML.

  • x:Type : construit une référence Type basée sur un nom de type. Il est utilisé pour spécifier des attributs qui prennent Type, comme Style.TargetType, même si la propriété a fréquemment une conversion de chaîne en Type native de manière à rendre l’utilisation de l’extension de balisage x:Type facultative.

Il existe d’autres constructions de programmation dans l’espace de noms XAML à préfixe x: qui ne sont pas aussi courantes. Pour plus d’informations, consultez Fonctionnalités de langage pour les espaces de noms XAML (x:).

Préfixes personnalisés et types personnalisés

Pour vos propres assemblys personnalisés ou pour des assemblys hors du noyau WPF de PresentationCore, PresentationFramework et WindowsBase, vous pouvez spécifier l’assembly en question dans le cadre d’un mappage xmlns personnalisé. Vous pouvez ensuite référencer des types depuis cet assembly dans votre XAML à partir du moment où le type voulu est correctement implémenté pour prendre en charge les utilisations XAML que vous essayez.

Voici un exemple simple de fonctionnement des préfixes personnalisés dans le balisage XAML. Le préfixe custom est défini dans la balise d’élément racine et mappé à un assembly spécifique qui est empaqueté et disponible avec l’application. Cet assembly contient un type NumericUpDown, qui est implémenté pour prendre en charge l’utilisation générale de XAML ainsi que l’utilisation d’un héritage de classe, autorisant son insertion à ce stade dans un modèle de contenu XAML WPF. Une instance de ce contrôle NumericUpDown est déclaré comme élément objet en utilisant le préfixe afin qu’un analyseur XAML identifie quel espace de noms XAML contient le type et par conséquent l’emplacement de l’assembly de stockage contenant la définition de type.

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:NumericUpDownCustomControl;assembly=CustomLibrary"
    >
  <StackPanel Name="LayoutRoot">
    <custom:NumericUpDown Name="numericCtrl1" Width="100" Height="60"/>
...
  </StackPanel>
</Page>

Pour plus d’informations sur les types personnalisés en XAML, consultez XAML et les classes personnalisées pour WPF.

Pour plus d’informations sur la relation entre les espaces de noms du code dans les assemblys et les espaces de noms XML, consultez Espaces de noms XAML et mappage d’espaces de noms pour XAML WPF.

Événements et code-Behind XAML

La plupart des applications WPF se composent de balises XAML et de code-behind. Dans un projet, le code XAML est écrit sous la forme d’un fichier .xaml et d’un langage CLR, si bien que Microsoft Visual Basic ou C# est utilisé pour écrire un fichier code-behind. Lors de la compilation du balisage d’un fichier XAML comme partie intégrante des modèles de programmation et d’application WPF, l’emplacement du fichier code-behind XAML pour un fichier XAML est identifié en spécifiant un espace de noms et une classe en tant qu’attribut x:Class de l’élément racine du XAML.

Jusqu’ici dans les exemples étudiés, vous avez vu plusieurs boutons, mais aucun d’eux n’avait encore de comportement logique qui lui était associé. Au niveau de l’application, le mécanisme principal permettant d’ajouter un comportement à un élément objet consiste à utiliser un événement existant de la classe élément et à écrire un gestionnaire spécifique pour cet événement qui est appelé lorsque l’événement est déclenché au moment de l’exécution. Le nom de l’événement et celui du gestionnaire à utiliser sont spécifiés dans le balisage, tandis que le code qui implémente le gestionnaire est défini dans le fichier code-behind.

<Page x:Class="ExampleNamespace.ExamplePage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel>
        <Button Click="Button_Click">Click me</Button>
    </StackPanel>
</Page>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace ExampleNamespace;

public partial class ExamplePage : Page
{
    public ExamplePage() =>
        InitializeComponent();

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var buttonControl = (Button)e.Source;
        buttonControl.Foreground = Brushes.Red;
    }
}
Class ExamplePage
    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        Dim buttonControl = DirectCast(e.Source, Button)
        buttonControl.Foreground = Brushes.Red
    End Sub
End Class

Notez que le fichier code-behind utilise l’espace de noms ExampleNamespace CLR (l’espace de noms n’est pas visible en Visual Basic) et déclare ExamplePage en tant que classe partielle dans cet espace de noms. Cela met en parallèle la valeur d’attribut x:Class de ExampleNamespace.ExamplePage qui a été fournie dans la racine de la balise. Le compilateur de balisage WPF crée une classe partielle pour tout fichier XAML compilé, en dérivant une classe à partir du type d’élément racine. Lorsque vous fournissez le code-behind qui définit également la même classe partielle, le code résultant est combiné dans le même espace de noms et la même classe de l’application compilée.

Important

Dans Visual Basic, l’espace de noms racine est implicite pour le code-behind et XAML. Seuls les espaces de noms imbriqués sont visibles. Cet article illustre le code XAML du projet C#.

Pour plus d’informations sur la configuration requise liée à la programmation de code-behind dans WPF, consultez la section Exigences concernant le code-behind, le gestionnaire d’événements et les classes partielles dans WPF.

Si vous ne souhaitez pas créer de fichier code-behind distinct, vous pouvez également incorporer votre code dans un fichier XAML. Toutefois, le code incorporé est une technique moins flexible qui présente des limitations importantes. Pour plus d’informations, voir Code d’arrière-plan et XAML dans WPF.

Événements routés

Un événement routé est une fonctionnalité d’événement particulière qui est fondamentale pour WPF. Les événements routés permettent à un élément de gérer un événement déclenché par un élément différent, tant que ces éléments sont connectés via une relation d’arborescence. Lorsque vous spécifiez la gestion des événements avec un attribut XAML, vous pouvez écouter et géré l’événement routé sur n’importe quel élément, notamment les éléments qui ne listent pas cet événement particulier dans la table des membres de la classe. Pour cela, vous devez qualifier l’attribut de nom d’événement avec le nom de la classe propriétaire. Par exemple, le parent StackPanel dans l’exemple StackPanel / Button en cours peut enregistrer un gestionnaire pour l’événement Click du bouton élément enfant en spécifiant l’attribut Button.Click sur l’élément objet StackPanel, avec le nom de votre gestionnaire comme valeur d’attribut. Pour plus d’informations, consultez Vue d’ensemble des événements acheminés.

Éléments nommés

Par défaut, l’instance d’objet qui est créée par le traitement d’un élément objet XAML dans un graphique d’objet n’a pas d’identificateur unique ni de référence d’objet. En revanche, si vous appelez un constructeur dans le code, vous utilisez presque toujours le résultat du constructeur pour définir une variable sur l’instance construite, afin de pouvoir référencer l’instance ultérieurement dans votre code. Pour fournir un accès standardisé aux objets créés via une définition de balise, XAML définit l’attribut x:Name. Vous pouvez définir la valeur de l’attribut x:Name sur n’importe quel élément objet. Dans votre code-behind, l’identificateur que vous choisissez équivaut à une variable d’instance qui fait référence à l’instance construite. Dans tous les cas, les éléments nommés fonctionnent comme s’ils étaient des instances d’objet (le nom fait référence à cette instance) et votre code-behind peut référencer les éléments nommés pour gérer les interactions au moment de l’exécution dans l’application. Cette connexion entre instances et variables est accomplie par le compilateur de balisage XAML WPF, et implique plus particulièrement des fonctionnalités et des modèles tels que InitializeComponent qui ne sont pas abordés en détail dans cet article.

Les éléments XAML du niveau framework WPF héritent d’une propriété Name, qui équivaut à l’attribut x:Name défini par XAML. Certaines autres classes fournissent également des équivalents de niveau propriété pour x:Name, qui est aussi généralement défini en tant que propriété Name. En règle générale, si vous ne trouvez pas une propriété Name dans la table des membres pour votre élément/type choisi, utilisez x:Name à la place. Les valeurs x:Name fournissent un identificateur à un élément XAML qui peut être utilisé au moment de l’exécution, soit par les sous-systèmes spécifiques, soit par les méthodes utilitaires telles que FindName.

L'exemple suivant ajoute Name sur un élément StackPanel. Ensuite, un gestionnaire sur un Button au sein de cette StackPanel fait référence au StackPanel par le biais de sa référence d’instance buttonContainer comme défini par Name.

<StackPanel Name="buttonContainer">
    <Button Click="RemoveThis_Click">Click to remove this button</Button>
</StackPanel>
private void RemoveThis_Click(object sender, RoutedEventArgs e)
{
    var element = (FrameworkElement)e.Source;
    
    if (buttonContainer.Children.Contains(element))
        buttonContainer.Children.Remove(element);
}
Private Sub RemoveThis_Click(sender As Object, e As RoutedEventArgs)
    Dim element = DirectCast(e.Source, FrameworkElement)

    If buttonContainer.Children.Contains(element) Then
        buttonContainer.Children.Remove(element)
    End If
End Sub

Tout comme une variable, le nom XAML d’une instance est régi par un concept de portée afin que les noms puissent être appliqués pour être uniques dans une certaine étendue qui est prévisible. La balisage principal qui définit une page désigne une portée de nom XAML unique, avec pour élément racine de cette page, les limites de portée de nom XAML. Toutefois, d’autres sources de balisage peuvent interagir avec une page au moment de l’exécution, telles que les styles ou les modèles dans les styles, et ces sources possèdent souvent leur propre portée de nom XAML qui ne se connecte pas nécessairement à la portée de nom XAML de la page. Pour plus d’informations sur x:Name et les portées de nom XAML, consultez Name, x:Name, directive ou Portées de nom XAML WPF.

Propriétés jointes et événements attachés

XAML spécifie une fonctionnalité de langage qui permet à certaines propriétés ou événements d’être spécifiés sur un élément, même si la propriété ou l’événement n’existe pas dans les définitions du type pour l’élément sur lequel il est défini. La version des propriétés de cette fonctionnalité est appelée une propriété jointe, et la version des événements, un événement attaché. D’un point de vue conceptuel, vous pouvez considérer les propriétés jointes et les événements attachés comme des membres globaux pouvant être définis sur n’importe quelle instance d’élément ou d’objet XAML. Toutefois, cet élément/cette classe ou une infrastructure plus importante doit prendre en charge une banque de propriétés de stockage pour les valeurs attachées.

Les propriétés jointes en XAML sont généralement utilisées dans la syntaxe d’attributs. Dans la syntaxe d’attributs, vous spécifiez une propriété jointe sous la forme ownerType.propertyName.

En apparence, cela ressemble à une utilisation d’élément de propriété, mais dans ce cas le ownerType que vous spécifiez est toujours un type différent de l’élément objet dans lequel la propriété jointe est définie. ownerType est le type qui fournit les méthodes d’accesseur demandées par un processeur XAML pour obtenir ou définir la valeur de propriété jointe.

Le scénario le plus courant pour les propriétés jointes consiste à permettre aux éléments enfants de signaler une valeur de propriété à leur élément parent.

L'exemple suivant illustre la propriété jointe DockPanel.Dock. La classe DockPanel définit les accesseurs pour DockPanel.Dock et possède la propriété jointe. La classe DockPanel inclut également une logique qui itère ses éléments enfants et vérifie spécifiquement chaque élément pour obtenir une valeur définie de DockPanel.Dock. Si une valeur est trouvée, cette valeur est utilisée au cours de la disposition pour positionner les éléments enfants. L’utilisation de la propriété jointe DockPanel.Dock et cette fonctionnalité de positionnement est en fait le scénario de motivation pour la classe DockPanel .

<DockPanel>
    <Button DockPanel.Dock="Left" Width="100" Height="20">I am on the left</Button>
    <Button DockPanel.Dock="Right" Width="100" Height="20">I am on the right</Button>
</DockPanel>

Dans WPF, la plus grande partie ou la totalité des propriétés jointes sont également implémentées en tant que propriétés de dépendance. Pour plus d’informations, consultez Vue d’ensemble des propriétés jointes.

Les événements attachés utilisent une forme ownerType.eventName similaire à la syntaxe d’attributs. À l’instar des événements non attachés, la valeur d’attribut d’un événement attaché en XAML spécifie le nom de la méthode de gestionnaire qui est appelée lorsque l’événement est géré sur l’élément. Les utilisations d’événements attachés en XAML WPF sont moins courantes. Pour plus d’informations, consultez Vue d’ensemble des événements attachés.

Types de base

Le XAML WPF sous-jacent et son espace de noms XAML représentent une collection de types correspondant aux objets CLR et aux éléments de balisage pour XAML. Cela étant, toutes les classes ne peuvent pas être mappées aux éléments. Les classes abstraites, telles que ButtonBase, et certaines classes de base non abstraites, sont utilisées pour l’héritage dans le modèle d’objets CLR. Les classes de base, y compris abstraites, sont toujours importantes pour le développement en XAML, car chacun des éléments XAML concrets hérite de membres provenant d’une classe de base dans sa hiérarchie. Ces membres incluent souvent des propriétés qui peuvent être définies en tant qu’attributs sur l’élément, ou comme événements qui peuvent être gérés. FrameworkElement est la classe d’interface utilisateur de base concrète de WPF au niveau de l’infrastructure WPF. Lors de la conception d’une IU, vous êtes amené à utiliser diverses classes, telles que forme, panneau, décorateur ou contrôle, qui dérivent toutes de FrameworkElement. Une classe de base associée, FrameworkContentElement, prend en charge les éléments orientés document qui fonctionnent bien pour une présentation de disposition de flux, à l’aide d’API qui reflètent délibérément les API dans FrameworkElement. La combinaison d’attributs au niveau de l’élément et d’un modèle d’objet CLR vous fournit un ensemble de propriétés communes qui peuvent être définies sur les éléments XAML les plus concrets, quel que soit l’élément XAML spécifique et son type sous-jacent.

Sécurité

Le XAML est un langage de balisage qui représente directement l’instanciation d’objets et leur exécution. C’est pourquoi les éléments créés en XAML ont la même capacité d’interagir avec les ressources système (accès réseau, e/s de système de fichiers, par exemple) que le code de votre application. XAML a également le même accès aux ressources système que l’application d’hébergement.

Sécurité d’accès du code (CAS) dans WPF

Contrairement à .NET Framework, WPF pour .NET ne prend pas en charge le cas. Pour plus d’informations, consultez Différences de Sécurité d’accès du code.

Charger XAML à partir du code

Vous utilisez XAML pour définir l’ensemble de l’interface utilisateur, mais il est parfois également judicieux de ne définir qu’une partie de l’interface utilisateur en XAML. Cette fonctionnalité peut être utilisée pour :

  • Activer la personnalisation partielle.
  • Le stockage local des informations de l’interface utilisateur.
  • Modéliser un objet métier.

La clé de ces scénarios est la classe XamlReader et sa méthode Load. L’entrée est un fichier XAML, et la sortie un objet représentant l’intégralité de l’arborescence d’exécution des objets qui a été créée à partir de ce balisage. Vous pouvez ensuite insérer l’objet pour qu’il soit une propriété d’un autre objet existant déjà dans l’application. Tant que la propriété est dans le modèle de contenu et dispose de capacités d’affichage qui informent le moteur d’exécution de l’ajout de nouveau contenu à l’application, vous pouvez modifier facilement un contenu d’application en cours d’exécution par le chargement dynamique en XAML.

Voir aussi