Vue d’ensemble des propriétés de dépendance (applications du Windows Store en C#/VB/C++ et XAML)
Cette rubrique décrit le système de propriétés de dépendance disponible lorsque vous écrivez une application du Windows Store pour Windows en C++, C# ou Visual Basic avec des définitions XAML pour l’interface utilisateur.
Qu’est-ce qu’une propriété de dépendance ?
Une propriété de dépendance est un type spécialisé de propriété qui est suivi par un système de propriétés dédiées qui fait partie de Windows Runtime. Afin de prendre en charge une propriété de dépendance, l’objet qui définit la propriété doit être un objet DependencyObject (en d’autres termes, une classe ayant une classe de base DependencyObject quelque part dans son héritage). Un grand nombre des types que vous utilisez pour une application du Windows Store avec XAML pour l’interface utilisateur et C#, Microsoft Visual Basic ou C++ constituent une sous-classe DependencyObject et prennent en charge les propriétés de dépendance.
L’objectif des propriétés de dépendance est de fournir une manière systémique de calculer la valeur d’une propriété en fonction d’autres entrées. Il peut s’agir des entrées suivantes :
- entrée externe telle qu’une préférence utilisateur ;
- mécanismes de détermination de propriété juste-à-temps tels que la liaison de données, les animations et les tables de montage séquentiel ;
- modèles à utilisation multiples tels que ressources et styles ;
- valeurs connues par le biais de relations parent-enfant avec d’autres éléments dans l’arborescence d’objets.
Une propriété de dépendance représente ou prend en charge une fonctionnalité spécifique du modèle de programmation pour définir une application du Windows Store avec XAML pour l’interface utilisateur et C#, Visual Basic ou C++ pour le code. Ces fonctionnalités incluent :
- Liaison de données
- Styles
- Animations dans une table de montage séquentiel
- Comportement de "PropertyChanged" (il est possible d’implémenter une propriété de dépendance afin de fournir des rappels capables de propager des modifications à d’autres propriétés de dépendance)
- Valeur par défaut via les métadonnées
- Utilitaire système de propriétés générales tel que ClearValue et recherche de métadonnées
Propriétés de dépendance et propriétés Windows Runtime
Les propriétés de dépendance étendent les fonctionnalités des propriétés Windows Runtime de base en fournissant une banque de propriétés en soutien à une propriété. Il s’agit d’une alternative du modèle standard de stockage d’une propriété avec un champ privé. Vous pouvez considérer une banque de propriétés comme un ensemble d’identificateurs de propriétés et de valeurs qui existent pour tout objet particulier. Au lieu d’être identifiée par son nom, chaque propriété de la banque est identifiée par une instance de DependencyProperty.
L’autre type important qui définit le système de propriétés de dépendance est DependencyObject. DependencyObject définit la classe de base capable d’inscrire et de posséder une propriété de dépendance et c’est DependencyObject qui gère les valeurs de ses propriétés de dépendance dans une banque.
Voici un résumé de la terminologie employée dans la présente documentation à propos des propriétés de dépendance :
| Terme | Description |
|---|---|
|
Propriété de dépendance |
Propriété qui existe sur une sous-classe DependencyObject est stockée par la banque de propriétés DependencyObject et identifiée par un identificateur DependencyProperty. Habituellement, l’identificateur est disponible en tant que membre statique de la classe DependencyObject de définition. |
|
Identificateur de propriété de dépendance |
Instance DependencyProperty. Pour une propriété de dépendance existante dans l’API principale, cette instance est habituellement exposée en tant que propriété statique publique en lecture seule, en tant que membre du même type DependencyObject qui utilise la propriété de dépendance. Il est également possible d’utiliser l’identificateur de propriété de dépendance en tant que paramètre dans les API telles que GetValue et SetValue, qui exposent les principes fondamentaux du système de propriétés de dépendance, ou Setter.Property. |
|
Wrapper de propriété |
Implémentations get et set pouvant être appelées pour une propriété Windows Runtime. Ou projection propre au langage de la définition d’origine. Une implémentation wrapper de propriété get appelle GetValue, en passant l’identificateur de propriété de dépendance approprié comme entrée et en renvoyant la valeur. Une implémentation wrapper de propriété set appelle SetValue, en passant l’identificateur de propriété de dépendance approprié comme première entrée et la valeur à définir comme deuxième entrée. |
Le wrapper de propriété n’est pas seulement pratique pour les appelants, il expose également la propriété de dépendance à tout processus, tout outil ou toute projection qui utilise des définitions Windows Runtime pour les propriétés.
L’exemple suivant définit une propriété de dépendance "IsSpinning" personnalisée telle qu’elle est définie pour C#, puis montre la relation entre l’identificateur de propriété de dépendance et le wrapper de propriété.
public static readonly DependencyProperty IsSpinningProperty = DependencyProperty.Register( "IsSpinning", typeof(Boolean), typeof(ExampleClass), null ); public bool IsSpinning //the property wrapper { get { return (bool)GetValue(IsSpinningProperty); } set { SetValue(IsSpinningProperty, value); } }
Remarque L’exemple précédent n’a pas vocation à représenter un exemple exhaustif de création de propriété de dépendance personnalisée. Il a pour but d’illustrer les concepts de propriété de dépendance pour toute personne qui assimile mieux un concept en examinant du code représentatif. Pour obtenir un exemple complet de création de propriété de dépendance personnalisée, voir Propriétés de dépendance personnalisées.
Fonctionnalités de propriété fournie par une propriété de dépendance
Liaison de données
Tant que la propriété de dépendance à définir se trouve sur une sous-classe DependencyObject, sa valeur peut être définie par l’intermédiaire de la liaison de données. La liaison de données utilise une syntaxe d’extension de balisage spécifique en XAML ou la classe Binding dans le code. Avec la liaison de données, la détermination de la valeur de la propriété finale est différée jusqu’au moment de l’exécution. La valeur est alors obtenue à partir d’une source de données. C’est l’aspect différé qui oblige la propriété cible à être une propriété de dépendance.
L’exemple suivant définit le texte d’un bloc de texte, à l’aide d’une liaison en XAML. La liaison utilise un contexte de données hérité et une source de données d’objet. (Aucun des deux n’est présenté dans l’exemple réduit ; pour obtenir un exemple plus complet qui montre le contexte et la source, voir Liaison de données avec XAML.)
<Canvas> <TextBlock Text="{Binding Team.TeamName}"/> </Canvas>
Vous pouvez également établir des liaisons à l’aide de code plutôt qu’en XAML. Voir SetBinding.
Remarque Les liaisons sont traitées en tant que valeur locale à des fins de priorité des valeurs de propriété de dépendance. Si vous affectez une autre valeur locale à une propriété qui contenait à l’origine une valeur Binding, vous éliminez la liaison.
Sources de liaison, cibles de liaison
Pour être la source d’une liaison, une propriété n’a pas besoin d’être une propriété de dépendance ; vous pouvez généralement utiliser n’importe quelle propriété en tant que source de liaison. Toutefois, pour être la cible d’une liaison, cette propriété doit être une propriété de dépendance.
Si vous définissez des liaisons dans du code, notez que l’API SetBinding est uniquement définie pour FrameworkElement. Toutefois, vous pouvez créer une définition de liaison à l’aide de la classe BindingOperations, et ainsi référencer toute propriété DependencyObject.
Qu’il s’agisse de code ou de XAML, n’oubliez pas que la propriété DataContext est une propriété FrameworkElement. En utilisant une forme d’héritage de propriétés entre parents et enfants (habituellement défini dans le balisage XAML), le système de liaison peut résoudre une propriété DataContext qui existe sur un élément parent, même si l’objet enfant (qui possède la propriété cible) n’est pas une classe FrameworkElement et ne contient donc pas sa propre valeur DataContext. En revanche, cet élément parent doit être une classe FrameworkElement afin de définir et contenir la propriété DataContext. Autrement, vous devez définir la liaison de sorte qu’elle puisse fonctionner avec une propriété DataContext Null.
Pour qu’une liaison unidirectionnelle ou bidirectionnelle soit efficace, la propriété source doit prendre en charge les notifications de modifications qui se propagent au système de liaison et par conséquent à la cible. Pour les sources de liaison personnalisées, cela signifie que la propriété doit prendre en charge INotifyPropertyChanged. Les collections doivent prendre en charge INotifyCollectionChanged. Certaines classes prennent en charge une de ces interfaces dans leurs implémentations afin d’être utiles en tant que classes de base pour les scénarios de liaison de données ; ObservableVector est un exemple d’une telle classe. Pour plus d’informations sur la liaison de données et sa relation avec le système de propriétés, voir Vue d’ensemble de la liaison de données.
Remarque Les sources de données C++ utilisent différentes interfaces pour la notification de modification. Voir Liaison aux collections.
Styles et modèles
Les styles et modèles constituent deux des scénarios pour la définition de propriétés en tant que propriétés de dépendance. Les styles s’avèrent utiles pour définir les propriétés qui déterminent l’interface utilisateur de l’application. Les styles sont définis en tant que ressources en XAML, soit comme entrée dans une collection Resources, soit dans des fichiers XAML distincts tels que des dictionnaires de ressources de thème. Les styles interagissent avec le système de propriétés car ils contiennent des méthodes setter pour les propriétés. La propriété la plus importante ici est la propriété Control.Template d’une classe Control : elle définit la majeure partie de l’aspect visuel et de l’état visuel d’une classe Control. Pour plus d’informations sur les styles, et pour obtenir un exemple XAML qui définit une classe Style et utilise des méthodes setter, voir Démarrage rapide : application de styles aux contrôles.
Les valeurs qui proviennent de styles ou de modèles sont nécessairement différées. Il en est ainsi pour que les utilisateurs de contrôles puissent remodéliser les contrôles ou redéfinir les styles. Et c’est la raison pour laquelle les styles définissent des propriétés de dépendance.
Animations dans une table de montage séquentiel
Vous pouvez animer la valeur d’une propriété de dépendance à l’aide d’une animation dans une table de montage séquentiel. Dans Windows Runtime, les animations dans une table de montage séquentiel ne sont pas simplement des décorations visuelles. Vous pouvez considérer les animations comme une technique de machine à états qui vous permet de définir l’état de propriétés individuelles ou de contrôles entiers, et d’en modifier la valeur dans le temps.
Pour être animée, la propriété cible de l’animation doit être une propriété de dépendance. En outre, pour être animée, le type de valeur de la propriété cible doit être pris en charge par l’un des types d’animation dérivés de Timeline existants. Lorsqu’une animation est appliquée et exécutée, la valeur animée fonctionne à un niveau de priorité supérieur à toute valeur (telle qu’une valeur locale) autrement affectée à la propriété. Les animations ont également un comportement HoldEnd optionnel pouvant entraîner leur application aux valeurs de propriété même si elles semblent visuellement arrêtées.
Le principe de machine à états est incarné par l’utilisation d’animations dans une table de montage séquentiel dans le cadre du modèle d’état VisualStateManager pour les contrôles. Pour plus d’informations sur les animations dans une table de montage séquentiel, voir Animations dans une table de montage séquentiel. Pour plus d’informations sur VisualStateManager, voir Animations dans une table de montage séquentiel pour les états visuels ou Démarrage rapide : modèles de contrôles.
Comportement modifié par une propriété
Le comportement modifié par une propriété est l’origine du côté « dépendance » de la terminologie liée aux propriétés de dépendance. Le maintien de valeurs valides pour une propriété quand une autre propriété peut influencer la valeur de la première propriété constitue un problème de développement difficile dans de nombreuses infrastructures. Dans le système de propriétés Windows Runtime, chaque propriété de dépendance peut spécifier un rappel qui est invoqué dès lors que sa valeur change. Ce rappel peut servir à notifier ou modifier des valeurs de propriété associées, d’une manière généralement synchrone. De nombreuses propriétés de dépendance ont un comportement modifié par une propriété. Vous pouvez également ajouter un comportement de rappel similaire à des propriétés de dépendance personnalisées, puis implémenter vos propres rappels modifiés par une propriété. Pour obtenir un exemple, voir Propriétés de dépendance personnalisées.
Valeur par défaut et ClearValue
Une propriété de dépendance peut avoir une valeur par défaut définie dans le cadre de ses métadonnées. La différence entre la valeur par défaut d’une propriété ordinaire et celle d’une propriété de dépendance est que la valeur par défaut peut s’appliquer dès lors qu’un autre déterminant de la priorité de la valeur disparaît. (La priorité de la valeur de la propriété de dépendance est expliquée dans la section suivante.) Par exemple, vous pouvez volontairement supprimer un modèle ou une animation d’une propriété, tout en souhaitant que la valeur soit une valeur par défaut raisonnable par la suite. La valeur par défaut de la propriété de dépendance fournit cette valeur, sans qu’il soit nécessaire de la définir spécifiquement dans tous les cas.
Mais il est nécessaire d’affecter délibérément à la propriété la valeur par défaut si vous avez déjà affecté une valeur locale. La nouvelle définition de la propriété affecte tout simplement la valeur locale une nouvelle fois sans vraiment rétablir la valeur par défaut. Pour réinitialiser une valeur afin qu’elle soit de nouveau la valeur par défaut, mais aussi pour activer d’autres participants en priorité qui peuvent remplacer la valeur par défaut mais pas une valeur locale, vous appelez la méthode ClearValue sur la propriété.
Priorité de la valeur de la propriété de dépendance
Lorsque vous obtenez la valeur d’une propriété de dépendance, vous obtenez une valeur qui a été affectée à cette propriété via l’une des entrées qui participent au système de propriétés Windows Runtime. Il existe une priorité de la valeur de la propriété de dépendance selon laquelle une diversité de scénarios relatifs à la manière dont les propriétés Windows Runtime obtiennent leurs valeurs peut interagir de façon prévisible.
Par exemple, les styles et modèles ont vocation à constituer un point de départ partagé pour établir des valeurs de propriété, et par conséquent les aspects d’un contrôle. Mais sur une instance de contrôle particulière, vous pouvez avoir envie de modifier un aspect propre à une propriété du contrôle par rapport au modèle courant, notamment en lui donnant une couleur d’arrière-plan différent ou une chaîne de texte différente en tant que contenu. Le système de propriétés Windows Runtime utilise les valeurs locales à un niveau de priorité supérieur à celui des valeurs fournis par les styles et modèles, ce qui permet ainsi ce scénario.
Ordre de priorité des propriétés de dépendance
La liste suivante indique l’ordre définitif utilisé par le système de propriétés pour assigner les valeurs d’exécution des propriétés de dépendance. La priorité la plus élevée est répertoriée en premier. Vous trouverez d’autres explications de certains éléments de priorité dans les sous-sections immédiates qui suivent la liste.
- Animations actives, animations de l’état visuel ou animations avec un comportement HoldEnd. Pour avoir un effet pratique, l’animation d’une propriété doit être prioritaire par rapport à la valeur de base (inanimée), même si cette valeur a été définie localement.
- Valeur locale. Une valeur locale peut être affectée à partir du wrapper de propriété, ce qui est comparable à la définition d’un attribut ou d’un élément de propriété en XAML ou par un appel de la méthode SetValue à l’aide d’une propriété d’une instance spécifique. Si vous définissez une valeur locale à l’aide d’une liaison ou d’une ressource statique, celle-ci fonctionne dans la priorité comme si une valeur locale avait été définie, et les liaisons ou références de ressources sont effacées si une nouvelle valeur locale est définie.
- Propriétés basées sur un modèle Un élément en comporte s’il a été créé dans le cadre d’un modèle (une classe ControlTemplate ou DataTemplate).
- Méthodes setter de style. Valeurs provenant d’une classe Setter au sein de styles à partir de ressources d’application ou de page.
- Valeur par défaut. Toute propriété de dépendance peut avoir une valeur par défaut.
Propriétés basées sur un modèle
Les propriétés basées sur un modèle en tant qu’élément de priorité ne s’appliquent pas à toute propriété d’un élément que vous déclarez directement dans le balisage de page XAML. Le concept de propriété basée sur un modèle existe uniquement pour les objets compris au sein d’une arborescence d’objets qui naissent via l’application du modèle. Lorsque le système de propriétés recherche les propriétés basées sur un modèle d’une valeur, il recherche le modèle qui a créé cet objet. Les valeurs de propriétés provenant du modèle agissent comme si elles étaient définies en tant que valeur locale sur l’objet, mais elles doivent pouvoir être distinguées d’une vraie valeur locale.
Notez que selon la manière dont il est construit, le modèle peut même remplacer des valeurs locales, s’il ne parvient pas à fournir des références TemplateBinding pour les propriétés définissables appropriées comme elles doivent apparaître dans les éléments du modèle. Ceci se produit uniquement si la propriété est une propriété héritée qui n’a pas de propriété analogue dans le modèle spécifique ou la conception visuelle.
Liaisons et priorité
Les opérations de liaison sont traitées comme si elles définissaient la valeur à laquelle elles sont appliquées. Par exemple, une liaison appliquée à une valeur locale agit comme une valeur locale, et une liaison pour une méthode setter au sein d’un style s’applique comme une méthode setter de style. Étant donné que les liaisons doivent être capables d’obtenir des valeurs à partir de l’état d’exécution de l’application, le processus réel de détermination de la priorité de la valeur d’une propriété, quelle qu’elle soit, s’étend également jusqu’au moment de l’exécution.
Non seulement les liaisons fonctionnent au même niveau de priorité qu’une valeur locale, mais elles correspondent vraiment à une valeur locale, mais avec une valeur différée. Si vous avez une liaison en place pour une valeur de propriété, toute valeur locale que vous définissez par la suite remplace entièrement la liaison. De même, si vous appelez la méthode SetBinding, vous remplacez la valeur locale précédente.
Animations dans une table de montage séquentiel et valeur de base
Les animations dans une table de montage séquentiel agissent sur une valeur appelée « valeur de base » dans toute la présente documentation. La valeur de base est donc une valeur, quelle qu’elle soit, déterminée par une évaluation ascendante dans la priorité jusqu’à ce que la « valeur locale » soit atteinte.
Pour une propriété animée, la valeur de base peut avoir un impact sur la valeur animée, si cette animation ne spécifie pas à la fois From et To pour certains comportements, ou si l’animation rétablit délibérément la valeur de base une fois qu’elle est terminée. Ensuite, une priorité normale est utilisée pour déterminer la valeur de base.
Inversement, une animation qui spécifie un To avec un comportement HoldEnd peut remplacer une valeur locale jusqu’à ce qu’elle soit supprimée, même lorsqu’elle apparaît visuellement arrêtée.
Il est possible d’appliquer plusieurs animations à une seule propriété, chacune de ces animations ayant éventuellement été définie à partir de points différents dans la priorité de la valeur. Toutefois, ces animations composent potentiellement leurs valeurs, au lieu de simplement appliquer l’animation à partir de la priorité la plus élevée. Cela dépend de la façon exacte dont sont définies les animations et du type de valeur qui est animé.
Valeurs par défaut
Les valeurs par défaut des propriétés de dépendance sont généralement l’une des suivantes :
- La valeur par défaut d’une propriété de dépendance de type référence est Null.
- La valeur par défaut d’une propriété de dépendance de type valeur est la valeur construite par défaut. Pour les primitives, cela entraîne des valeurs par défaut attendues telles que 0 pour un entier et un double. Pour les structures telles que Point ou les structures personnalisées, le constructeur par défaut implicite est utilisé. Pour les énumérations, la valeur par défaut est le premier membre défini.
- La valeur par défaut d’une propriété de dépendance de type chaîne est une chaîne vide.
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 du Windows Store en C++, C# ou Visual Basic. 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 asynchrones 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é.
Rubriques associées
- Documentation conceptuelle
- Propriétés de dépendance personnalisées
- Vue d’ensemble des propriétés jointes
- Vue d’ensemble de la liaison de données
- Animations dans une table de montage séquentiel
- Création de composants Windows Runtime
- Exemple de contrôles personnalisés et utilisateur XAML
- API en rapport avec les propriétés de dépendance
- DependencyObject
- DependencyProperty
