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

Applies to Windows and Windows Phone

Nous expliquons ici comment définir et implémenter vos propres propriétés de dépendance pour une application Windows Runtime en C++, C# ou Visual Basic. Nous listons ici les raisons pour lesquelles les développeurs et les auteurs de composants peuvent souhaiter créer des propriétés de dépendance personnalisées. Nous décrivons les étapes d’implémentation de propriété de dépendance personnalisée et certaines meilleures pratiques susceptibles d’améliorer les performances, la simplicité d’utilisation ou la polyvalence de la propriété de dépendance.

Prérequis

Nous supposons que vous avez lu la vue d’ensemble des propriétés de dépendance et que vous comprenez ce que sont les propriétés de dépendance du point de vue d’un consommateur de propriétés de dépendance existantes. Pour suivre les exemples de cette rubrique, vous devez également comprendre le langage XAML et savoir comment écrire une application Windows Runtime de base en C++, C# ou Visual Basic.

Qu’est-ce qu’une propriété de dépendance ?

Les propriétés de dépendance sont des propriétés inscrites auprès du système de propriétés Windows Runtime grâce à un appel à la méthode DependencyProperty.Register et identifiées par un membre identificateur DependencyProperty sur la classe de définition. Vous pouvez activer ce que l’on nommerait autrement une propriété CLR (Common Language Runtime) ou C++ afin de prendre en charge les styles, la liaison de données, les animations et les valeurs par défaut en l’implémentant en tant que propriété de dépendance. Les propriétés de dépendance peuvent être utilisées uniquement par les types DependencyObject. Toutefois, DependencyObject étant relativement haut dans la hiérarchie de classes, la plupart des classes destinées à la prise en charge de l’interface utilisateur et de la présentation peuvent prendre en charge des propriétés de dépendance. Pour plus d’informations sur les propriétés de dépendance et certains termes et conventions utilisés pour les décrire dans cette documentation, voir Vue d’ensemble des propriétés de dépendance.

Control.Background, FrameworkElement.Widthet TextBox.Text sont des exemples de propriétés de dépendance Windows Runtime. Chaque propriété de dépendance exposée par une classe a une propriété public static readonly correspondante de type DependencyProperty qui est exposée sur cette même classe et est l’identificateur de la propriété de dépendance. Le nom de l’identificateur respecte la convention suivante : le nom de la propriété de dépendance, avec la chaîne "Property" ajoutée à la fin du nom. Par exemple, l’identificateur DependencyProperty correspondant pour la propriété Control.Background est Control.BackgroundProperty. L’identificateur stocke les informations sur la propriété de dépendance dès qu’elle a été inscrite et peut ensuite être utilisé pour d’autres opérations impliquant la propriété de dépendance, telles que l’appel de SetValue.

Wrappers de propriétés

Les propriétés de dépendance ont en général une implémentation de wrapper. Sans le wrapper, le seul moyen d’obtenir ou de définir les propriétés consisterait à utiliser les méthodes d’utilitaire de propriété de dépendance GetValue et SetValue et à leur passer l’identificateur comme paramètre. Il s’agirait d’une utilisation plutôt contre nature pour un objet qui n’est somme toute qu’une propriété. Mais avec le wrapper, votre code et tout autre code qui fait référence à la propriété de dépendance peut utiliser une syntaxe de propriété-objet simple et naturelle pour le langage que vous utilisez.

Si vous implémentez une propriété de dépendance personnalisée vous-même et que vous souhaitez qu’elle soit publique et simple à appeler, définissez également les wrappers de propriété. Les wrappers de propriété sont également utiles pour fournir des informations de base concernant la propriété de dépendance aux processus d’analyse statique ou de réflexion. Plus spécifiquement, le wrapper est l’endroit où l’on place des attributs tels que ContentPropertyAttribute.

Quand implémenter une propriété en tant que propriété de dépendance ?

Quand vous implémentez une propriété publique en lecture/écriture sur une classe, tant que votre classe dérive de DependencyObject, vous pouvez faire en sorte que votre propriété fonctionne comme propriété de dépendance. Parfois, la technique par défaut consistant à seconder votre propriété à l’aide d’un champ privé est adéquate. La définition de votre propriété personnalisée en tant que propriété de dépendance n’est pas toujours nécessaire ou convenable. Le choix dépendra des scénarios que votre propriété doit prendre en charge.

