Partager via


Vue d’ensemble du code XAML

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 spécifiquement le code XAML comme implémenté par WPF. XAML lui-même est un concept de langage plus grand que WPF.

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 le balisage XAML déclaratif, puis séparer la définition de l’interface utilisateur de la logique d’exécution à l’aide de fichiers code-behind joints au balisage par le biais de définitions de classes partielles. XAML représente directement l’instanciation des objets dans un ensemble spécifique de types de support définis dans les assemblies. Cela est différent de la plupart des autres langages de balisage, qui sont généralement des langages interprétés sans une liaison directe à un système de types sous-jacent. XAML permet un flux de travail où des parties distinctes peuvent travailler sur l’interface utilisateur et la logique d’une application, à l’aide d’outils potentiellement différents.

Lorsqu’ils sont 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 n’importe quel encodage XML, mais l’encodage en UTF-8 est classique.

L’exemple suivant montre comment créer un bouton dans le cadre d’une interface utilisateur. Cet exemple est destiné à vous donner une saveur de la façon dont XAML représente les métaphores courantes de programmation d’interface utilisateur (il ne s’agit pas d’un exemple complet).

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

Syntaxe XAML en bref

Les sections suivantes expliquent les formes de base de la syntaxe XAML et donnent un court exemple de balisage. Ces sections ne sont pas destinées à fournir des informations complètes sur chaque forme de syntaxe, comme la façon dont elles sont représentées dans le système de types sous-jacent. Pour plus d’informations sur les spécificités de la syntaxe XAML, consultez Syntaxe XAML en détail.

La majeure partie du matériel dans les sections suivantes sera élémentaire pour vous si vous connaissez déjà le langage XML. Il s’agit d’une des conséquences de l’un des principes de conception de base de XAML. Le langage XAML définit les concepts de son propre, mais ces concepts fonctionnent dans le langage XML et le formulaire de balisage.

Éléments d’objet XAML

Un élément d’objet déclare généralement une instance d’un type. Ce type est défini dans les assemblies que la technologie utilisant XAML comme langue référence.

La syntaxe de l’élément objet commence toujours par un crochet d’angle ouvrant (<). Ceci est suivi du nom du type dans lequel vous souhaitez créer une instance. (Le nom peut inclure un préfixe, un concept qui sera expliqué ultérieurement.) Après cela, vous pouvez éventuellement déclarer des attributs sur l’élément objet. Pour terminer la balise d’élément d’objet, terminez par un crochet d’angle fermant (>). Vous pouvez plutôt utiliser un formulaire auto-fermant qui n’a pas de contenu, en terminant la balise avec une barre oblique et un crochet d’angle fermant en succession (/>). Par exemple, examinez à nouveau l’extrait de code de balisage précédemment affiché.

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

Cela spécifie deux éléments d’objet : <StackPanel> (avec du contenu et une balise fermante ultérieurement) et <Button .../> (formulaire auto-fermant, avec plusieurs attributs). Les éléments d'objet StackPanel et Button correspondent chacun au nom d'une classe définie par WPF et font partie des assemblages WPF. Lorsque vous spécifiez une balise d’élément d’objet, vous créez une instruction pour le traitement XAML pour créer une 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 en cours de définition, suivie de l’opérateur d’affectation (=). La valeur d’un attribut est toujours spécifiée sous la forme d’une chaîne contenue entre guillemets.

La syntaxe d’attribut est la syntaxe de paramètre de propriété la plus rationalisée et est la syntaxe la plus intuitive à utiliser pour les développeurs qui ont utilisé des langages de balisage dans le passé. Par exemple, le balisage suivant crée un bouton qui a du texte rouge et un arrière-plan bleu avec un texte d’affichage de Content.

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

Syntaxe de l’élément Property

