Définir des types personnalisés à utiliser avec les services XAML .NET

Lorsque vous définissez des types personnalisés qui sont des objets métier ou des types qui n’ont pas de dépendance sur des frameworks spécifiques, certaines bonnes pratiques sont recommandées pour XAML que vous pouvez suivre. Si vous suivez ces pratiques, les services XAML .NET et ses lecteurs XAML et enregistreurs XAML peuvent découvrir les caractéristiques XAML de votre type et lui donner une représentation appropriée dans un flux de nœuds XAML à l’aide du système de type XAML. Cette rubrique décrit les meilleures pratiques pour les définitions de types, les définitions de membres et l’attribut CLR des types ou des membres.

Modèles de constructeur et définitions de type pour XAML

Pour être instancié en tant qu’élément objet en XAML, une classe personnalisée doit répondre aux exigences suivantes :

  • La classe personnalisée doit être publique et doit exposer un constructeur public sans paramètre. (Consultez la section suivante pour des remarques concernant les structures.)

  • La classe personnalisée ne doit pas être une classe imbriquée. Le « point » supplémentaire dans le chemin de nom complet rend la division d’espace de noms de classes ambiguë et interfère avec d’autres fonctionnalités XAML telles que les propriétés jointes. Si un objet peut être instancié en tant qu’élément objet, l’objet créé peut remplir la forme d’élément de propriété de toutes les propriétés qui prennent l’objet comme type sous-jacent.

Vous pouvez toujours fournir des valeurs d’objet pour les types qui ne répondent pas à ces critères, si vous activez un convertisseur de valeurs. Pour plus d’informations, consultez Convertisseurs de types et extensions de balisage pour XAML.

Structures

Les structures peuvent toujours être construites en XAML, par définition CLR. Cela est dû au fait qu’un compilateur CLR crée implicitement un constructeur sans paramètre pour une structure. Ce constructeur initialise toutes les valeurs de propriété à leurs valeurs par défaut.

Dans certains cas, le comportement de construction par défaut d’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. En tant qu’union, les valeurs contenues peuvent avoir des interprétations mutuellement exclusives et, par conséquent, aucune de ses propriétés n’est paramétrable. Un exemple de telle structure dans le vocabulaire WPF est GridLength. 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 structure. La structure doit également exposer un comportement similaire pour la construction du code par le biais d’un constructeur sans paramètre.

Interfaces

Les interfaces peuvent être utilisées comme types sous-jacents de membres. Le système de type XAML case activée la liste assignable et s’attend à ce que l’objet fourni comme valeur puisse être affecté à l’interface. Il n’existe aucun concept de la façon dont l’interface doit être présentée en tant que type XAML tant qu’un type assignable pertinent prend en charge les exigences de construction XAML.

Méthodes d’usine

Les méthodes de fabrique sont une fonctionnalité XAML 2009. Ils modifient le principe XAML que les objets doivent avoir des constructeurs sans paramètre. Les méthodes de fabrique ne sont pas documentées dans cet article. Voir la directive x :FactoryMethod.

Énumérations

Les énumérations ont un comportement de conversion de type natif XAML. Les noms de constantes d’énumération spécifiés en XAML sont résolus par rapport au type d’énumération sous-jacent et retournent la valeur d’énumération à un enregistreur d’objets XAML.

XAML prend en charge une utilisation de style indicateurs pour les énumérations avec FlagsAttribute application. Pour plus d’informations, consultez La syntaxe XAML en détail. (La syntaxe XAML en détail est écrite pour l’audience WPF, mais la plupart des informations de cette rubrique sont pertinentes pour le code XAML qui n’est pas spécifique à un framework d’implémentation particulier.)

Définitions de membres

Les types peuvent définir des membres pour l’utilisation XAML. Il est possible que les types définissent des membres utilisables en XAML même si ce type spécifique n’est pas utilisable en XAML. Cela est possible en raison de l’héritage CLR. Tant que certains types qui héritent du membre prennent en charge l’utilisation XAML en tant que type, et que le membre prend en charge l’utilisation XAML pour son type sous-jacent ou a une syntaxe XAML native disponible, ce membre est utilisable en XAML.

Propriétés

Si vous définissez des propriétés en tant que propriété CLR publique à l’aide des modèles d’accesseur get et set d’accesseur standard et des mot clé appropriés au langage, le système de type XAML peut signaler la propriété en tant que membre avec les informations appropriées fournies pour XamlMember les propriétés, telles que IsReadPublic et IsWritePublic.