Il peut être souhaitable d’implémenter une propriété comme propriété de dépendance si vous voulez qu’elle prenne en charge une ou plusieurs de ces fonctionnalités Windows Runtime ou des applications Windows Runtime :

  • définition de la propriété par le biais d’un Style ;
  • fonctionnement en tant que propriété cible valide pour la liaison de données ;
  • prise en charge de valeurs animées par le biais d’un Storyboard ;
  • avertissement en cas de modification de la valeur précédente de la propriété par :
    • des actions exécutées par le système de propriétés lui-même ;
    • l’environnement ;
    • des actions de l’utilisateur ;
    • la lecture et l’écriture de styles.

Liste de vérification pour la définition d’une propriété de dépendance

La définition d’une propriété de dépendance peut être envisagée d’un point de vue conceptuel. Ces concepts ne sont pas nécessairement des étapes procédurales, car plusieurs concepts peuvent être abordés sur une même ligne de code dans l’implémentation. La liste suivante constitue simplement une vue d’ensemble. Vous trouverez plus loin dans cette rubrique une explication plus détaillée de chacun des concepts, ainsi que des exemples de code dans plusieurs langages.

  • (Facultatif) Créez des métadonnées de propriétés pour la propriété de dépendance. Il vous faut des métadonnées de propriété uniquement si vous souhaitez disposer d’un comportement de modification de propriété ou d’une valeur par défaut basée sur des métadonnées qui peut être restaurée en appelant ClearValue.

  • Inscrivez le nom de la propriété auprès du système de propriétés (appelez Register), en spécifiant un type de propriétaire et le type de la valeur de propriété. Il existe un paramètre obligatoire pour Register qui attend des métadonnées de propriétés. Spécifiez la valeur null pour ce paramètre ou spécifiez les métadonnées de propriété si vous en avez déclaré.

  • Définissez un identificateur DependencyProperty en tant que membre de propriété public static readonly sur le type de propriétaire.

  • Définissez une propriété wrapper, en respectant le modèle d’accesseur de propriété utilisé dans le langage que vous implémentez. Le nom de la propriété wrapper doit correspondre à la chaîne name que vous avez utilisée dans Register. Implémentez les accesseurs get et set pour connecter le wrapper à la propriété de dépendance qu’il enveloppe en appelant GetValue et SetValue et en passant l’identificateur de votre propre propriété en tant que paramètre.
  • (Facultatif) Placez des attributs tels que ContentPropertyAttribute sur le wrapper.

Remarque  Si l’on définit une propriété jointe personnalisée, on omet en général le wrapper. Au lieu de cela, on écrit un style d’accesseur différent utilisable par un processeur XAML. Voir Propriétés jointes personnalisées.

Inscription de la propriété

Pour que votre propriété soit une propriété de dépendance, vous devez l’inscrire dans une banque de propriétés conservée par le système de propriétés Windows Runtime. Vous devez affecter à la propriété un identificateur unique qui sera utilisé comme qualificateur pour les opérations ultérieures du système de propriétés. Ces opérations doivent être des opérations internes ou votre propre code qui appelle des API du système de propriétés. Pour inscrire la propriété, vous devez appeler la méthode Register.