Pour certaines propriétés d’un élément objet, la syntaxe d’attribut n’est pas possible, car l’objet ou les informations nécessaires pour fournir la valeur de propriété ne peuvent pas être exprimées adéquatement dans les restrictions de guillemets et de chaîne de syntaxe d’attribut. Dans ce cas, une syntaxe différente appelée syntaxe d’élément de propriété peut être utilisée.

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, l’utilisation de la syntaxe d’attribut est généralement plus pratique et active un balisage plus compact, mais ce n’est souvent qu’une question de style, et non une limitation technique. L’exemple suivant montre les mêmes propriétés définies que dans l’exemple de syntaxe d’attribut précédent, mais cette fois à l’aide de la syntaxe d’élément de propriété pour toutes les propriétés du 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 inclut certaines optimisations qui produisent des marques plus lisibles par l’homme. Une telle optimisation est que si une propriété particulière accepte un type de collection, les éléments enfants que vous déclarez dans le markup comme faisant partie de la valeur de cette propriété deviennent partie de la collection. Dans ce cas, une collection d’éléments d’objets enfants constitue la valeur attribuée à la propriété de collection.

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

<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 exactement l’une de ses propriétés pour être 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 de manière unique, 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é de contenu de Child. Les deux Border éléments suivants sont traités de façon identique. Le premier exploite la syntaxe de la propriété de contenu et omet l'élément de propriété Border.Child. La deuxième montre Border.Child explicitement.

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

En règle du langage XAML, la valeur d’une propriété de contenu XAML doit être donnée entièrement avant ou entièrement après d’autres éléments de propriété sur cet élément objet. Par exemple, le balisage suivant ne se compile pas.

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

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

Contenu textuel

Un petit nombre d’éléments XAML peuvent traiter directement le texte en tant que contenu. Pour l’activer, l’un des cas suivants doit être vrai :

  • 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, tout ContentControl utilise Content comme sa propriété de contenu et son type est Object, ce qui prend en charge l’utilisation suivante sur un ContentControl comme Button : <Button>Hello</Button>.

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

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

Propriétés de contenu et syntaxe de collection combinées

Prenons cet exemple.

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

Ici, chacun Button est un élément enfant de StackPanel. Il s’agit d’un balisage simplifié 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 propriété de contenu XAML.

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

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

Syntaxe d’attribut (événements)

La syntaxe d’attribut peut également être utilisée 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 des événements pour XAML, la valeur de l’attribut est le nom d’un gestionnaire qui implémente le délégué de cet é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 y a plus d’événements et XAML dans WPF que cet exemple de syntaxe d’attribut. Par exemple, vous pouvez vous demander ce que la ClickHandler référence représente et comment elle est définie. Cela sera expliqué dans la section Événements à venir et code-behind XAML de cet article.

Case et espace blanc en XAML

En général, XAML respecte la casse. Pour résoudre les types de prise en charge, WPF XAML respecte la casse selon les mêmes règles que le CLR. Les éléments d’objet, les éléments de propriété et les noms d’attributs doivent tous être spécifiés à l’aide de la casse sensible par rapport au type sous-jacent dans l’assembly ou à un membre d’un type. Les mots clés et primitives du langage XAML respectent également la casse. Les valeurs ne sont pas toujours sensibles à la casse. La sensibilité à la casse pour les valeurs dépend du comportement du convertisseur de type associé à la propriété qui accepte la valeur, ou du type de la valeur de cette propriété. Par exemple, les propriétés qui acceptent le Boolean type peuvent prendre des true valeurs équivalentes ou True en tant que valeurs équivalentes, mais uniquement parce que la conversion de type d’analyseur XAML WPF native pour la chaîne Boolean autorise déjà ces valeurs en tant qu’équivalents.

