Partager via


Classes XAML et personnalisées pour WPF

XAML tel qu’implémenté dans les frameworks CLR (Common Language Runtime) prend en charge la possibilité de définir une classe ou une structure personnalisée dans n’importe quel langage CLR (Common Language Runtime), puis d’accéder à cette classe à l’aide du balisage XAML. Vous pouvez utiliser un mélange de types définis par Windows Presentation Foundation (WPF) et de vos types personnalisés dans le même fichier de balisage, généralement en mappant les types personnalisés à un préfixe d’espace de noms XAML. Cette rubrique décrit les exigences qu’une classe personnalisée doit satisfaire pour être utilisable en tant qu’élément XAML.

Classes personnalisées dans des applications ou des assemblys

Les classes personnalisées utilisées en XAML peuvent être définies de deux façons distinctes : au sein du code-behind ou d’un autre code qui produit l’application WPF (Windows Presentation Foundation) principale, ou en tant que classe dans un assembly distinct, tel qu’un exécutable ou une DLL utilisé comme bibliothèque de classes. Chacune de ces approches présente des avantages et des inconvénients particuliers.

  • L’avantage de créer une bibliothèque de classes est que toutes ces classes personnalisées peuvent être partagées entre de nombreuses applications possibles. Une bibliothèque distincte facilite également le contrôle des problèmes de contrôle de version des applications et simplifie la création d’une classe où l’utilisation de classe prévue est un élément racine sur une page XAML.

  • L’avantage de définir les classes personnalisées dans l’application est que cette technique est relativement légère et réduit les problèmes de déploiement et de test rencontrés lorsque vous introduisez des assemblys distincts au-delà du fichier exécutable de l’application principale.

  • Si elles sont définies dans le même assembly ou dans un autre assembly, les classes personnalisées doivent être mappées entre l’espace de noms CLR et l’espace de noms XML afin d’être utilisées en XAML en tant qu’éléments. Consultez les espaces de noms XAML et le mappage des espaces de noms pour WPF XAML.

Configuration requise pour une classe personnalisée en tant qu’élément XAML

Pour pouvoir être instancié en tant qu’élément objet, votre classe doit répondre aux exigences suivantes :

  • Votre classe personnalisée doit être publique et prendre en charge un constructeur public par défaut (sans paramètre). (Consultez la section suivante pour obtenir des notes concernant les structures.)

  • Votre classe personnalisée ne doit pas être une classe imbriquée. Les classes imbriquées et le « point » dans leur syntaxe d’utilisation générale du CLR interfèrent avec d’autres fonctionnalités WPF et/ou XAML telles que les propriétés jointes.

Outre l’activation de la syntaxe des éléments d’objet, votre définition d’objet active également la syntaxe de l’élément de propriété pour toutes les autres propriétés publiques qui prennent cet objet comme type valeur. Cela est dû au fait que l’objet peut maintenant être instancié en tant qu’élément d’objet et remplir la valeur de l’élément de propriété d’une telle propriété.

Structures

Les structures que vous définissez en tant que types personnalisés sont toujours en mesure d’être construites en XAML dans WPF. Cela est dû au fait que les compilateurs CLR créent implicitement un constructeur sans paramètre pour une structure qui initialise toutes les valeurs de propriété à leurs valeurs par défaut. Dans certains cas, le comportement de construction par défaut et/ou l’utilisation des éléments d’objet pour une structure n’est pas souhaitable. Cela peut être dû au fait que la structure est destinée à remplir des valeurs et à fonctionner conceptuellement en tant qu’union, où les valeurs contenues peuvent avoir des interprétations mutuellement exclusives et donc aucune de ses propriétés n’est settable. Un exemple WPF de telle structure est GridLength. En règle générale, ces structures doivent implémenter un convertisseur de type afin que les valeurs puissent être exprimées sous forme d’attribut, à l’aide de conventions de chaîne qui créent les différentes interprétations ou modes des valeurs de la structure. La structure doit également exposer un comportement similaire pour la construction du code par le biais d’un constructeur sans paramètre.

