Priorité des valeurs de propriété de dépendance (WPF .NET)

Les fonctionnements du système de propriétés Windows Presentation Foundation (WPF) affectent la valeur d’une propriété de dépendance. Cet article explique comment la priorité des différentes entrées basées sur des propriétés dans le système de propriétés WPF détermine la valeur effective d’une propriété de dépendance.

Important

La documentation du Guide du bureau pour .NET 7 et .NET 6 est en cours de construction.

Prérequis

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

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 des propriétés 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 de propriété de dépendance soient complexes, l’apprentissage peut vous aider à éviter les paramètres de propriété inutiles et à déterminer également 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 emplacements

L’exemple XAML suivant montre comment trois opérations « set » différentes sur la propriété du Background 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 l’étendue du bouton tente de définir la Background propriété Bluesur . Et, lorsque la souris est sur le bouton, le déclencheur dans le style implicite tente de définir la Background propriété Yellowsur . À l’exception de la contrainte et de l’animation, une valeur de propriété définie localement a la priorité la plus élevée, de sorte que le bouton sera rouge, même sur le plan de la souris. Toutefois, si vous supprimez la valeur définie localement du bouton, elle obtient sa Background valeur à partir du style. Dans un style, les déclencheurs sont prioritaires, de sorte que le bouton sera jaune sur leover de la souris et bleu sinon. L’exemple remplace la valeur par défaut du bouton, car le modèle par défaut ControlTemplate a une valeur de souris Background codée en dur.

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

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

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

  2. Animations actives ou animations avec un comportement de blocage. 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 Contraintes 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’API à l’aide SetValue 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 définie directement.

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

    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 n’importe quelle 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 Thèmes.

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

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

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

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

    1. Déclencheurs actifs.

    2. Setters.

  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 peut-être pas nécessaire de définir des valeurs de propriété sur chaque élément dans l’application. Pour plus d’informations, consultez Héritage des valeurs de propriété.

  11. Valeur par défaut des métadonnées de propriété de dépendance Une propriété de dépendance peut avoir une valeur par défaut définie pendant 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 remplacer les métadonnées de propriété de dépendance (y compris la valeur par défaut) par type. Pour plus d’informations, consultez les 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 sur la valeur par défaut d’un élément enfant. Par conséquent, si aucune propriété héritée n’est définie, la valeur par défaut de la racine ou du parent est utilisée au lieu 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 déclarés directement dans le balisage d’application standard. Le TemplatedParent concept existe uniquement pour les éléments enfants d’une arborescence visuelle qui entrent en existence via l’application d’un modèle. Lorsque le système de propriétés recherche le modèle spécifié par les TemplatedParent 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 si elles étaient définies localement sur l’élément, mais avec une priorité moindre que les valeurs locales réelles, car les modèles sont potentiellement partagés. Pour plus d’informations, consultez TemplatedParent.

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 en ce qu’elle ne peut pas être mise en forme elle-même. La co-animation ou l’animation de la Style propriété n’est pas recommandée (et l’animation de la Style propriété nécessite une classe d’animation personnalisée). Par conséquent, tous les éléments de précédence ne s’appliquent pas. Il existe seulement 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 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 de précédence. Dans la plupart des scénarios, les styles explicites ne sont pas définis inline et sont plutôt référencés explicitement 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 niveau dans la page ou 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 s’il MyButton est dérivé de Button. La Style valeur de propriété a la même priorité que l’élément 5 dans la liste de précédence. Une valeur de style implicite peut être détectée en appelant la DependencyPropertyHelper.GetValueSource méthode, en passant la Style propriété et en case activée ing pour ImplicitStyleReference 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 propriété a la même priorité que l’élément 9 dans la liste de précédence.

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, c’est pourquoi le style par défaut est parfois appelé style de thème.

Il ControlTemplate s’agit d’un élément important dans le style par défaut d’un contrôle. ControlTemplate est une valeur setter pour la propriété du Template style. 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, il définit également les connexions entre les propriétés de 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 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 une arborescence visuelle, avec plusieurs composants imbriqués Border pour créer une apparence biseautée. Dans le modèle, les propriétés destinées à être personnalisables par la Thumb classe sont exposées via TemplateBinding. Le modèle par défaut du Thumb contrôle a différentes 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 qui sont liées à des valeurs provenant directement du thème, vous ne pouvez modifier ces valeurs qu’en remplaçant l’intégralité du modèle. En règle générale, si une propriété provient d’un parent modèle et n’est pas exposée par un TemplateBinding, la valeur de la propriété ne peut pas être modifiée par les styles, car il n’existe aucun moyen pratique de le cibler. Toutefois, cette propriété peut toujours être influencée par l’héritage de valeur 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 runtime correspond au TargetType 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 l’objet est héritée par des classes dérivées, de sorte que les éléments dérivés qui n’ont pas de style associé n’obtiennent pas d’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 remplacer la valeur par défaut des métadonnées de propriété de DefaultStyleKey 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 activé 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’ensemble de 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 auquel 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 de précédence. Dans un autre exemple, une liaison de ressource dynamique appliquée à un jeu de propriétés dans un style par défaut a la même priorité que l’élément 9 dans la liste de précédence. Étant donné que les références et la liaison de ressources dynamiques doivent obtenir des valeurs à partir de l’état d’exécution de l’application, le processus de détermination de la priorité des valeurs de propriété pour toute propriété donnée s’étend au runtime.

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