Les processeurs XAML WPF et les sérialiseurs ignorent ou suppriment tous les espaces blancs non significatifs et normalisent tout espace blanc significatif. Cela est cohérent avec les recommandations de comportement d’espace blanc par défaut de la spécification XAML. Ce comportement n’est de conséquence que lorsque vous spécifiez des chaînes dans les propriétés de contenu XAML. En termes les plus simples, XAML convertit l’espace, le flux de lignes et les caractères de tabulation en espaces, puis conserve un espace s’il se trouve à l’une des extrémités d’une chaîne contiguë. L’explication complète de la gestion des espaces blancs XAML n’est pas abordée dans cet article. Pour plus d’informations, consultez Traitement de l’espace blanc en XAML.

Extensions de balisage

Les extensions de balisage sont un concept de langage XAML. Lorsqu’il est utilisé pour fournir la valeur d’une syntaxe d’attribut, les accolades ({ et }) indiquent une utilisation de l’extension de balisage. Cette utilisation dirige le traitement XAML vers l’échappement du traitement général des valeurs d’attribut sous la forme d’une chaîne littérale ou d’une valeur convertible en chaîne.

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

Par exemple, le balisage suivant définit la valeur de la propriété à l’aide de la Style syntaxe d’attribut. La Style propriété prend une instance de la Style classe, qui par défaut n’a pas pu être instanciée par une chaîne de syntaxe d’attribut. Mais dans ce cas, 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 précédemment instancié en tant que ressource clé 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 une liste de références de toutes les extensions de balisage pour XAML implémentées spécifiquement 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 types

Dans la section Syntaxe XAML dans Brève , il a été indiqué que la valeur d’attribut doit être définie par une chaîne. La gestion native de base de la façon dont les chaînes sont converties en d’autres types d’objets ou valeurs primitives est basée sur le type String lui-même, ainsi qu'un traitement natif pour certains types tels que DateTime et Uri. Toutefois, de nombreux 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 en tant que chaînes et attributs.

La Thickness structure 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 un Thickness sont plus faciles à spécifier en XAML, car elles peuvent être spécifiées en tant qu’attributs. L’exemple suivant utilise une syntaxe de conversion de type et d’attribut pour fournir une valeur pour un Margin:

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

L'exemple précédent de syntaxe d'attribut est équivalent à l'exemple plus détaillé suivant, où le Margin est défini via la syntaxe de l'élément de propriété contenant un élément objet Thickness. Les quatre propriétés clés de Thickness sont définies en tant qu’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 où la conversion de type est la seule façon publique de définir une propriété sur ce type sans impliquer de 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, pour être à la fois un fichier XML bien formé 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 pour Page 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 classique 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 quels espaces de noms XAML contiennent les définitions de types pour les types de support que le balisage référencera en tant qu’éléments. L’attribut xmlns indique spécifiquement l’espace de noms XAML par défaut. Dans l’espace de noms XAML par défaut, les éléments d’objet du 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 de développement logiciel (SDK), l’espace de noms XAML par défaut est mappé à l’espace de noms http://schemas.microsoft.com/winfx/2006/xaml/presentationWPF. L’attribut xmlns:x indique un espace de noms XAML supplémentaire, qui mappe l’espace de noms http://schemas.microsoft.com/winfx/2006/xamldu langage XAML.

Cette utilisation de xmlns définir une étendue pour l’utilisation et le mappage d’un namescope est cohérente avec la spécification XML 1.0. Les portées de noms XAML sont différentes des portées de noms XML uniquement dans le sens où un namescope XAML implique également quelque chose sur la façon dont les éléments de namescope sont soutenus par des types lorsqu’il s’agit de la résolution de type et de l’analyse du code XAML.

Les xmlns attributs ne sont strictement nécessaires que sur l’élément racine de chaque fichier XAML. xmlns les définitions s’appliquent à tous les éléments descendants de l’élément racine (ce comportement est à nouveau cohérent avec la spécification XML 1.0 pour xmlns.) xmlns les attributs sont également autorisés sur d’autres éléments sous la racine et s’appliquent à tous les éléments descendants de l’élément de définition. Toutefois, la définition fréquente ou la redéfinition des espaces de noms XAML peut entraîner un style de balisage XAML difficile à lire.