Des propriétés spécifiques peuvent activer une syntaxe de texte en appliquant TypeConverterAttribute. Pour plus d’informations, consultez Convertisseurs de types et extensions de balisage pour XAML.

En l’absence d’une syntaxe de texte ou d’une conversion XAML native et en l’absence d’une autre indirection, comme une utilisation de l’extension de balisage, le type d’une propriété (TargetType dans le système de type XAML) doit être en mesure de retourner une instance à un enregistreur d’objets XAML en traitant le type cible comme un type CLR.

Si vous utilisez XAML 2009, l’extension x :Reference Markup peut être utilisée pour fournir des valeurs si les considérations précédentes ne sont pas remplies ; toutefois, il s’agit davantage d’un problème d’utilisation qu’un problème de définition de type.

Événements

Si vous définissez des événements en tant qu’événement CLR public, le système de type XAML peut signaler l’événement en tant que membre avec IsEvent .true Le câblage des gestionnaires d’événements n’est pas dans l’étendue des fonctionnalités des services XAML .NET ; le câblage est laissé à des infrastructures et des implémentations spécifiques.

Méthodes

Le code inline pour les méthodes n’est pas une fonctionnalité XAML par défaut. Dans la plupart des cas, vous ne référencez pas directement les membres de méthode à partir de XAML, et le rôle des méthodes en XAML n’est que pour prendre en charge des modèles XAML spécifiques. La directive x :FactoryMethod est une exception.

Champs

Les instructions de conception CLR découragent les champs non statiques. Pour les champs statiques, vous pouvez accéder aux valeurs de champ statique uniquement via x :Static Markup Extension . Dans ce cas, vous ne faites rien de spécial dans la définition CLR pour exposer un champ pour les utilisations x :Static .

Membres attachables

Les membres attachables sont exposés au code XAML via un modèle de méthode d’accesseur sur un type de définition. Le type de définition lui-même n’a pas besoin d’être utilisable en XAML en tant qu’objet. En fait, un modèle courant consiste à déclarer une classe de service dont le rôle est de posséder le membre attachable et d’implémenter les comportements associés, mais ne sert aucune autre fonction, comme une représentation de l’interface utilisateur. Pour les sections suivantes, l’espace réservé PropertyName représente le nom de votre membre pouvant être attaché. Ce nom doit être valide dans la grammaire XamlName.

Soyez prudent quant aux collisions de noms entre ces modèles et d’autres méthodes d’un type. Si un membre existe qui correspond à l’un des modèles, il peut être interprété comme un chemin d’utilisation de membre attachable par un processeur XAML, même si ce n’était pas votre intention.

Accesseur GetPropertyName

La signature de l’accesseur GetPropertyName doit être :

public static object GetPropertyName(object target)

  • L’objet target peut être défini comme un type plus spécifique dans votre implémentation. Vous pouvez l’utiliser pour étendre l’utilisation de votre membre pouvant être attaché ; les utilisations en dehors de votre étendue prévue lèvent des exceptions de cast non valides qui sont ensuite exposées par une erreur d’analyse XAML. Le nom target du paramètre n’est pas obligatoire, mais est nommé target par convention dans la plupart des implémentations.

  • La valeur de retour peut être spécifiée comme un type plus spécifique dans votre implémentation.

Pour prendre en charge une TypeConverter syntaxe de texte activée pour l’utilisation des attributs du membre attachable, appliquez TypeConverterAttribute l’accesseur GetPropertyName . L’application à la get place de celle-ci set peut sembler non intuitive. Toutefois, cette convention peut prendre en charge le concept de membres attachables en lecture seule qui sont sérialisables, ce qui est utile dans les scénarios de concepteur.

Accesseur SetPropertyName

La signature de l’accesseur SetPropertyName doit être :

public static void SetPropertyName(object target, object value)

  • L’objet target peut être spécifié en tant que type plus spécifique dans votre implémentation, avec la même logique et les mêmes conséquences que celles décrites dans la section précédente.

  • L’objet value peut être défini comme un type plus spécifique dans votre implémentation.

N’oubliez pas que la valeur de cette méthode est l’entrée provenant de l’utilisation XAML, généralement sous forme d’attribut. À partir du formulaire d’attribut, il doit y avoir une prise en charge du convertisseur de valeur pour une syntaxe de texte et vous attribuez l’attribut sur l’accesseur GetPropertyName.