Pour les langages Microsoft .NET (C# et Microsoft Visual Basic), vous devez appeler Register dans le corps de votre classe (à l’intérieur de la classe, mais à l’extérieur des définitions de membres). L’identificateur est également fourni par l’appel de la méthode Register, en tant que valeur de retour. L’appel Register est généralement effectué en dehors d’autres définitions de membres car vous utilisez la valeur de retour pour assigner et créer une propriété public static readonly de type DependencyProperty dans le cadre de votre classe. Cette propriété devient l’identificateur de votre propriété de dépendance. Voici quelques exemples d’appel Register.


public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(
  "Label",
  typeof(String),
  typeof(ImageWithLabelControl),
  new PropertyMetadata(null)
);

Remarque  L’inscription de la propriété de dépendance dans un corps de classe est l’implémentation par défaut, mais vous pouvez aussi inscrire une propriété de dépendance dans le constructeur statique de classe. Cette approche est logique si vous avez besoin de plusieurs lignes de code pour initialiser la propriété de dépendance.

En C++, plusieurs options sont à votre disposition pour le fractionnement de l’implémentation entre l’en-tête et le fichier de code. Le fractionnement par défaut consiste à déclarer l’identificateur proprement dit en tant que propriété public static dans l’en-tête, avec une implémentation get mais sans set. L’implémentation get fait référence à un champ privé, qui est une instance DependencyProperty non initialisée. Vous pouvez aussi déclarer les wrappers et les implémentations get et set du wrapper. Dans ce cas, l’en-tête comprend une implémentation minimale. Si le wrapper a besoin d’une attribution Windows Runtime, attribuez également l’en-tête. Placez l’appel à la propriété Register dans le fichier de code, au sein d’une fonction d’assistance qui s’exécute uniquement lorsque l’application est initialisée pour la première fois. Utilisez la valeur de retour de la méthode Register pour remplir les identificateurs statiques mais non initialisés que vous avez déclarés dans l’en-tête, auquel vous avez initialement attribué la valeur nullptr au niveau de l’étendue racine du fichier d’implémentation.


//.h file
//using namespace Windows::UI::Xaml::Controls;
//using namespace Windows::UI::Xaml::Interop;
//using namespace Windows::UI::Xaml;
//using namespace Platform;

public ref class ImageWithLabelControl sealed : public Control
{  
private:
    static DependencyProperty^ _LabelProperty;
...
public:
    static void RegisterDependencyProperties(); 
    static property DependencyProperty^ LabelProperty
    {
        DependencyProperty^ get() {return _LabelProperty;}
    }
...
};



//.cpp file
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml.Interop;

DependencyProperty^ ImageWithLabelControl::_LabelProperty = nullptr;

// This function is called from the App constructor in App.xaml.cpp 
// to register the properties
void ImageWithLabelControl::RegisterDependencyProperties() 
{ 
    if (_LabelProperty == nullptr) 
    { 
        _LabelProperty = DependencyProperty::Register(
          "Label", Platform::String::typeid, ImageWithLabelControl::typeid, nullptr); 
    } 
}

Remarque  Pour le code C++, vous vous demandez peut-être pourquoi il y a un champ privé et une propriété publique en lecture seule qui expose la DependencyProperty. C’est pour que d’autres appelants qui utilisent votre propriété de dépendance puissent également utiliser vos API d’utilitaire de système de propriétés qui requièrent que l’identificateur soit public. Si l’identificateur demeure privé, personne ne pourra utiliser ces API d’utilitaire. Parmi ces API et scénarios, on peut citer GetValue ou SetValue par choix, ClearValue, GetAnimationBaseValue, SetBinding et Setter.Property. Vous ne pouvez pas utiliser de champ public pour cela, car Windows Runtime compile des règles qui n’autorisent pas les membres de données publiques qui utilisent des types de référence tels que DependencyProperty.

Conventions d’affectation de noms de propriétés de dépendance

Il existe des conventions d’affectation de noms pour les propriétés de dépendance ; elles doivent être respectées en permanence, sauf cas exceptionnel. La propriété de dépendance proprement dite a un nom de base ("Label" dans l’exemple précédent) qui est donné comme premier paramètre de Register. Ce nom doit être unique dans chaque type d’inscription et l’exigence du caractère unique s’applique également à tout membre hérité. Les propriétés de dépendance héritées par le biais de types de base sont considérées comme faisant déjà partie du type d’inscription ; les noms des propriétés héritées ne peuvent pas être inscrits de nouveau.

Attention  Bien que le nom fourni ici puisse être tout identificateur de chaîne qui est valide en programmation pour le langage de votre choix, il est préférable de pouvoir définir la propriété de dépendance en XAML également. Pour être défini en XAML, le nom de propriété que vous choisissez doit être un nom XAML valide. Pour plus d’informations, voir Vue d’ensemble du langage XAML.

Lors de la création de la propriété identificatrice, combinez le nom de la propriété telle que vous l’avez inscrite avec le suffixe "Property" ("LabelProperty", par exemple). Cette propriété est votre identificateur pour la propriété de dépendance et elle est utilisée comme entrée pour les appels SetValue et GetValue que vous effectuez dans vos propres wrappers de propriétés. Elle est aussi utilisée par le système de propriétés et éventuellement par les processeurs XAML.

Implémentation du wrapper

Votre wrapper de propriété doit appeler GetValue dans l’implémentation get et SetValue dans l’implémentation set.

Attention  Hormis dans de rares cas exceptionnels, vos implémentations de wrappers doivent effectuer uniquement les opérations GetValue et SetValue. Sinon, vous obtiendrez un comportement différent lorsque votre propriété sera définie par le biais de XAML et par le biais de code. Pour des raisons d’efficacité, l’analyseur XAML contourne les wrappers lors de la définition des propriétés de dépendance ; dans la mesure du possible, il utilise le registre de propriétés de dépendance.


public String Label
{
    get { return (String)GetValue(LabelProperty); }
    set { SetValue(LabelProperty, value); }
}

Métadonnées de propriété pour une propriété de dépendance personnalisée

Lorsque des métadonnées de propriété sont assignées à une propriété de dépendance, les mêmes métadonnées sont appliquées à cette propriété pour toute instance du type de propriétaire de propriété ou ses sous-classes. Dans les métadonnées de propriété, vous pouvez spécifier deux comportements :

  • une valeur par défaut que le système de propriétés assigne à tous les cas de la propriété ;
  • une méthode de rappel statique qui est appelée automatiquement dans le système de propriétés chaque fois qu’une valeur de propriété est détectée.

Appel du Registre à l’aide de métadonnées de propriété

Dans les exemples précédents d’appel de DependencyProperty.Register, nous avons transmis une valeur Null pour le paramètre propertyMetadata. Pour permettre à une propriété de dépendance de fournir une valeur par défaut ou d’utiliser un rappel de modification de propriété, vous devez définir une instance de PropertyMetadata qui fournit l’une et/ou l’autre de ces fonctionnalités.

En règle générale, vous fournissez PropertyMetadata en tant qu’instance créée inline dans les paramètres de DependencyProperty.Register.

Remarque  Si vous définissez une implémentation de CreateDefaultValueCallback, vous devez utiliser la méthode d’utilitaire PropertyMetadata.Create au lieu d’appeler un constructeur PropertyMetadata pour définir l’instance de PropertyMetadata.

L’exemple suivant modifie les exemples de DependencyProperty.Register présentés auparavant en référençant une instance de PropertyMetadata avec une valeur PropertyChangedCallback. L’implémentation du rappel "OnLabelChanged" est décrite plus loin dans cette section.


public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(
  "Label",
  typeof(String),
  typeof(ImageWithLabelControl),
  new PropertyMetadata(null,new PropertyChangedCallback(OnLabelChanged))
);

Valeur par défaut

Vous pouvez spécifier une valeur par défaut pour une propriété de dépendance afin que la propriété retourne toujours une valeur par défaut particulière quand sa définition est annulée. Cette valeur peut être différente de la valeur par défaut inhérente au type de cette propriété.

Si aucune valeur par défaut n’est spécifiée, la valeur par défaut d’une propriété de dépendance est null pour un type de référence ou a la valeur par défaut du type pour un type de valeur ou une primitive de langage (par exemple, 0 pour un entier ou une chaîne vide pour une chaîne). La principale raison pour laquelle on définit une valeur par défaut est le fait que cette valeur est restaurée quand vous appelez ClearValue sur la propriété. Il peut être plus commode de définir une valeur par défaut sur la base de chaque propriété que de définir des valeurs par défaut dans des constructeurs, en particulier pour les types de valeurs. Toutefois, pour les types de référence, assurez-vous que la définition d’une valeur par défaut n’entraîne pas la création accidentelle d’un modèle de singleton. Pour plus d’informations, voir Meilleures pratiques plus loin dans cette rubrique.

Remarque  N’effectuez pas une inscription avec la valeur par défaut UnsetValue. Cela prêterait à confusion pour les consommateurs de propriété et aurait des conséquences inattendues dans le système de propriétés.

CreateDefaultValueCallback

Dans certains scénarios, vous définissez des propriétés de dépendance pour les objets qui sont utilisés sur plusieurs threads d’interface utilisateur. Cela peut être le cas si vous définissez un objet de données utilisé par plusieurs applications ou un contrôle que vous utilisez dans plusieurs applications. Vous pouvez activer l’échange de l’objet entre différents threads d’interface utilisateur en fournissant une implémentation de CreateDefaultValueCallback à la place d’une instance de valeur par défaut, qui est liée au thread ayant inscrit la propriété. Fondamentalement, CreateDefaultValueCallback définit une fabrique pour les valeurs par défaut. La valeur retournée par CreateDefaultValueCallback est toujours associée au thread CreateDefaultValueCallback de l’interface utilisateur actuelle, qui utilise l’objet.

Pour définir les métadonnées qui spécifient CreateDefaultValueCallback, vous devez appeler PropertyMetadata.Create afin de retourner une instance de métadonnées ; les constructeurs PropertyMetadata n’ont pas de signature qui comporte un paramètre CreateDefaultValueCallback.

Le modèle d’implémentation classique de CreateDefaultValueCallback consiste à créer une classe DependencyObject, à définir la valeur de propriété spécifique de chaque propriété de DependencyObject en fonction de la valeur par défaut appropriée, puis à retourner la nouvelle classe en tant que référence Object via la valeur de retour de la méthode CreateDefaultValueCallback.

Méthode de rappel de modification de propriété

Vous pouvez définir une méthode de rappel de modification de propriété pour définir les interactions de votre propriété avec d’autres propriétés de dépendance ou pour définir un état ou une propriété interne de votre objet chaque fois que la propriété change. Si votre rappel est effectué, le système de propriétés a déterminé qu’il existe un changement de valeur de propriété. La méthode de rappel étant statique, le paramètre d du rappel est important car il indique l’instance de la classe qui a signalé le changement. Une implémentation par défaut utilise la propriété NewValue des données d’événement et traite cette valeur d’une certaine manière, généralement en apportant une autre modification à l’objet transmis comme d. Il existe d’autres réponses à une modification de propriété, par exemple le rejet de la valeur signalée par NewValue, la restauration de OldValueou la définition de la valeur sur une contrainte de programmation appliquée à NewValue.

L’exemple suivant illustre une implémentation PropertyChangedCallback. Il implémente la méthode référencée dans les exemples Register précédents, dans le cadre des arguments de construction pour PropertyMetadata. Le scénario géré par ce rappel implique que la classe possède également une propriété en lecture seule calculée nommée "HasLabelValue" (implémentation non illustrée). Chaque fois que la propriété "Label" est réévaluée, cette méthode de rappel est appelée et le rappel permet à la valeur calculée dépendante de rester synchronisée avec les modifications apportées à la propriété de dépendance.


private static void OnLabelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
    ImageWithLabelControl iwlc = d as ImageWithLabelControl; //null checks omitted
    String s = e.NewValue as String; //null checks omitted
    if (s == String.Empty)
    {
        iwlc.HasLabelValue = false;
    } else {
        iwlc.HasLabelValue = true;
    }
}