L’implémentation WPF de son processeur XAML comprend une infrastructure qui reconnaît les assemblages principaux de WPF. Les assemblies principaux WPF sont réputés contenir les types qui prennent en charge les mappages de WPF vers l'espace de noms XAML par défaut. Cela est activé par le biais de la configuration qui fait partie de votre fichier de build de projet et des systèmes de build et de projet WPF. Par conséquent, déclarer l’espace de noms XAML comme la valeur par défaut xmlns est tout ce qui est nécessaire pour référencer des éléments XAML provenant d’assemblies 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 http://schemas.microsoft.com/winfx/2006/xamlXAML, qui est l’espace de noms XAML dédié qui prend en charge les constructions de langage XAML. Ce x: préfixe est utilisé pour mapper cet espace de noms XAML dans les modèles de projets, dans des exemples et dans la documentation de ce Kit de développement logiciel (SDK). L’espace de noms XAML pour le langage XAML contient plusieurs constructions de programmation que vous utiliserez fréquemment dans votre code XAML. Voici une liste des constructions de programmation de préfixe les plus courantes x: que vous allez utiliser :

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

  • x :Class : spécifie l’espace de noms CLR et le nom de classe de la classe qui fournit du code-behind pour une page XAML. Vous devez avoir une telle classe spécifique pour prendre en charge le code-behind (code en arrière-plan) selon le modèle de programmation WPF, et donc, vous voyez x: presque toujours associé, même s'il n'y a pas de ressources.

  • 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 utiliserez 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 code XAML initialisé. La propriété la plus courante est FrameworkElement.Name. Vous pouvez toujours utiliser x :Name lorsque la propriété de niveau Name framework WPF équivalente n’est pas prise en charge dans un type particulier. Cela se produit dans certains scénarios d’animation.

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

  • x :Type : construit une Type référence basée sur un nom de type. Cela permet de spécifier des attributs qui prennent Type, par exemple Style.TargetType, bien que la propriété ait souvent une conversion native de chaîne en Type rendant ainsi l’utilisation de l’extension de balisage x:Type facultative.

Il existe des constructions de programmation supplémentaires dans l'espace de noms préfixé/XAML x:, qui ne sont pas très courantes. Pour plus d’informations, consultez Fonctionnalités du langage de l’espace de noms XAML (x :).

Préfixes personnalisés et types personnalisés

Pour vos propres assemblys personnalisés ou pour les assemblys en dehors du cœur WPF de PresentationCore, PresentationFramework et WindowsBase, vous pouvez spécifier l’assembly dans le cadre d’un mappage personnalisé xmlns . Vous pouvez ensuite référencer des types à partir de cet assembly dans votre code XAML, tant que ce type est correctement implémenté pour prendre en charge les utilisations XAML que vous tentez.

Voici un exemple de base de la façon dont les préfixes personnalisés fonctionnent dans le balisage XAML. Le préfixe custom est défini dans la balise d’élément racine et mappé à un assembly spécifique 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 du code XAML, ainsi que l’utilisation d’un héritage de classe qui autorise son insertion à ce stade particulier dans un modèle de contenu XAML WPF. Une instance de ce contrôle NumericUpDown est déclarée en tant qu’élément objet, en utilisant le préfixe afin qu’un analyseur XAML sache quel espace de noms XAML contient le type et où se trouve l’assembly de soutien qui contient la définition du 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 Classes personnalisées pour WPF.

Pour plus d’informations sur la façon dont les espaces de noms XML et les espaces de noms de code dans les assemblys sont associés, consultez Les espaces de noms XAML et le mappage d’espaces de noms pour WPF XAML.

Événements et XAML code-behind

