Priorité de la valeur de propriété de dépendance

Cette rubrique explique comment les fonctionnements du système de propriétés Windows Presentation Foundation (WPF) peuvent affecter la valeur d’une propriété de dépendance et décrit la priorité par laquelle les aspects du système de propriétés s’appliquent à la valeur effective d’une propriété.

Prérequis

Cette rubrique part du principe que vous comprenez les propriétés de dépendance du point de vue d’un consommateur de propriétés de dépendance existantes sur les classes WPF et que vous avez lu la vue d’ensemble des propriétés de dépendance. Pour suivre les exemples de cette rubrique, vous devez également comprendre XAML et savoir comment écrire des applications WPF.

Le système de propriétés WPF

Le système de propriétés WPF offre un moyen puissant de déterminer la valeur des propriétés de dépendance par divers facteurs, ce qui permet aux fonctionnalités telles que la validation des propriétés en temps réel, la liaison tardive et la notification des propriétés associées des modifications apportées aux valeurs pour d’autres propriétés. L’ordre et la logique exacts utilisés pour déterminer les valeurs des propriétés de dépendance sont relativement complexes. Connaître cet ordre vous aidera à éviter les paramètres de propriétés inutiles, et peut également éliminer toute confusion quant aux raisons pour lesquelles une tentative visant à influencer ou à anticiper une valeur de propriété de dépendance n’a pas généré la valeur attendue.

Les propriétés de dépendance peuvent être « définies » à plusieurs emplacements

Voici un exemple XAML où la même propriété (Background) a trois opérations « set » différentes qui peuvent influencer la 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>

Ici, quelle sera la couleur appliquée selon vous ? Le rouge, le vert ou le bleu ?

À l’exception des valeurs animées et du forçage, les jeux de propriétés locaux sont définis à la priorité la plus élevée. Si vous définissez une valeur localement, vous pouvez vous attendre à ce qu’elle soit honorée, même au-delà des styles ou des modèles de contrôle. Ici, dans l’exemple, Background est défini sur Rouge localement. Par conséquent, le style défini dans cette étendue, même s’il s’agit d’un style implicite qui s’appliquerait autrement à tous les éléments de ce type dans cette étendue, n’est pas la priorité la plus élevée pour donner à la Background propriété sa valeur. Si vous supprimiez la valeur locale Red de cette instance de Button, le style aurait la priorité et le bouton obtiendrait la valeur Background à partir du style. Dans le style, les déclencheurs sont prioritaires. Le bouton sera donc bleu si la souris est sur lui, et vert dans le cas contraire.

Liste de priorité de définition de propriété de dépendance

Voici l’ordre définitif suivi par le système de propriétés lors de l’affectation des valeurs d’exécution des propriétés de dépendance. La priorité la plus élevée est répertoriée en premier. Cette liste étend certaines des généralisations présentées dans la Vue d’ensemble des propriétés de dépendance.

  1. Forçage du système de propriétés. Pour plus d’informations sur le forçage, consultez Forçage, animation et valeur de base plus loin dans cette rubrique.

  2. Animations actives ou animations avec un comportement de blocage. Pour avoir un effet pratique, une animation d’une propriété doit pouvoir être prioritaire par rapport à la valeur de base (non animée), même si cette valeur a été définie localement. Pour plus d’informations, consultez Forçage, animation et valeur de base plus loin dans cette rubrique.

  3. Valeur locale. Une valeur locale peut être définie par le biais de la commodité de la propriété « wrapper », qui équivaut également à définir en tant qu’attribut ou élément de propriété en XAML, ou par un appel à l’API à l’aide SetValue 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, celles-ci se comportent chacune en termes de priorité comme si une valeur directe avait été définie.

  4. Propriétés de modèle TemplatedParent. Un élément a une TemplatedParent valeur si elle a été créée dans le cadre d’un modèle (a ControlTemplate ou DataTemplate). Pour plus d’informations sur les cas où ceci est applicable, consultez TemplatedParent plus loin dans cette rubrique. Dans le modèle, la priorité suivante s’applique :

    1. Déclencheurs à partir du TemplatedParent modèle.

    2. Jeux de propriétés (généralement via des attributs XAML) dans le TemplatedParent modèle.

  5. Style implicite. S’applique uniquement à la propriété Style. La propriété Style est renseignée par toute ressource de style avec une clé qui correspond au type de cet élément. Cette ressource de style doit exister dans la page ou dans l’application ; la recherche d’une ressource de style implicite ne se poursuit pas dans les thèmes.

  6. Déclencheurs de styles. Déclencheurs dans les styles de page ou d’application (ces styles peuvent être explicites ou implicites, mais pas issus des styles par défaut, qui ont une priorité inférieure).

  7. Déclencheurs de modèles. Tout déclencheur d’un modèle dans un style, ou un modèle appliqué directement.

  8. Style Setters. Valeurs d’un style intérieur à partir d’une Setter page ou d’une application.

  9. Style (de thème) par défaut. Pour plus d’informations sur les cas où ceci est applicable, et sur la relation entre les styles de thème et les modèles dans les styles de thème, consultez Style (de thème) par défaut plus loin dans cette rubrique. Dans un style par défaut, l’ordre de priorité suivant s’applique :

    1. Déclencheurs actifs dans le style de thème.

    2. Méthodes setter dans le style de thème.

  10. Héritage. Quelques propriétés de dépendance héritent de leurs valeurs d’élément parent à éléments enfants, et n’ont donc pas besoin d’être définies spécifiquement sur chaque élément dans une application. Pour plus d’informations, consultez Héritage de la valeur de propriété.

  11. Valeur par défaut issue des métadonnées de propriété de dépendance. Toute propriété de dépendance peut avoir une valeur par défaut établie par l’inscription de cette propriété particulière dans le système de propriétés. En outre, les classes dérivées qui héritent d’une propriété de dépendance peuvent substituer ces métadonnées (notamment la valeur par défaut) pour chaque type. Pour plus d’informations, consultez Métadonnées de propriété de dépendance. Étant donné que l’héritage est vérifié avant la valeur par défaut, pour une propriété héritée une valeur par défaut d’élément parent est prioritaire par rapport à un élément enfant. Par conséquent, si une propriété pouvant être héritée n’est définie nulle part, la valeur par défaut spécifiée pour la racine ou le parent est utilisée au lieu de la valeur par défaut de l’élément enfant.

