Priorité de la valeur de propriété de dépendance (WPF .NET)

le fonctionnement du système de propriétés Windows Presentation Foundation (WPF) affecte la valeur d’une propriété de dépendance. Cet article explique comment la précédence des différentes entrées basées sur les propriétés dans le système de propriétés WPF détermine la valeur effective d’une propriété de dépendance.

Prérequis

Cet article suppose une connaissance de base des propriétés de dépendance et que vous avez lu vue d’ensemble des propriétés de dépendance. Pour suivre les exemples de cet article, il est utile de connaître Extensible Application Markup Language (XAML) et de savoir comment écrire des applications WPF.

Le système de propriétés WPF

Le système de propriétés WPF utilise divers facteurs pour déterminer la valeur des propriétés de dépendance, telles que la validation de propriété en temps réel, la liaison tardive et les notifications de modification de propriété pour les propriétés associées. Bien que l’ordre et la logique utilisés pour déterminer les valeurs des propriétés de dépendance soient complexes, l’apprentissage peut vous aider à éviter des paramètres de propriété inutiles et à comprendre pourquoi une tentative de définition d’une propriété de dépendance n’a pas entraîné la valeur attendue.

Propriétés de dépendance définies à plusieurs endroits

L’exemple de code XAML suivant montre comment trois opérations « Set » différentes sur la Background propriété du bouton peuvent influencer sa valeur.

<StackPanel>
    <StackPanel.Resources>
        <ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
            <Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" 
                    BorderBrush="{TemplateBinding BorderBrush}">
                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Border>
        </ControlTemplate>
    </StackPanel.Resources>

    <Button Template="{StaticResource ButtonTemplate}" Background="Red">
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Setter Property="Background" Value="Blue"/>
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="Yellow" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
        Which color do you expect?
    </Button>
</StackPanel>

Dans l’exemple, la Background propriété est définie localement sur Red . Toutefois, le style implicite déclaré dans la portée du bouton tente d’affecter la valeur à la Background propriété Blue . Et, lorsque la souris se trouve sur le bouton, le déclencheur dans le style implicite tente d’affecter à la propriété la valeur Background Yellow . À l’exception de la contrainte et de l’animation, une valeur de propriété définie localement a la priorité la plus élevée, donc le bouton sera rouge — même sur MouseOver. Toutefois, si vous supprimez la valeur définie localement du bouton, elle obtiendra sa Background valeur à partir du style. Dans un style, les déclencheurs sont prioritaires, donc le bouton est jaune sur MouseOver et bleu dans le cas contraire. L’exemple remplace la valeur par défaut du bouton ControlTemplate , car le modèle par défaut a une valeur MouseOver codée en dur Background .

Ordre de priorité des propriétés de dépendance

La liste suivante est l’ordre de priorité définitif utilisé par le système de propriétés lors de l’affectation de valeurs d’exécution à des propriétés de dépendance. La priorité la plus élevée est répertoriée en premier.

  1. Contrainte du système de propriétés. Pour plus d’informations sur la contrainte, consultez forçage et animations.

  2. Animations actives ou animations avec un comportement de maintien. Pour avoir un effet pratique, une valeur d’animation doit avoir la priorité sur la valeur de base (non animée), même si la valeur de base a été définie localement. Pour plus d’informations, consultez forçage et animations.

  3. Valeurs locales. Vous pouvez définir une valeur locale via une propriété « wrapper », qui équivaut à définir un attribut ou un élément de propriété en XAML, ou par un appel à l' SetValue API à l’aide d’une propriété d’une instance spécifique. Une valeur locale définie par le biais d’une liaison ou d’une ressource aura la même priorité qu’une valeur directement définie.

  4. Valeurs de propriété de modèle TemplatedParent. Un élément a un TemplatedParent s’il a été créé par un modèle ( ControlTemplate ou DataTemplate ). Pour plus d’informations, consultez TemplatedParent. Dans le modèle spécifié par TemplatedParent , l’ordre de priorité est le suivant :

    1. Déclencheurs.

    2. Jeux de propriétés, généralement par le biais d’attributs XAML.

  5. Styles implicites. S’applique uniquement à la propriété Style. La Style valeur est toute ressource de style avec une TargetType valeur qui correspond au type d’élément. La ressource de style doit exister dans la page ou l’application. La recherche d’une ressource de style implicite ne s’étend pas aux ressources de styles dans les thèmes.

  6. Déclencheurs de style. Un déclencheur de style est un déclencheur dans un style explicite ou implicite. Le style doit exister dans la page ou dans l’application. Les déclencheurs dans les styles par défaut ont une priorité plus faible.

  7. Déclencheurs de modèle. Un déclencheur de modèle est un déclencheur issu d’un modèle directement appliqué ou d’un modèle dans un style. Le style doit exister dans la page ou dans l’application.

  8. Valeurs de l’accesseur Set de style. Une valeur de setter de style est une valeur appliquée par un Setter dans un style. Le style doit exister dans la page ou dans l’application.

  9. Les styles par défaut, également appelés styles de thème. Pour plus d’informations, consultez styles par défaut (thème). Dans un style par défaut, l’ordre de priorité est le suivant :

    1. Déclencheurs actifs.

    2. Méthodes setter.

  10. Héritage. Certaines propriétés de dépendance d’un élément enfant héritent de leur valeur de l’élément parent. Par conséquent, il n’est pas nécessaire de définir des valeurs de propriété sur chaque élément de l’application. Pour plus d’informations, consultez héritage de la valeur de propriété.

  11. Valeur par défaut des métadonnées de la propriété de dépendance Une propriété de dépendance peut avoir une valeur par défaut définie lors de l’inscription du système de propriétés de cette propriété. Les classes dérivées qui héritent d’une propriété de dépendance peuvent substituer les métadonnées de propriété de dépendance (y compris la valeur par défaut) en fonction du type. Pour plus d’informations, consultez métadonnées de propriété de dépendance. Pour une propriété héritée, la valeur par défaut d’un élément parent est prioritaire par rapport à la valeur par défaut d’un élément enfant. Ainsi, si une propriété pouvant être héritée n’est pas définie, la valeur par défaut de la racine ou du parent est utilisée à la place de la valeur par défaut de l’élément enfant.