La plupart des applications WPF se composent de balisage XAML et de code associé. Dans un projet, le code XAML est écrit en tant que .xaml fichier et un langage CLR tel que Microsoft Visual Basic ou C# est utilisé pour écrire un fichier code-behind. Lorsqu'un fichier XAML est compilé dans le cadre des modèles de programmation et d’application WPF, l’emplacement du fichier code-behind pour un fichier XAML est identifié en spécifiant un espace de noms et une classe comme attribut x:Class de l’élément racine du XAML.

Dans les exemples jusqu’à présent, vous avez vu plusieurs boutons, mais aucun de ces boutons n’avait de comportement logique associé à ces boutons. Le mécanisme de niveau application principal pour l’ajout d’un comportement pour un élément objet consiste à utiliser un événement existant de la classe d’élément et à écrire un gestionnaire spécifique pour cet événement appelé lorsque cet événement est déclenché au moment de l’exécution. Le nom de l’événement et le nom du gestionnaire à utiliser sont spécifiés dans le balisage, tandis que le code qui implémente votre gestionnaire est défini dans le 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 fourni dans la racine de balisage. Le compilateur de balisage WPF crée une classe partielle pour tout fichier XAML compilé, en dérivant une classe du type d’élément racine. Lorsque vous fournissez du 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 pour la programmation code-behind dans WPF, consultez Code-behind, Gestionnaire d’événements et Exigences de classe partielle dans WPF.

Si vous ne souhaitez pas créer de fichier code-behind distinct, vous pouvez également inliner votre code dans un fichier XAML. Toutefois, le code inline est une technique moins polyvalente qui présente des limitations substantielles. Pour plus d’informations, consultez Code-Behind et XAML dans WPF.

Événements routés

Une fonctionnalité d’événement particulière qui est fondamentale pour WPF est un événement routé. Les événements routés permettent à un élément de gérer un événement déclenché par un autre élément, tant que les éléments sont connectés via une relation d’arborescence. Lorsque vous spécifiez la gestion des événements avec un attribut XAML, l’événement routé peut être écouté et géré sur n’importe quel élément, y compris les éléments qui ne répertorient pas cet événement particulier dans la table des membres de classe. Pour ce faire, vous devez qualifier l’attribut de nom d’événement avec le nom de classe propriétaire. Par exemple, le parent StackPanel dans l'exemple donné en cours StackPanel / Button pourrait enregistrer un gestionnaire pour l’événement du bouton de l’élément enfant Click 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 créée dans un graphique d’objets en traitant un élément d’objet XAML n’a pas d’identificateur unique ou 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 que vous puissiez référencer l’instance plus loin dans votre code. Pour fournir un accès standardisé aux objets créés par le biais d’une définition de balisage, XAML définit l’attribut x :Name. Vous pouvez définir la valeur de l’attribut x:Name sur n’importe quel élément d’objet. Dans votre code-behind, l’identificateur que vous choisissez est équivalent à une variable d’instance qui fait référence à l’instance construite. À tous égards, les éléments nommés fonctionnent comme s’ils étaient des instances d’objet (le nom 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 les instances et les variables est effectuée par le compilateur de balisage XAML WPF, et implique plus spécifiquement des fonctionnalités et des modèles tels que InitializeComponent ceux-ci ne seront pas abordés en détail dans cet article.

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

L’exemple suivant définit Name sur un StackPanel élément. Ensuite, un gestionnaire sur un Button dans ce StackPanel fait référence au StackPanel via son instance buttonContainer tel que 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 d’étendue, afin que les noms puissent être appliqués pour être uniques dans une certaine étendue prévisible. Le balisage principal qui définit une page désigne un namescope XAML unique, avec la limite du namescope XAML étant l’élément racine de cette page. 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 au sein des styles, et ces sources de balisage ont souvent leurs propres portées de noms XAML qui ne se connectent pas nécessairement avec le namescope XAML de la page. Pour plus d’informations sur x:Name et les portées de noms XAML, consultez Name, x:Name Directive ou WPF XAML Namescopes.

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

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 propriété jointe, la version des événements est appelée événement attaché. Conceptuellement, vous pouvez considérer les propriétés jointes et les événements attachés en tant que membres globaux pouvant être définis sur n’importe quelle instance d’élément/objet XAML. Toutefois, cet élément/classe ou une infrastructure plus grande doit prendre en charge un magasin de propriétés de support pour les valeurs jointes.

