Partager via


XAML et classes personnalisées

Mise à jour : novembre 2007

Le XAML (Extensible Application Markup Language) permet de définir une classe personnalisée ou une structure dans n'importe quel langage du Common Language Runtime (CLR), puis d'accéder à la classe en utilisant le balisage XAML, y compris en utilisant une combinaison de XAML Windows Presentation Foundation (WPF) et des indicateurs XAML de votre classe personnalisée dans le même fichier de balisage. Cette rubrique porte sur les conditions que doit satisfaire une classe personnalisée pour pouvoir l'utiliser comme élément XAML.

Cette rubrique comprend les sections suivantes.

  • Classes personnalisées dans les applications ou les assemblys
  • Spécifications d'une classe personnalisée comme élément XAML
  • Spécifications des propriétés d'une classe personnalisée comme attributs XAML
  • Spécifications de la syntaxe d'attribut de gestionnaire d'événements XAML sur les événements d'une classe personnalisée
  • Écriture de propriétés de collection
  • Déclaration des propriétés de contenu XAML
  • Sérialisation du XAML
  • Rubriques connexes

Classes personnalisées dans les applications ou les assemblys

Les classes personnalisées utilisées en XAML peuvent être définies de deux manières distinctes : dans le code-behind ou un autre code qui produit l'application Windows Presentation Foundation (WPF) principale, ou sous la forme d'une classe dans un assembly séparé, tel qu'un fichier exécutable ou une DLL utilisée comme bibliothèque de classes. Chacune de ces approches a des avantages et des inconvénients.

  • La création d'une bibliothèque de classes offre l'avantage de pouvoir partager des classes personnalisées dans un grand nombre d'applications différentes. Une bibliothèque distincte simplifie également le versioning des applications à contrôler, ainsi que la création d'une classe que vous envisagez d'utiliser comme élément racine dans une page XAML.

  • La définition de classes personnalisées dans l'application est une technique qui offre l'avantage d'être relativement légère et elle réduit les problèmes de déploiement et de test qui apparaissent lorsque vous introduisez des assemblys distincts au-delà de l'exécutable principal. Toutefois, un inconvénient notable réside dans le fait que vous ne pouvez pas utiliser des classes définies dans le même assembly que l'élément racine d'une page XAML.

  • Quelles soient définies dans un même assembly ou dans un assembly différent, les classes personnalisées doivent être mappées entre l'espace de noms CLR et l'espace de noms XML pour qu'elles puissent être utilisées dans le XAML en tant qu'éléments. Consultez Espaces de noms XAML et mappage d'espace de noms.

Spécifications d'une classe personnalisée comme élément XAML