TemplatedParent

TemplatedParent la priorité ne s’applique pas aux propriétés des éléments qui sont déclarés directement dans le balisage d’application standard. Le TemplatedParent concept existe uniquement pour les éléments enfants dans une arborescence d’éléments visuels qui interviennent via l’application d’un modèle. Lorsque le système de propriétés recherche le modèle spécifié par TemplatedParent pour les valeurs de propriété d’un élément, il recherche le modèle qui a créé l’élément. Les valeurs de propriété du TemplatedParent modèle agissent généralement comme s’il s’agissait de valeurs localement définies sur l’élément, mais avec une précédence moins élevée que les valeurs locales réelles, car les modèles sont potentiellement partagés. Pour plus d’informations, consultez TemplatedParent.

La propriété style

Le même ordre de priorité s’applique à toutes les propriétés de dépendance, à l’exception de la Style propriété. La Style propriété est unique, car elle ne peut pas lui-même être stylisée. La contrainte ou l’animation de la Style propriété n’est pas recommandée (et l’animation de la Style propriété nécessiterait une classe d’animation personnalisée). Par conséquent, tous les éléments de précédence ne s’appliquent pas. Il existe trois façons de définir la Style propriété :

  • Style explicite. La Style propriété d’un élément est définie directement. La Style valeur de la propriété agit comme s’il s’agissait d’une valeur locale et a la même priorité que l’élément 3 dans la liste des priorités. Dans la plupart des scénarios, les styles explicites ne sont pas définis inline et sont plutôt explicitement référencés en tant que ressource, par exemple Style="{StaticResource myResourceKey}" .

  • Style implicite. La Style propriété d’un élément n’est pas définie directement. Au lieu de cela, un style est appliqué lorsqu’il existe à un certain niveau de la page ou de l’application, et a une clé de ressource qui correspond au type d’élément auquel le style s’applique, par exemple <Style TargetType="x:Type Button"> . Le type doit correspondre exactement, par exemple <Style TargetType="x:Type Button"> ne sera pas appliqué au MyButton type même si MyButton est dérivé de Button . La Style valeur de la propriété a la même priorité que l’élément 5 dans la liste des priorités. Une valeur de style implicite peut être détectée en appelant la DependencyPropertyHelper.GetValueSource méthode, en passant la Style propriété et ImplicitStyleReference en vérifiant dans les résultats.

  • Style par défaut, également appelé style de thème. La Style propriété d’un élément n’est pas définie directement. Au lieu de cela, il provient de l’évaluation du thème d’exécution par le moteur de présentation WPF. Avant l’exécution, la valeur de la Style propriété est null . La Style valeur de la propriété a la même priorité que l’élément 9 dans la liste des priorités.

Styles par défaut (thème)

Chaque contrôle fourni avec WPF a un style par défaut qui peut varier selon le thème, ce qui explique pourquoi le style par défaut est parfois appelé style de thème.