Comportement des modifications de propriétés pour les structures et les énumérations

Si le type de DependencyProperty est une énumération ou une structure, le rappel peut être invoqué même si les valeurs internes de la structure ou la valeur d’énumération n’ont pas changé. Cela diffère d’un système primitif tel qu’une chaîne, où il est uniquement invoqué si la valeur a changé. Il s’agit d’une conséquence des opérations boxing et unboxing sur ces valeurs en interne. Si vous avez une méthode PropertyChangedCallback pour une propriété où votre valeur est une énumération ou une structure, vous devez comparer OldValue et NewValue en effectuant vous-même une conversion de type (transtypage) des valeurs et en utilisant les opérateurs de comparaison surchargés disponibles pour les valeurs de transtypage. À défaut, si aucun opérateur n’est disponible (ce qui peut être le cas pour une structure personnalisée), vous devrez peut-être comparer les valeurs individuelles. En principe, ne faites rien si les valeurs n’ont pas changé au final.



private static void OnVisibilityValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
    if ((Visibility)e.NewValue != (Visibility)e.OldValue)
    {
        //value really changed, invoke your changed logic here
    } // else this was invoked because of boxing, do nothing
}

Meilleures pratiques

Lors de la définition de votre propriété de dépendance, veillez à respecter les recommandations suivantes.