Magasins de membres attachables

Les méthodes d’accesseur ne sont généralement pas suffisantes pour fournir un moyen de placer des valeurs membres attachables dans un graphique d’objet, ou de récupérer des valeurs hors du graphique d’objet et de les sérialiser correctement. Pour fournir cette fonctionnalité, les target objets des signatures d’accesseur précédentes doivent être capables de stocker des valeurs. Le mécanisme de stockage doit être cohérent avec le principe de membre attachable que le membre est attaché à des cibles où le membre pouvant être attaché n’est pas dans la liste des membres. Les services XAML .NET fournissent une technique d’implémentation pour les magasins de membres attachables via les API IAttachedPropertyStore et AttachablePropertyServices. IAttachedPropertyStore est utilisé par les enregistreurs XAML pour découvrir l’implémentation du magasin et doit être implémenté sur le type qui est les target accesseurs. Les API statiques AttachablePropertyServices sont utilisées dans le corps des accesseurs et font référence au membre attachable par son AttachableMemberIdentifier.

L’attribution correcte de vos types, membres et assemblys est importante pour signaler les informations système de type XAML aux services XAML .NET. Les informations système de type XAML de création de rapports sont pertinentes si l’une des situations suivantes s’applique :

  • Vous prévoyez que vos types soient utilisés avec des systèmes XAML qui sont directement basés sur les lecteurs XAML des services XAML .NET et les enregistreurs XAML.
  • Vous définissez ou utilisez une infrastructure d’utilisation XAML basée sur ces lecteurs XAML et les enregistreurs XAML.

Pour obtenir la liste de chaque attribut lié au code XAML qui est pertinent pour la prise en charge XAML de vos types personnalisés, consultez les attributs CLR liés au code XAML pour les types et bibliothèques personnalisés.

Utilisation

L’utilisation des types personnalisés nécessite que l’auteur du balisage mappe un préfixe pour l’assembly et l’espace de noms CLR qui contiennent le type personnalisé. Cette procédure n’est pas documentée dans cette rubrique.

Niveau d’accès

XAML fournit un moyen de charger et d’instancier des types qui ont un niveau d’accès internal . Cette fonctionnalité est fournie afin que le code utilisateur puisse définir ses propres types, puis instancier ces classes à partir du balisage qui fait également partie de la même étendue de code utilisateur.

Un exemple de WPF est chaque fois que le code utilisateur définit un UserControl élément destiné à refactoriser un comportement d’interface utilisateur, mais pas dans le cadre d’un mécanisme d’extension possible qui peut être implicite en déclarant la classe de prise en charge avec public le niveau d’accès. UserControl Une telle opération peut être déclarée avec internal accès si le code de stockage est compilé dans le même assembly à partir duquel il est référencé en tant que type XAML.

Pour une application qui charge xaml en toute confiance et utilise XamlObjectWriter, le chargement de classes avec internal le niveau d’accès est toujours activé.

Pour une application qui charge XAML en cas d’approbation partielle, vous pouvez contrôler les caractéristiques de niveau d’accès à l’aide de l’API XamlAccessLevel . En outre, les mécanismes de report (tels que le système de modèle WPF) doivent être en mesure de propager toutes les autorisations de niveau d’accès et de les conserver pour les évaluations de temps d’exécution éventuelles ; ceci est géré en interne en transmettant les XamlAccessLevel informations.

Implémentation WPF

WPF XAML utilise un modèle d’accès à confiance partielle où si BAML est chargé sous approbation partielle, l’accès est limité à AssemblyAccessTo l’assembly qui est la source BAML. Pour le report, WPF utilise IXamlObjectWriterFactory.GetParentSettings comme mécanisme de transmission des informations de niveau d’accès.

Dans la terminologie XAML WPF, un type interne est un type défini par le même assembly qui inclut également le code XAML de référencement. Un tel type peut être mappé via un espace de noms XAML qui omet délibérément la partie assembly= d’un mappage, par exemple xmlns:local="clr-namespace:WPFApplication1". Si BAML fait référence à un type interne et que ce type a internal un niveau d’accès, cela génère une GeneratedInternalTypeHelper classe pour l’assembly. Si vous souhaitez éviter GeneratedInternalTypeHelper, vous devez utiliser public le niveau d’accès ou prendre en compte la classe pertinente dans un assembly distinct et rendre cet assembly dépendant.

Voir aussi