Le ControlTemplate est un élément important dans le style par défaut d’un contrôle. ControlTemplate est une valeur Setter pour la propriété du style Template . Si les styles par défaut ne contenaient pas de modèle, un contrôle sans modèle personnalisé dans le cadre d’un style personnalisé n’aurait aucune apparence visuelle. Non seulement un modèle définit l’apparence visuelle d’un contrôle, mais définit également les connexions entre les propriétés dans l’arborescence d’éléments visuels du modèle et la classe de contrôle correspondante. Chaque contrôle expose un ensemble de propriétés qui peuvent influencer l’apparence visuelle du contrôle sans remplacer le modèle. Par exemple, considérez l’apparence visuelle par défaut d’un Thumb contrôle, qui est un ScrollBar composant.

Un Thumb contrôle a certaines propriétés personnalisables. Le modèle par défaut d’un Thumb contrôle crée une structure de base, ou arborescence d’éléments visuels, avec plusieurs composants imbriqués Border pour créer un aspect biseauté. Dans le modèle, les propriétés qui sont destinées à être personnalisées par la Thumb classe sont exposées par le biais de TemplateBinding. Le modèle par défaut pour le Thumb contrôle a plusieurs propriétés de bordure qui partagent une liaison de modèle avec des propriétés telles que Background ou BorderThickness . Toutefois, lorsque les valeurs des propriétés ou des dispositions visuelles sont codées en dur dans le modèle, ou si elles sont liées à des valeurs provenant directement du thème, vous pouvez uniquement modifier ces valeurs en remplaçant l’intégralité du modèle. En règle générale, si une propriété provient d’un parent basé sur un modèle et n’est pas exposée par un TemplateBinding , la valeur de la propriété ne peut pas être modifiée par des styles, car il n’existe aucun moyen pratique de la cibler. Toutefois, cette propriété peut toujours être influencée par l’héritage des valeurs de propriété dans le modèle appliqué ou par une valeur par défaut.

Les styles par défaut spécifient un TargetType dans leurs définitions. L’évaluation du thème d’exécution fait correspondre le TargetType d’un style par défaut à la DefaultStyleKey propriété d’un contrôle. En revanche, le comportement de recherche pour les styles implicites utilise le type réel du contrôle. La valeur de DefaultStyleKey est héritée par les classes dérivées, de sorte que les éléments dérivés qui peuvent autrement avoir un style associé obtiennent une apparence visuelle par défaut. Par exemple, si vous dérivez MyButton de Button , MyButton héritera du modèle par défaut de Button . Les classes dérivées peuvent substituer la valeur par défaut de DefaultStyleKey dans les métadonnées de propriété de dépendance. Par conséquent, si vous souhaitez une représentation visuelle différente pour MyButton , vous pouvez remplacer les métadonnées de propriété de dépendance pour DefaultStyleKey sur MyButton , puis définir le style par défaut approprié, y compris un modèle, que vous allez empaqueter avec votre MyButton contrôle. Pour plus d’informations, consultez vue d’ensemblede la création de contrôles.

Ressource dynamique

Les références de ressources dynamiques et les opérations de liaison ont la priorité de l’emplacement où elles sont définies. Par exemple, une ressource dynamique appliquée à une valeur locale a la même priorité que l’élément 3 dans la liste des priorités. Autre exemple : une liaison de ressource dynamique appliquée à un accesseur Set de propriété dans un style par défaut a la même priorité que l’élément 9 dans la liste des priorités. Étant donné que les références de ressources dynamiques et la liaison doivent obtenir des valeurs à partir de l’état d’exécution de l’application, le processus de détermination de la priorité de la valeur de propriété pour une propriété donnée s’étend dans le Runtime.

Les références de ressources dynamiques ne font pas techniquement partie du système de propriétés et ont leur propre ordre de recherche qui interagit avec la liste des priorités. Fondamentalement, la priorité des références de ressources dynamiques est : élément à la racine de la page, application, thème, puis système. Pour plus d’informations, consultez Ressources XAML.

Bien que les liaisons et les références de ressources dynamiques aient la priorité de l’emplacement où elles sont définies, la valeur est différée. En conséquence, si vous définissez une ressource dynamique ou une liaison sur une valeur locale, toute modification apportée à la valeur locale remplace entièrement la ressource ou la liaison dynamique. Même si vous appelez la ClearValue méthode pour effacer la valeur définie localement, la ressource ou la liaison dynamique ne sera pas restaurée. En fait, si vous appelez ClearValue sur une propriété qui a une ressource ou une liaison dynamique (sans valeur locale littérale), la ressource ou la liaison dynamique est effacée.

SetCurrentValue

La SetCurrentValue méthode est une autre façon de définir une propriété, mais elle ne figure pas dans la liste des priorités. SetCurrentValue vous permet de modifier la valeur d’une propriété sans remplacer la source d’une valeur précédente. Par exemple, si une propriété est définie par un déclencheur, puis que vous affectez une autre valeur à l’aide de SetCurrentValue , l’action de déclencheur suivante affecte à la propriété la valeur du déclencheur. Vous pouvez utiliser SetCurrentValue chaque fois que vous souhaitez définir une valeur de propriété sans donner à cette valeur le niveau de priorité d’une valeur locale. De même, vous pouvez utiliser SetCurrentValue pour modifier la valeur d’une propriété sans remplacer une liaison.