DependencyObject et threads

Toutes les instances de DependencyObject doivent être créées sur le thread d’interface utilisateur associé au Window actuel qui est affiché par une application Windows Runtime. Bien qu’il soit indispensable de créer chaque DependencyObject sur le thread d’interface utilisateur principal, les objets sont accessibles à l’aide d’une référence de répartiteur en provenance des autres threads, via l’appel de Dispatcher.

Les aspects relatifs aux threads de DependencyObject sont importants, car en règle générale, seul le code qui s’exécute sur le thread d’interface utilisateur peut modifier ou même lire la valeur d’une propriété de dépendance. Les problèmes de threads peuvent généralement être évités dans le code d’interface utilisateur classique qui utilise correctement les modèles async et les threads de travail d’arrière-plan. En règle générale, vous rencontrez des problèmes de threads relatifs à DependencyObject uniquement si vous définissez vos propres types DependencyObject et tentez de les utiliser pour des sources de données ou d’autres scénarios avec lesquels DependencyObject n’est pas nécessairement approprié.

Éviter les singletons accidentels

Il existe un risque de création accidentelle de singleton si vous déclarez une propriété de dépendance qui prend un type de référence et que vous appelez un constructeur pour ce type de référence dans le cadre du code qui établit votre PropertyMetadata. Toutes les utilisations de la propriété de dépendance partagent une seule instance de PropertyMetadata et essayent ainsi de partager le type de référence unique que vous avez construit. Toute sous-propriété de ce type de valeur que vous définissez par le biais de votre propriété de dépendance est alors propagée à d’autres objets de manière probablement indésirable.