TemplatedParent

TemplatedParent en tant qu’élément de priorité ne s’applique pas à une propriété d’un élément que vous déclarez directement dans le balisage d’application standard. Le concept de TemplatedParent existe uniquement pour les éléments enfants dans une arborescence visuelle qui sont créés par l’intermédiaire de l’application du modèle. Lorsque le système de propriétés recherche le TemplatedParent modèle pour une valeur, il recherche le modèle qui a créé cet élément. Les valeurs de propriété du TemplatedParent modèle agissent généralement comme si elles étaient définies comme une valeur locale sur l’élément enfant, mais cette priorité moindre par rapport à la valeur locale existe, car les modèles sont potentiellement partagés. Pour plus d’informations, consultez TemplatedParent.

Propriété Style

L’ordre de recherche décrit précédemment s’applique à toutes les propriétés de dépendance possibles, sauf une : la Style propriété. La Style propriété est unique en ce qu’elle ne peut pas elle-même être mise en forme, de sorte que les éléments de précédence 5 à 8 ne s’appliquent pas. En outre, l’animation ou la coécisation Style n’est pas recommandée (et l’animation Style nécessite une classe d’animation personnalisée). Cela laisse trois façons de définir la Style propriété :

  • Style explicite. La Style propriété est définie directement. Dans la plupart des scénarios, le style n’est pas défini inline. Il est plutôt référencé en tant que ressource, par clé explicite. Dans ce cas, la propriété Style proprement dite se comporte comme s’il s’agissait d’une valeur locale (élément de priorité 3).

  • Style implicite. La Style propriété n’est pas définie directement. Toutefois, il Style existe à un certain niveau dans la séquence de recherche de ressources (page, application) et est clé à l’aide d’une clé de ressource qui correspond au type auquel le style doit être appliqué. Dans ce cas, la Style propriété elle-même agit par une priorité identifiée dans la séquence comme élément 5. Cette condition peut être détectée à l’aide DependencyPropertyHelper de la Style propriété et à la recherche ImplicitStyleReference dans les résultats.

  • Style par défaut, également appelé style de thème. La Style propriété n’est pas définie directement. En fait, elle est lue comme null étant jusqu’au moment de l’exécution. Dans ce cas, le style provient de l’évaluation du thème d’exécution qui fait partie du moteur de présentation WPF.

Pour les styles implicites non dans les thèmes, le type doit correspondre exactement - une MyButtonButtonclasse dérivée ne utilisera pas implicitement un style pour Button.

Style (de thème) par défaut

Chaque contrôle fourni avec WPF a un style par défaut. Ce style par défaut peut varier en fonction du thème. C’est pourquoi on le nomme parfois « style de thème ».

Les informations les plus importantes trouvées dans un style par défaut pour un contrôle sont son modèle de contrôle, qui existe dans le style de thème en tant que setter pour sa Template propriété. S’il n’y avait aucun modèle issu des styles par défaut, un contrôle sans modèle personnalisé dans le cadre d’un style personnalisé n’aurait aucune apparence visuelle. Le modèle du style par défaut donne une structure de base à l’apparence visuelle de chaque contrôle, et définit également les connexions entre les propriétés définies dans l’arborescence visuelle 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 complètement le modèle. Par exemple, considérez l’apparence visuelle par défaut d’un Thumb contrôle, qui est un composant d’un ScrollBar.