Les propriétés jointes en XAML sont généralement utilisées par le biais de la syntaxe d’attribut. Dans la syntaxe d’attribut, vous spécifiez une propriété jointe dans le formulaire ownerType.propertyName.

Superficiellement, cela ressemble à une utilisation des éléments de propriété, mais dans ce cas, le ownerType type que vous spécifiez est toujours différent de l’élément objet où la propriété jointe est définie. ownerType est le type qui fournit les méthodes d’accesseur requises 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 DockPanel.Dock propriété jointe. La DockPanel classe définit les accesseurs pour DockPanel.Dock et possède la propriété jointe. La DockPanel classe inclut également la logique qui itère ses éléments enfants et vérifie spécifiquement chaque élément pour une valeur définie de DockPanel.Dock. Si une valeur est trouvée, cette valeur est utilisée pendant la mise en page pour positionner les éléments enfants. L’utilisation de la propriété attachée DockPanel.Dock et de cette capacité de positionnement est en fait le scénario motivant 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 plupart ou toutes les 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 similaire ownerType.eventName de syntaxe d’attribut. Tout comme les é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 appelée lorsque l’événement est géré sur l’élément. Les usages d’événements attachés dans le XAML WPF sont moins courants. Pour plus d’informations, consultez Vue d’ensemble des événements joints.

Types de base

Le code XAML WPF sous-jacent et son espace de noms XAML sont une collection de types qui correspondent aux objets CLR et aux éléments de balisage pour XAML. Toutefois, 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 les classes abstraites, sont toujours importantes pour le développement XAML, car chacun des éléments XAML concrets hérite des membres 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 des é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 de l’interface utilisateur, vous utiliserez différentes classes de formes, panneaux, décorateurs ou contrôles, qui dérivent toutes de FrameworkElement. Une classe de base associée, FrameworkContentElement, prend en charge les éléments orientés document qui conviennent bien à une mise en page de flux, à l’aide d’API qui sont délibérément calquées sur les API de FrameworkElement. La combinaison d’attributs au niveau de l’élément et d’un modèle objet CLR vous fournit un ensemble de propriétés communes qui sont définies sur la plupart des éléments XAML concrets, quel que soit l’élément XAML spécifique et son type sous-jacent.

Sécurité

XAML est un langage de balisage qui représente directement l’instanciation et l’exécution d’objets. C’est pourquoi les éléments créés en XAML ont la même possibilité d’interagir avec les ressources système (accès réseau, E/S du 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é de l’accès au code (CAS) dans WPF

Contrairement à .NET Framework, WPF .NET ne prend pas en charge la sécurité d'accès au code. Pour plus d’informations, consultez les différences de sécurité d’accès au code.

Charger XAML à partir du code

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

  • Activez la personnalisation partielle.
  • Stockage local des informations d’interface utilisateur.
  • Modélisez un objet métier.

La clé de ces scénarios est la XamlReader classe et sa Load méthode. L’entrée est un fichier XAML et la sortie est un objet qui représente l’arborescence d’exécution des objets créés à partir de ce balisage. Vous pouvez ensuite insérer l’objet comme propriété d’un autre objet qui existe déjà dans l’application. Tant que la propriété se trouve dans le modèle de contenu et dispose de fonctionnalités d’affichage qui avertiront le moteur d’exécution que le nouveau contenu a été ajouté à l’application, vous pouvez modifier facilement le contenu d’une application en cours d’exécution en charge dynamiquement en XAML.

Voir aussi