Exigences pour les propriétés d'une classe personnalisée en tant qu'attributs XAML

Les propriétés doivent référencer un type par valeur (tel qu’une primitive) ou utiliser une classe pour le type qui a un constructeur sans paramètre ou un convertisseur de type dédié auquel un processeur XAML peut accéder. Dans l’implémentation XAML CLR, les processeurs XAML trouvent ces convertisseurs soit par le biais de la prise en charge native des primitives de langage, soit par l’application de TypeConverterAttribute à un type ou à un membre dans les définitions de type associées.

Vous pouvez également référencer un type de classe abstrait ou une interface. Pour les classes ou interfaces abstraites, l’attente pour l’analyse XAML est que la valeur de propriété doit être remplie d’instances de classe concrètes qui implémentent l’interface ou des instances de types qui dérivent de la classe abstraite.

Les propriétés peuvent être déclarées sur une classe abstraite, mais peuvent uniquement être définies sur des classes concrètes qui dérivent de la classe abstraite. Cela est dû au fait que la création de l’élément objet pour la classe nécessite un constructeur sans paramètre public sur la classe.

Syntaxe d'attribut TypeConverter activée

Si vous fournissez un convertisseur de type attribué dédié au niveau de la classe, la conversion de type appliquée active la syntaxe d’attribut pour toute propriété qui doit instancier ce type. Un convertisseur de type n’active pas l’utilisation de l’élément objet du type ; seule la présence d’un constructeur sans paramètre pour ce type active l’utilisation des éléments d’objet. Par conséquent, les propriétés qui sont activées pour le convertisseur de type ne sont généralement pas utilisables dans la syntaxe de propriété, sauf si le type lui-même prend également en charge la syntaxe d’élément objet. L’exception à ceci est que vous pouvez spécifier une syntaxe d’élément de propriété, à condition que l’élément de propriété contienne une chaîne. Cette utilisation équivaut essentiellement à une utilisation de la syntaxe des attributs, et ce n'est pas courant à moins qu'il ne soit nécessaire de gérer plus robustement les espaces blancs des valeurs d'attribut. Par exemple, voici un élément de propriété utilisé qui accepte une chaîne, ainsi que l’équivalent en utilisation d’attribut :

<Button>Hallo!
  <Button.Language>
    de-DE
  </Button.Language>
</Button>
<Button Language="de-DE">Hallo!</Button>

Exemples de propriétés où la syntaxe d’attribut est autorisée, mais la syntaxe de l’élément de propriété qui contient un élément objet n’est pas autorisée par le biais de XAML sont différentes propriétés qui prennent le type Cursor. La classe Cursor a un convertisseur de type dédié CursorConverter, mais n’expose pas de constructeur sans paramètre, de sorte que la propriété Cursor ne peut être définie qu’à l’aide de la syntaxe d’attribut, même si le type Cursor réel est un type référence.

Convertisseurs de types Per-Property

La propriété elle-même peut également déclarer un convertisseur de type au niveau de la propriété. Cela permet une « mini langue » qui instancie les objets du type de la propriété inline, en traitant les valeurs de chaîne entrantes de l’attribut comme entrée pour une opération de ConvertFrom en fonction du type approprié. En règle générale, cela permet de fournir un accesseur pratique, et non comme seul moyen d’activer la définition d’une propriété en XAML. Toutefois, il est également possible d’utiliser des convertisseurs de type pour les attributs dans lesquels vous souhaitez utiliser des types CLR existants qui ne fournissent pas de constructeur sans paramètre ou un convertisseur de type attribut. Les exemples de l’API WPF sont certaines propriétés qui prennent le type CultureInfo. Dans ce cas, WPF a utilisé le type de CultureInfo Microsoft .NET Framework existant pour mieux résoudre les scénarios de compatibilité et de migration utilisés dans les versions antérieures des frameworks, mais le type CultureInfo ne prenait pas en charge les constructeurs nécessaires ou la conversion de type au niveau du type pour être utilisables directement en tant que valeur de propriété XAML.