Contrainte et animation

La contrainte et l’animation agissent toutes deux sur une valeur de base. La valeur de base est la valeur de la propriété de dépendance ayant la priorité la plus élevée, déterminée par l’évaluation à l’aide de la liste des précédences jusqu’à ce que l’élément 2 soit atteint.

Si une animation ne spécifie pas les From To valeurs de propriété et pour certains comportements, ou si l’animation revient délibérément à la valeur de base lorsqu’elle est terminée, la valeur de base peut affecter la valeur animée. Pour voir cela dans la pratique, exécutez l’exemple d’application valeurs cibles . Dans l’exemple, pour la hauteur du rectangle, essayez de définir les valeurs locales initiales qui diffèrent de toute From valeur. Les exemples d’animations démarrent immédiatement à l’aide From de la valeur au lieu de la valeur de base. En spécifiant Stop comme FillBehavior , à la fin d’une animation, une valeur de propriété est réinitialisée à sa valeur de base. La priorité normale est utilisée pour la détermination de la valeur de base après la fin d’une animation.

Plusieurs animations peuvent être appliquées à une seule propriété, chaque animation ayant une priorité différente. Au lieu d’appliquer l’animation avec la priorité la plus élevée, le moteur de présentation WPF peut combiner les valeurs d’animation, en fonction de la façon dont les animations ont été définies et du type de valeurs animées. Pour plus d’informations, consultez Vue d’ensemble de l’animation.

La contrainte figure en haut de la liste des priorités. Même une animation en cours d’exécution est sujette à la contrainte de valeur. Certaines propriétés de dépendance existantes dans WPF ont une contrainte intégrée. Pour les propriétés de dépendance personnalisées, vous pouvez définir le comportement de forçage en écrivant un CoerceValueCallback que vous transmettez dans le cadre des métadonnées lorsque vous créez une propriété. Vous pouvez également substituer le comportement de forçage des propriétés existantes en substituant les métadonnées de cette propriété dans une classe dérivée. La contrainte interagit avec la valeur de base de telle sorte que les contraintes sur la contrainte sont appliquées telles qu’elles existent à ce moment-là, mais la valeur de base est toujours conservée. Par conséquent, si les contraintes de contrainte sont levées par la suite, la contrainte retourne la valeur la plus proche possible de la valeur de base et, éventuellement, l’influence de la contrainte sur une propriété prend fin dès que toutes les contraintes sont levées. Pour plus d’informations sur le comportement de forçage, consultez validation et rappels de propriétés de dépendance.

Comportements des déclencheurs

Les contrôles définissent souvent des comportements de déclencheur dans le cadre de leur style par défaut. La définition de propriétés locales sur des contrôles peut potentiellement entrer en conflit avec ces déclencheurs, empêchant ainsi les déclencheurs de répondre (visuellement ou de manière comportementale) à des événements pilotés par l’utilisateur. Une utilisation courante d’un déclencheur de propriété consiste à contrôler les propriétés d’État, telles que IsSelected ou IsEnabled . Par exemple, lorsqu’un Button est désactivé, par défaut, un déclencheur de style de thème ( IsEnabled a false la valeur) définit la Foreground valeur de sorte que le Button s’affiche en grisé. Si vous avez défini une Foreground valeur locale, la valeur de propriété locale de précédence la plus élevée remplace la valeur du style de thème Foreground , même lorsque Button est désactivé. Quand vous définissez des valeurs de propriété qui remplacent les comportements de déclencheur au niveau du thème pour un contrôle, veillez à ne pas interférer incorrectement avec l’expérience utilisateur prévue pour ce contrôle.

ClearValue

La ClearValue méthode efface toute valeur appliquée localement d’une propriété de dépendance pour un élément. Toutefois, l’appel ClearValue de ne garantit pas que la valeur par défaut établie dans les métadonnées lors de l’inscription de la propriété est la nouvelle valeur effective. Tous les autres participants de la liste de priorités sont toujours actifs, et seule la valeur définie localement est supprimée. Par exemple, si vous appelez ClearValue sur une propriété qui a un style de thème, la valeur de style de thème sera appliquée comme nouvelle valeur, plutôt que par défaut basée sur les métadonnées. Si vous souhaitez définir une valeur de propriété sur la valeur par défaut des métadonnées inscrites, récupérez la valeur de métadonnées par défaut en interrogeant les métadonnées de propriété de dépendance, puis définissez localement la valeur de la propriété avec un appel à SetValue .

Voir aussi