Bien que les références et liaisons de ressources dynamiques aient la priorité de l’emplacement auquel elles sont définies, la valeur est différée. L’une des conséquences est que si vous définissez une ressource dynamique ou une liaison à 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 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 (sans valeur locale littérale), la ressource dynamique ou la liaison sera effacée.

SetCurrentValue

La SetCurrentValue méthode est une autre façon de définir une propriété, mais elle n’est pas dans la liste de précédences. 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 en utilisant SetCurrentValue, l’action de déclencheur suivante rétablit la propriété sur 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 précédence 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 tous deux sur une valeur de base. La valeur de base est la valeur de propriété de dépendance avec la priorité la plus élevée, déterminée par l’évaluation vers le haut dans la liste de précédence jusqu’à ce que l’élément 2 soit atteint.

Si une animation ne spécifie pas à la fois From et To les valeurs de propriété pour certains comportements, ou si l’animation revient délibérément à la valeur de base une fois 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 n’importe quelle From valeur. Les exemples d’animations commencent immédiatement en utilisant la From valeur au lieu de la valeur de base. En spécifiant Stop comme , à la FillBehaviorfin d’une animation, réinitialise une valeur de propriété à sa valeur de base. La précédence 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 propriété unique, 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 compositer les valeurs d’animation, selon la façon dont les animations ont été définies et le type de valeurs animées. Pour plus d’informations, consultez Vue d’ensemble de l’animation.

Le forçage se trouve en haut de la liste de précédences. Même une animation en cours d’exécution est soumise à la contrainte de valeur. Certaines propriétés de dépendance existantes dans WPF ont un forçage intégré. Pour les propriétés de dépendance personnalisées, vous pouvez définir un comportement de contrainte en écrivant un CoerceValueCallback passage dans le cadre des métadonnées lorsque vous créez une propriété. Vous pouvez également remplacer le comportement de contrainte des propriétés existantes en remplaçant 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 sorte que les contraintes sur la contrainte soient appliquées au moment où elles existent, mais que la valeur de base est toujours conservée. Par conséquent, si les contraintes dans la contrainte sont ultérieurement levées, le forçage retourne la valeur la plus proche possible à la valeur de base, et potentiellement l’influence de contrainte sur une propriété cessera dès que toutes les contraintes sont levées. Pour plus d’informations sur le comportement de contrainte, consultez rappels et validation des propriétés de dépendance.

Comportements de déclencheur

Les contrôles définissent souvent des comportements de déclencheur dans le cadre de leur style par défaut. La définition des propriétés locales sur les contrôles peut potentiellement entrer en conflit avec ces déclencheurs, ce qui empêche les déclencheurs de répondre (visuellement ou comportementalement) aux événements pilotés par l’utilisateur. Un usage courant d’un déclencheur de propriété consiste à contrôler les propriétés d’état, telles que IsSelected ou IsEnabled. Par exemple, par défaut, lorsqu’un Button paramètre est désactivé, un déclencheur de style de thème (IsEnabled est false) définit la Foreground valeur pour rendre l’affichage Button grisé. Si vous avez défini une valeur locale Foreground , la valeur de propriété locale de priorité la plus élevée remplace la valeur du style Foreground de thème, même lorsque la Button valeur est désactivée. Lorsque 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 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 ne garantit pas que la valeur par défaut établie dans les métadonnées pendant l’inscription des propriétés est la nouvelle valeur effective. Tous les autres participants de la liste de précédence sont toujours actifs, et seule la valeur définie localement est supprimée. Par exemple, si vous appelez ClearValue une propriété qui a un style de thème, la valeur de style de 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 définir une valeur de propriété sur la valeur par défaut des métadonnées inscrites, obtenez la valeur de métadonnées par défaut en interrogeant les métadonnées de propriété de dépendance et définissez localement la valeur de la propriété avec un appel à SetValue.

Voir aussi