Vous pouvez utiliser des constructeurs de classe pour définir des valeurs initiales pour une propriété de dépendance de type référence si vous voulez une valeur non-nulle, mais sachez que cela serait considéré comme une valeur locale pour les besoins de la priorité de propriété de dépendance. Il peut être préférable d’utiliser un modèle, si votre classe les prend en charge. Une autre manière d’éviter les modèles de singleton tout en fournissant une valeur par défaut utile consiste à exposer une propriété statique sur le type de référence qui fournit une valeur par défaut convenable pour les valeurs de cette classe.

Propriétés de dépendance de type collection

Avec les propriétés de dépendance de type collection, certains aspects supplémentaires liés à l’implémentation doivent être pris en compte.

Les propriétés de dépendance de type collection sont relativement rares dans l’API Windows Runtime. Dans la plupart des cas, vous pouvez utiliser des collections dans lesquelles les éléments sont une sous-classe DependencyObject, mais où la propriété de collection proprement dite est implémentée sous forme de propriété CLR ou C++ conventionnelle. Cela est dû au fait que les collections ne conviennent pas nécessairement à certains scénarios classiques où des propriétés de dépendance entrent en jeu. Par exemple :

  • Vous n’animez généralement pas une collection.
  • Vous ne préremplissez généralement pas les éléments d’une collection avec des styles ou un modèle.
  • Bien que la liaison à des collections soit un scénario majeur, il n’est pas obligatoire qu’une collection soit une propriété de dépendance pour être une source de liaison. Pour les cibles de liaison, il est plus courant d’utiliser des sous-classes de ItemsControl ou DataTemplate pour prendre en charge les éléments de collection ou pour utiliser des modèles d’affichage. Pour plus d’informations sur la liaison vers et à partir de collections, voir Liaison de données en XAML.
  • Il est préférable de gérer les notifications de modification de collection par le biais d’interfaces telles que INotifyPropertyChanged ou INotifyCollectionChanged, ou en dérivant le type de collection de ObservableCollection.

Néanmoins, il existe certains scénarios impliquant des propriétés de dépendance de type collection. Les trois sections qui suivent fournissent quelques recommandations quant à la manière d’implémenter une propriété de dépendance de type collection.

Initialisation de la collection

Lorsque vous créez une propriété de dépendance, vous pouvez établir une valeur par défaut au moyen de métadonnées de propriété de dépendance. Mais prenez soin de ne pas utiliser de collection statique de singletons comme valeur par défaut. Au lieu de cela, vous devez affecter comme valeur de collection une collection (d’instance) unique dans le cadre de la logique de constructeur de classe pour la classe propriétaire de la propriété de collection.

Notifications de modifications