Pour pouvoir instancier la classe comme un élément d'objet, la classe doit répondre aux conditions suivantes :

  • La classe personnalisée doit être publique et prendre en charge un constructeur public par défaut (sans paramètre). (Les structures de code managé prennent en charge implicitement un tel constructeur.)

  • Votre classe personnalisée ne doit pas être une classe imbriquée (les classes imbriquées et le "point" dans leur syntaxe interfèrent avec d'autres fonctionnalités WPF, telles que les propriétés attachées).

Outre l'activation de la syntaxe d'élément d'objet, vous activez également la syntaxe d'élément de propriété des propriétés publiques qui utilisent l'objet comme type valeur. Cela s'explique par le fait que l'objet peut être désormais instancié comme élément d'objet et qu'il peut remplir la valeur d'élément de propriété d'une telle propriété.

Structures

Les structures que vous définissez en tant que types personnalisés peuvent toujours être construites en XAML dans WPF. Cela s'explique par le fait que les compilateurs CLR créent implicitement un constructeur par défaut pour une structure qui initialise toutes les valeurs de propriété sur leurs valeurs par défaut. Dans certains cas, le comportement de construction par défaut et/ou l'utilisation d'éléments objet pour une structure ne sont pas souhaitables. Cela peut provenir du fait que la structure est destinée à remplir des valeurs et à fonctionner du point de vue conceptuel comme une union, où les valeurs contenues peuvent avoir des interprétations mutuellement exclusives et, dans ce cas, aucune de ses propriétés n'est définissable. Un exemple WPF d'une telle structure est GridLength. En règle générale, ces structures doivent implémenter un convertisseur de type pour que les valeurs puissent être exprimées dans le formulaire d'attribut, à l'aide de conventions de chaîne qui créent les différents mode ou interprétations des valeurs de la structure, et la structure doit également exposer un comportement similaire pour la structure de code via un constructeur non défini par défaut.

Spécifications des propriétés d'une classe personnalisée comme attributs XAML

Les propriétés doivent faire référence à un type par valeur (tel qu'une primitive) ou utilisent une classe pour le type qui a un constructeur par défaut ou un convertisseur de type dédié au niveau de la classe.

La propriété peut également faire référence à un type de classe abstraite ou une interface. Pour les classes abstraites ou les interfaces, au moment de l'exécution, la valeur de la propriété doit être remplie avec des instances de classe pratiques qui implémentent l'interface ou des instances de classe qui dérivent de la classe abstraite.

Les propriétés peuvent être déclarées dans une classe abstraite, mais elles ne peuvent être définies que dans des classes pratiques qui dérivent de la classe abstraite, car la création de l'élément objet de la classe nécessite un constructeur par défaut public sur la classe.

Syntaxe d'attribut Enabled de convertisseur de type

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 d'une propriété qui doit instancier ce type. Un convertisseur de type n'active pas l'utilisation d'élément objet du type ; seule la présence d'un constructeur par défaut pour ce type active l'utilisation d'élément objet. Par conséquent, les propriétés qui sont activées par un convertisseur de type sont généralement inutilisables dans la syntaxe de la propriété, sauf si le type lui-même prend également en charge la syntaxe d'élément objet. Il existe néanmoins une exception dans la mesure où vous pouvez définir une syntaxe d'élément de propriété et que l'élément de propriété peut contenir une chaîne. Cette utilisation est vraiment essentiellement équivalente à une utilisation de syntaxe d'attribut ; une telle utilisation n'est pas courante, sauf s'il est nécessaire de traiter plus efficacement les espaces de la valeur d'attribut. L'exemple suivant montre une utilisation d'élément de propriété qui utilise une chaîne et l'équivalent de l'utilisation de l'attribut :

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

Des exemples de propriétés pour lesquelles la syntaxe d'attribut est autorisée, mais pour lesquelles la syntaxe d'élément de propriété contenant un élément d'objet n'est pas autorisée en XAML sont les propriétés qui prennent le type Cursor. La classe Cursor a un convertisseur de type CursorConverter dédié, mais elle n'expose pas un constructeur par défaut. Par conséquent, la propriété Cursor peut être définie uniquement via la syntaxe d'attribut bien que le type Cursor réel soit un type référence.

Convertisseurs de type en fonction de la propriété

La propriété elle-même peut déclarer également un convertisseur de type au niveau de la propriété. Cela active un "mini langage" qui instancie des 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 ConvertFrom basé sur le type approprié. En général, cela permet de fournir un accesseur pratique et non pas uniquement pour pouvoir définir une propriété en XAML. Toutefois, il est également possible d'utiliser des convertisseurs de type pour les attributs pour lesquels vous voulez utiliser des types CLR existants qui ne fournissent pas un constructeur par défaut ni un convertisseur de type attribué. Les exemples d'WPFAPI représentent certaines propriétés qui prennent le type CultureInfo. Dans ce cas, WPF a utilisé le type Microsoft .NET FrameworkCultureInfo existant pour les scénarios de compatibilité et de migration utilisés dans les versions antérieures d'infrastructures, mais le type CultureInfo ne prenait pas en charge les constructeurs nécessaires, ni la conversion de type au niveau du type utilisable directement comme valeur de propriété XAML.

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

Écriture et attribution d'un convertisseur de type

Vous devrez fréquemment écrire une classe dérivée TypeConverter personnalisée pour fournir la conversion de type pour votre type de propriété. Pour savoir comment dériver une classe et créer un convertisseur de type qui prend en charge les utilisations XAML, et appliquer l'TypeConverterAttribute, consultez TypeConverters et XAML.

Spécifications de la syntaxe d'attribut de gestionnaire d'événements XAML sur les événements d'une classe personnalisée

Pour pouvoir utiliser un événement comme événement CLR, l'événement doit être exposé comme un événement public dans une classe qui prend en charge un constructeur par défaut, ou dans une classe abstraite où l'événement est accessible dans des classes dérivées. Pour pouvoir l'utiliser aisément comme événement routé, votre événement CLR doit implémenter les méthodes implicites add et remove, qui ajoutent et suppriment des gestionnaires pour la signature d'événement CLR et envoient ces gestionnaires aux méthodes AddHandler et RemoveHandler. Ces méthodes ajoutent ou suppriment les gestionnaires dans le magasin des gestionnaires d'événements routés dans l'instance auquel l'événement est joint.

Remarque :

Il est possible d'inscrire directement des gestionnaires d'é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 pas recommandé en général parce que l'événement n'activera pas la syntaxe d'attribut XAML pour joindre des gestionnaires, et votre classe résultante offrira une vue XAML moins transparente du modèle d'objet de classe.

Écriture de propriétés de collection

Les propriétés qui prennent un type collection ont une syntaxe XAML qui vous permet de spécifier les objets ajoutés à la collection. Cette syntaxe a deux fonctions notables.

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

  • Les éléments enfants de la propriété de collection sont traités pour devenir membres de la collection. Normalement, l'accès de code aux membres d'une collection est effectué via des méthodes de collection telles que Add, ou via une propriété d'indexeur de la collection. Mais la syntaxe XAML ne prend pas en charge les méthodes, ni les indexeurs. Les collections sont à l'évidence une spécification très courante pour générer une arborescence d'éléments, et vous devez utiliser une méthode pour remplir ces collections en XAML déclaratif. Par conséquent, les éléments enfants d'une propriété de collection sont traités en les ajoutant à la collection qui est la valeur de type de propriété de collection.

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'un des éléments suivants :

Chacun de ces types a une méthode Add qui est utilisée par le processeur XAML pour ajouter des éléments à la collection sous-jacente.

Remarque :

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

Lorsque vous déclarez une propriété qui prend une collection, vérifiez la manière dont la valeur de propriété est initialisée dans les nouvelles instances du type. Si vous n'implémentez pas la propriété comme une propriété de dépendance, vous pouvez faire en sorte que la propriété utilise un champ de stockage qui appelle le constructeur de type. Si votre propriété est une propriété de dépendance, vous pouvez devoir initialiser la propriété de collection dans le cadre du constructeur de type par défaut. Cela s'explique par le fait qu'une propriété de dépendance prend sa valeur par défaut des métadonnées, et que vous ne souhaitez pas, en général, que la valeur initiale d'une propriété de collection corresponde à une collection partagée statique (il doit exister une instance de collection par chaque instance conteneur). Pour plus d'informations, consultez Propriétés de dépendance personnalisées.

Vous pouvez implémenter un type collection personnalisé pour votre propriété de collection. Du fait du traitement de propriété de collection implicite, le type de collection personnalisé n'a pas besoin de fournir un constructeur par défaut pour qu'il soit utilisé en XAML. Toutefois, vous pouvez fournir éventuellement un constructeur par défaut pour le type collection. Cette pratique peut s'avérer efficace, car vous ne pouvez pas déclarer explicitement la collection sous la forme d'un élément d'objet si vous ne fournissez pas un constructeur par défaut. Certains auteurs de balises considèrent plutôt la collection explicite comme un type de balisage. En outre, un constructeur par défaut peut simplifier les spécifications d'initialisation lorsque vous créez des objets qui utilisent votre type collection comme une valeur de propriété.

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

Le langage XAML définit le concept de 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 étant la propriété de contenu XAML de votre classe, appliquez l'ContentPropertyAttribute dans le cadre de la définition de classe. Spécifiez le nom de la propriété de contenu XAML comme Name dans l'attribut.

Vous pouvez spécifier une propriété de collection comme étant la propriété de contenu XAML. Cela génère une utilisation de la propriété par laquelle l'élément d'objet peut avoir un ou plusieurs éléments enfants sans éléments d'objet collection intermédiaires ou indicateurs d'éléments de propriété. Ces éléments sont traités ensuite comme étant la valeur de la propriété de contenu XAML et ils sont ajoutés à l'instance de collection de stockage.

Certaines propriété de contenu XAML WPF existantes utilisent le type de propriété Object. Cela permet d'utiliser une propriété de contenu XAML qui peut prendre des valeurs primitives, telles que String et une valeur d'objet de référence unique. Si vous suivez ce modèle, votre type se charge de la détermination de type et de la gestion des types possibles. La justification type d'un modèle de type Object est de prendre en charge une méthode simple d'ajout de contenu d'objet sous la forme d'une chaîne (qui reçoit un traitement de présentation par défaut), ou une méthode avancée d'ajout de contenu d'objet qui spécifie une présentation non définie par défaut.

Sérialisation du XAML

Dans certains cas, lorsque vous êtes auteur de contrôle, par exemple, vous pouvez vous assurer qu'une représentation d'objet pouvant être instanciée en XAML puisse être également sérialisée dans l'équivalent XAML. Les spécifications de sérialisation ne sont pas décrites dans cette rubrique. Consultez Vue d'ensemble de la création de contrôles et Sérialisation et arborescence d'éléments.

Voir aussi

Concepts

Vue d'ensemble du langage XAML

Propriétés de dépendance personnalisées

Vue d'ensemble de la création de contrôles

Vue d'ensemble des éléments de base

Propriétés de dépendance et chargement XAML