A Thumb certaines propriétés personnalisables. Le modèle par défaut d’une Thumb structure de base /arborescence visuelle avec plusieurs composants imbriqués Border pour créer une apparence de biseau. Si une propriété qui fait partie du modèle est destinée à être exposée pour la personnalisation par la Thumb classe, cette propriété doit être exposée par un TemplateBinding, dans le modèle. Dans le cas de , différentes propriétés de Thumbces bordures partagent une liaison de modèle à des propriétés telles que Background ou BorderThickness. En revanche, certaines autres propriétés ou dispositions visuelles sont codées en dur dans le modèle de contrôle ou sont liées à des valeurs qui proviennent directement du thème, et ne peuvent pas être changées à moins de remplacer le modèle entier. 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 une liaison de modèle, elle ne peut pas être ajustée par des styles car il n’existe aucun moyen simple de la cibler. Mais cette propriété peut toujours être influencée par l’héritage de valeur de propriété dans le modèle appliqué, ou par la valeur par défaut.

Les styles de thème utilisent un type comme clé dans leurs définitions. Toutefois, lorsque les thèmes sont appliqués à une instance d’élément donnée, la recherche de thèmes pour ce type est effectuée en case activée la DefaultStyleKey propriété sur un contrôle. Ce comportement est à contraster avec l’utilisation du littéral Type (par les styles implicites). La valeur de DefaultStyleKey cette propriété hériterait de classes dérivées même si l’implémenteur ne l’a pas modifié (la façon prévue de modifier la propriété n’est pas de la remplacer au niveau de la propriété, mais de modifier sa valeur par défaut dans les métadonnées de propriété). Cette indirection permet aux classes de base de définir les styles de thème pour les éléments dérivés qui ne disposent pas de style (ou, plus important encore, qui n’ont pas de modèle dans ce style et n’auraient donc aucune apparence visuelle par défaut). Par conséquent, vous pouvez dériver MyButton du Button modèle par défaut.Button Si vous étiez l’auteur du contrôle et que vous vouliez un comportement différent, vous pouvez remplacer les métadonnées de propriété de dépendance pour DefaultStyleKey retourner une clé différente, puis définir les styles de MyButton thème pertinents, y compris le modèle pour MyButton lequel vous devez empaqueter avec votre MyButtonMyButton contrôle. Pour plus d’informations sur les thèmes, les styles et la création de contrôles, consultez Vue d’ensemble de la création de contrôles.

Références de ressources dynamiques et liaison

Les opérations de liaison et les références de ressources dynamiques respectent la priorité de l’emplacement auquel elles sont définies. Par exemple, une ressource dynamique appliquée à une valeur locale agit conformément à l’élément de priorité 3, une liaison pour une méthode setter de propriété dans un style de thème s’applique à l’élément de priorité 9, et ainsi de suite. Étant donné que les références de ressources dynamiques et la liaison doivent pouvoir obtenir des valeurs à partir de l’état d’exécution de l’application, cela implique que le processus de détermination de la priorité de valeur de propriété pour une propriété donnée s’étend également au moment de l’exécution.

Les références de ressources dynamiques ne font pas à proprement parler partie du système de propriétés, mais elles ont leur propre ordre de recherche qui interagit avec la séquence indiquée ci-dessus. Cette priorité est documentée plus en détail dans les Ressources XAML. Il s’agit en gros de la priorité suivante : élément à racine de la page, application, thème, système.

Les ressources dynamiques et les liaisons ont la priorité de l’emplacement où elles ont été définies, mais la valeur est différée. L’une des conséquences de cela est que si vous affectez une valeur locale à une ressource dynamique ou une liaison, tout changement apporté à la valeur locale remplace entièrement la ressource dynamique ou la liaison. Même si vous appelez la ClearValue méthode pour effacer la valeur définie localement, la ressource dynamique ou la liaison ne sera pas restaurée. En fait, si vous appelez ClearValue sur une propriété qui a une ressource dynamique ou une liaison en place (sans valeur locale littérale), elles sont également effacées par l’appel ClearValue .

SetCurrentValue

La SetCurrentValue méthode est une autre façon de définir une propriété, mais elle n’est pas dans l’ordre de priorité. Au lieu de cela, SetCurrentValue vous pouvez modifier la valeur d’une propriété sans remplacer la source d’une valeur précédente. Vous pouvez utiliser SetCurrentValue chaque fois que vous souhaitez définir une valeur sans donner à cette valeur la priorité d’une valeur locale. Par exemple, si une propriété est définie par un déclencheur, puis affectée à une autre valeur via SetCurrentValue, le système de propriétés respecte toujours le déclencheur et la propriété change si l’action du déclencheur se produit. SetCurrentValue vous permet de modifier la valeur de la propriété sans lui donner une source avec une priorité plus élevée. De même, vous pouvez utiliser SetCurrentValue pour modifier la valeur d’une propriété sans remplacer une liaison.