Chaque fois que vous exposez une propriété qui a une utilisation XAML, en particulier si vous êtes un auteur de contrôle, vous devez fortement envisager de sauvegarder cette propriété avec une propriété de dépendance. Cela est particulièrement vrai si vous utilisez l'implémentation existante de Windows Presentation Foundation (WPF) du processeur XAML, car vous pouvez améliorer les performances en utilisant le support DependencyProperty. Une propriété de dépendance va exposer, pour votre propriété, les fonctionnalités du système que les utilisateurs s'attendent à trouver pour une propriété accessible XAML. Cela inclut des fonctionnalités telles que l’animation, la liaison de données et la prise en charge des styles. Pour plus d’informations, consultez les propriétés dépendantes personnalisées et les propriétés de chargement et de dépendance XAML.

Écriture et attribution d’un convertisseur de type

Vous devrez parfois écrire une classe dérivée TypeConverter personnalisée pour fournir la conversion de type pour votre type de propriété. Pour obtenir des instructions sur la façon de dériver et de créer un convertisseur de type qui peut prendre en charge les utilisations XAML et comment appliquer le TypeConverterAttribute, consultez TypeConverters et xaml.

Exigences pour la syntaxe des attributs du gestionnaire d’événements XAML pour les événements d’une classe personnalisée

Pour être utilisable en tant qu’événement CLR, l’événement doit être exposé en tant qu’événement public sur une classe qui prend en charge un constructeur sans paramètre ou sur une classe abstraite où l’événement est accessible sur des classes dérivées. Pour pouvoir être utilisé de manière pratique en tant qu’événement routé, votre événement CLR doit implémenter des méthodes explicites add et remove, qui ajoutent et suppriment des gestionnaires pour la signature d’événement CLR et transfèrent ces gestionnaires aux méthodes AddHandler et RemoveHandler. Ces méthodes ajoutent ou suppriment les gestionnaires dans le magasin de gestionnaires pour événements routés dans l’instance à laquelle l’événement est attaché.

Note

Il est possible d’inscrire directement des gestionnaires pour les événements routés à l’aide de AddHandler, et de ne pas définir délibérément un événement CLR qui expose l’événement routé. Cela n’est généralement pas recommandé, car l’événement n’active pas la syntaxe d’attribut XAML pour l’attachement de gestionnaires, et votre classe résultante offre une vue XAML moins transparente des fonctionnalités de ce type.

Rédaction des propriétés d'une collection

Les propriétés qui prennent un type de collection ont une syntaxe XAML qui vous permet de spécifier des objets ajoutés à la collection. Cette syntaxe présente deux caractéristiques notables.

  • L’objet qui est l’objet de collection n’a pas besoin d’être spécifié dans la syntaxe de l’élément objet. La présence de ce type de collection est implicite chaque fois que vous spécifiez une propriété en XAML qui accepte un type de collection.

  • Les éléments enfants de la propriété de collection dans le balisage sont traités pour devenir membres de la collection. En règle générale, l’accès au code aux membres d’une collection est effectué via des méthodes de liste/dictionnaire telles que Add, ou via un indexeur. Mais la syntaxe XAML ne prend pas en charge les méthodes ou les indexeurs (exception : XAML 2009 peut prendre en charge les méthodes, mais l’utilisation de XAML 2009 limite les utilisations WPF possibles ; voir fonctionnalités de langage XAML 2009). Les collections sont évidemment une exigence très courante pour la création d’une arborescence d’éléments, et vous avez besoin d’un moyen de remplir ces collections en XAML déclaratif. Par conséquent, les éléments enfants d’une propriété de la collection sont traités en les ajoutant à la collection, qui constitue la valeur type de la propriété de la collection.

L’implémentation des services XAML .NET Framework et donc le processeur XAML WPF utilise la définition suivante pour ce qui constitue une propriété de collection. Le type de la propriété doit implémenter l'une des suivantes :

Chacun de ces types dans CLR a une méthode Add, utilisée par le processeur XAML pour ajouter des éléments à la collection sous-jacente lors de la création du graphe d’objets.

Note