Le fait de définir la collection en tant que propriété de dépendance ne procure pas automatiquement de notification de modification pour les éléments de la collection grâce à l’appel de la méthode de rappel "PropertyChanged" par le système de propriétés. Si vous voulez obtenir des notifications pour des collections ou des éléments de collection (par exemple pour un scénario de liaison de données), implémentez l’interface INotifyPropertyChanged ou INotifyCollectionChanged. Pour plus d’informations, voir Liaison de données avec XAML.

Considérations relatives à la sécurité des propriétés de dépendance

Déclarez les propriétés de dépendance comme propriétés publiques. Déclarez les identificateurs de propriétés de dépendance comme membres statiques publics en lecture seule. Même si vous essayez de déclarer d’autres niveaux d’accès autorisés par un langage (tels que protected), une propriété de dépendance est toujours accessible par le biais de l’identificateur combiné aux API du système de propriétés. La déclaration de l’identificateur de propriété de dépendance comme interne ou privé ne fonctionne pas, car dans ce cas le système ne peut pas opérer correctement.

Les propriétés wrappers ne sont là qu’à titre de commodité. Les mécanismes de sécurité appliqués aux wrappers peuvent être contournés en appelant GetValue ou SetValue. Il faut donc que les propriétés wrappers soient publiques, sinon vous ne faites que rendre votre propriété plus difficile à utiliser pour les appelants légitimes sans apporter de réel avantage en matière de sécurité.

Windows Runtime ne permet pas d’inscrire une propriété de dépendance personnalisée en lecture seule.

Propriétés de dépendance et constructeurs de classe

Il existe un principe général qui veut que les constructeurs de classe ne doivent pas appeler de méthodes virtuelles. Cela est dû au fait que les constructeurs peuvent être appelés pour accomplir une initialisation de base d’un constructeur de classe dérivé et que l’entrée dans la méthode virtuelle par le biais du constructeur peut se produire quand l’instance d’objet en construction n’est pas encore complètement initialisée. Quand vous dérivez d’une classe quelconque qui dérive déjà de DependencyObject, souvenez-vous que le système de propriétés lui-même appelle et expose des méthodes virtuelles en interne dans le cadre de ses services. Pour éviter tout problème d’initialisation au moment de l’exécution, ne définissez pas de valeurs de propriétés de dépendance dans des constructeurs de classes.

Inscription des propriétés de dépendance pour les applications C++/CX

L’inscription d’une propriété en C++/CX est plus compliquée à implémenter qu’en C#C#, non seulement en raison de la séparation en-tête/fichier d’implémentation, mais aussi parce que l’initialisation au niveau de l’étendue racine du fichier d’implémentation est une pratique déconseillée. (Les extensions de composant Visual C++ [C++/CX] placent le code de l’initialiseur statique de l’étendue racine directement dans DllMain, alors que les compilateurs C# affectent les initialiseurs statiques à des classes et évitent ainsi les problèmes de verrouillage de charge DllMain.) Dans le cas présent, la meilleure pratique consiste à déclarer une fonction d’assistance qui se charge de toutes les inscriptions de vos propriétés de dépendance pour une classe, une fonction par classe. Ensuite, pour chaque classe personnalisée que votre application consomme, vous devez faire référence à la fonction d’inscription d’assistance qui est exposée par chaque classe personnalisée que vous souhaitez utiliser. Appelez chaque fonction d’inscription d’assistance dans le cadre de la méthode Application constructor (App::App()), avant InitializeComponent. Ce constructeur s’exécute uniquement lorsque l’application est vraiment référencée pour la première fois (ainsi, il ne s’exécute pas une nouvelle fois lors de la reprise d’une application suspendue). Par ailleurs, comme vous pouvez le voir dans l’exemple d’inscription précédent en C++, la vérification nullptr autour de chaque appel Register est importante, car elle garantit qu’un appelant de la fonction ne peut inscrire la propriété deux fois. Sans une telle vérification, un deuxième appel d’inscription entraînerait probablement le blocage de votre application en raison de la duplication du nom de la propriété. Ce modèle d’implémentation est présenté dans l’Exemple de contrôles personnalisés et utilisateur XAML (examinez le code correspondant à la version C++/CX de l’exemple).

Rubriques associées

DependencyObject
DependencyProperty.Register
Vue d’ensemble des propriétés de dépendance
Exemple de contrôles personnalisés et utilisateur XAML

 

 

Afficher:
© 2014 Microsoft