Forçage, animations et valeur de base

La contrainte et l’animation agissent tous deux sur une valeur appelée « valeur de base » dans ce Kit de développement logiciel (SDK). La valeur de base est donc toute valeur déterminée par l’intermédiaire d’une évaluation vers le haut parmi les éléments jusqu’à ce que l’élément 2 soit atteint.

Pour une animation, la valeur de base peut avoir un effet 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 terminé. Pour voir cela en pratique, exécutez l’Exemple de valeurs cibles d’animation From, To et By. Essayez de définir les valeurs locales de la hauteur du rectangle dans l’exemple, telles que la valeur locale initiale soit différente de toute valeur « From » dans l’animation. Vous noterez que les animations démarrent immédiatement en utilisant les valeurs « From », et qu’elles remplacent la valeur de base une fois qu’elles ont commencé. L’animation peut spécifier de revenir à la valeur trouvée avant l’animation une fois l’animation terminée en spécifiant l’arrêt FillBehavior. Par la suite, la priorité normale est utilisée pour déterminer la valeur de base.

Plusieurs animations peuvent être appliquées à une même 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 créeront peut-être une valeur composite à partir de leurs valeurs, plutôt que d’appliquer simplement l’animation à partir de la priorité la plus élevée. Cela dépend de la manière exacte dont les animations sont définies et du type de la valeur qui est animée. Pour plus d’informations sur l’animation de propriétés, consultez Vue d’ensemble de l’animation.

Le forçage s’applique au niveau le plus élevé. Même une animation en cours d’exécution est sujette au forçage de valeur. Certaines propriétés de dépendance existantes dans WPF ont une contrainte intégrée. Pour une propriété de dépendance personnalisée, vous définissez le comportement de contrainte d’une propriété de dépendance personnalisée en écrivant un CoerceValueCallback rappel et en passant le rappel dans le cadre des métadonnées lorsque vous créez la propriété. Vous pouvez également substituer le comportement de forçage d’une propriété existante en substituant les métadonnées de cette propriété dans une classe dérivée. Le forçage interagit avec la valeur de base de telle façon que les contraintes du forçage soient appliquées telles qu’elles existent à ce moment précis, mais la valeur de base est quand même conservée. Par conséquent, si des contraintes du forçage sont par la suite levées, le forçage retourne la valeur la plus proche possible de cette valeur de base, et l’influence du forçage sur une propriété peut cesser 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 les comportements des déclencheurs dans le cadre de leur style par défaut dans les thèmes. La définition de propriétés locales sur des contrôles peut empêcher les déclencheurs de répondre à des événements pilotés par l’utilisateur visuellement ou par comportement. L’utilisation la plus courante d’un déclencheur de propriété est destinée aux propriétés de contrôle ou d’état telles que IsSelected. Par exemple, par défaut, lorsqu’un Button déclencheur est désactivé (déclencheur à IsEnabled l’état ) false, la Foreground valeur dans le style de thème est ce qui entraîne l’affichage du contrôle « grisé ». Toutefois, si vous avez défini une valeur locale Foreground , cette couleur de gris-out normale sera surchaînée en priorité par votre jeu de propriétés local, même dans ce scénario déclenché par la propriété. Soyez prudent quand vous définissez des valeurs pour des propriétés qui ont des comportements de déclenchement au niveau du thème, et vérifiez que vous n’interférez pas indûment avec l’expérience utilisateur prévue pour ce contrôle.

ClearValue et priorité de valeur

La ClearValue méthode fournit un moyen expedient d’effacer toute valeur appliquée localement à partir d’une propriété de dépendance définie sur un élément. Toutefois, l’appel ClearValue n’est pas une garantie que la valeur par défaut définie dans les métadonnées pendant l’inscription des propriétés est la nouvelle valeur effective. Tous les autres participants à la séquence de priorité de valeur sont toujours actifs. Seule la valeur définie localement a été supprimée de la séquence de priorité. Par exemple, si vous appelez ClearValue une propriété où cette propriété est également définie par un style de thème, la valeur du thème est appliquée comme nouvelle valeur plutôt que la valeur par défaut basée sur les métadonnées. Si vous souhaitez retirer tous les participants de la valeur de propriété du processus et définir la valeur sur la valeur par défaut des métadonnées inscrites, vous pouvez obtenir cette valeur par défaut définitivement en interrogeant les métadonnées de propriété de dépendance, puis vous pouvez utiliser la valeur par défaut pour définir localement la propriété avec un appel à SetValue.

Voir aussi