Les interfaces List et Dictionary génériques (IList<T> et IDictionary<TKey,TValue>) ne sont pas prises en charge pour la détection de regroupement par le processeur XAML WPF. Toutefois, vous pouvez utiliser la classe List<T> comme classe de base, car elle implémente IList directement, ou Dictionary<TKey,TValue> en tant que classe de base, car elle implémente IDictionary directement.

Lorsque vous déclarez une propriété qui accepte une collection, soyez prudent sur la façon dont cette valeur de propriété est initialisée dans de nouvelles instances du type. Si vous n’implémentez pas la propriété en tant que propriété de dépendance, il est suffisant que la propriété utilise un champ de stockage qui appelle le constructeur du type de collection. Si votre propriété est une propriété de dépendance, vous devrez peut-être initialiser la propriété de collection dans le cadre du constructeur de type par défaut. Cela est dû au fait qu’une propriété de dépendance prend sa valeur par défaut à partir des métadonnées et que vous ne souhaitez généralement pas que la valeur initiale d’une propriété de collection soit une collection statique et partagée. Il doit y avoir une instance de collection par chaque instance de type contenant. Pour plus d’informations, consultez Propriétés de Dépendance Personnalisées.

Vous pouvez implémenter un type de collection personnalisé pour votre propriété de collection. En raison du traitement implicite des propriétés de collection, le type de collection personnalisé n’a pas besoin de fournir un constructeur sans paramètre afin d’être utilisé implicitement dans XAML. Toutefois, vous pouvez éventuellement fournir un constructeur sans paramètre pour le type de collection. Il peut s’agir d’une pratique intéressante. Sauf si vous fournissez un constructeur sans paramètre, vous ne pouvez pas déclarer explicitement la collection en tant qu’élément d’objet. Certains auteurs de balisage peuvent préférer voir la collection explicite comme une question de style de balisage. En outre, un constructeur sans paramètre peut simplifier les exigences d’initialisation lorsque vous créez de nouveaux objets qui utilisent votre type de collection comme valeur de propriété.

Déclaration des propriétés de contenu XAML

Le langage XAML définit le concept d’une propriété de contenu XAML. Chaque classe utilisable dans la syntaxe d’objet peut avoir exactement une propriété de contenu XAML. Pour déclarer une propriété comme propriété de contenu XAML pour votre classe, appliquez la ContentPropertyAttribute dans le cadre de la définition de classe. Spécifiez le nom de la propriété de contenu XAML prévue comme Name dans l’attribut. La propriété est spécifiée sous la forme d’une chaîne par nom, et non comme une construction de réflexion telle que PropertyInfo.

Vous pouvez spécifier une propriété de collection pour être la propriété de contenu XAML. Cela entraîne une utilisation de cette propriété permettant à l'élément objet d'avoir un ou plusieurs éléments enfants, sans des éléments de collection intermédiaire ou balises d'élément de propriété. Ces éléments sont ensuite traités comme la valeur de la propriété de contenu XAML et ajoutés à l’instance de la collection de support.

Certaines propriétés de contenu XAML existantes utilisent le type de propriété de Object. Cela permet une propriété de contenu XAML qui peut prendre des valeurs primitives telles qu’un String ainsi que la prise d’une valeur d’objet de référence unique. Si vous suivez ce modèle, votre type est responsable de la détermination du type ainsi que de la gestion des types possibles. La raison classique d’un type de contenu Object consiste à prendre en charge à la fois un moyen simple d’ajouter du contenu objet en tant que chaîne (qui reçoit un traitement de présentation par défaut) ou un moyen avancé d’ajouter du contenu d’objet qui spécifie une présentation non par défaut ou des données supplémentaires.

Sérialisation du code XAML

Pour certains scénarios, comme si vous êtes un auteur de contrôle, vous pouvez également vous assurer que toute représentation d’objet qui peut être instanciée en XAML peut également être sérialisée vers un balisage XAML équivalent. Les exigences de sérialisation ne sont pas décrites dans cette rubrique. Consultez Vue d’ensemble de la création de contrôles et l'arborescence d’éléments etde sérialisation.

Voir aussi