Vue d’ensemble des propriétés de dépendance (WPF .NET)

WPF (Windows Presentation Foundation) fournit un ensemble de services qui permettent d’étendre la fonctionnalité de la propriété d’un type. Collectivement, ces services sont appelés système de propriétés WPF. Une propriété soutenue par le système de propriétés WPF est appelée propriété de dépendance. Cette vue d’ensemble décrit le système de propriétés WPF et les fonctionnalités d’une propriété de dépendance, notamment l’utilisation des propriétés de dépendance existantes en XAML et dans le code. Elle introduit également des aspects spécialisés des propriétés de dépendance, tels que les métadonnées de propriétés de dépendance et comment créer votre propre propriété de dépendance dans une classe personnalisée.

Prérequis

Cet article suppose une connaissance de base du système de type .NET et de la programmation orientée objet. Pour suivre les exemples de cet article, il permet de comprendre XAML et de savoir comment écrire des applications WPF. Pour plus d’informations, consultez Tutoriel : Créer une application WPF avec .NET.

Propriétés de dépendance et propriétés CLR

Les propriétés WPF sont généralement exposées en tant que propriétés .NET standard. Vous pouvez interagir avec ces propriétés à un niveau de base et ne jamais savoir qu’elles sont implémentées en tant que propriété de dépendance. Toutefois, la connaissance de certaines ou de toutes les fonctionnalités du système de propriétés WPF vous aidera à tirer parti de ces fonctionnalités.

L’objectif des propriétés de dépendance est de fournir un moyen de calculer la valeur d’une propriété en fonction de la valeur d’autres entrées, telles que :

  • Propriétés système, telles que les thèmes et les préférences utilisateur.
  • Mécanismes de détermination des propriétés juste-à-temps, tels que la liaison de données et les animations/storyboards.
  • Modèles à plusieurs utilisations, tels que les ressources et les styles.
  • Valeurs connues par le biais de relations parent-enfant avec d’autres éléments de l’arborescence d’éléments.

En outre, une propriété de dépendance peut fournir :

  • Validation autonome.
  • Valeurs par défaut.
  • Rappels qui surveillent les modifications apportées à d’autres propriétés.
  • Système qui peut forcer les valeurs de propriété en fonction des informations d’exécution.

Les classes dérivées peuvent modifier certaines caractéristiques d’une propriété existante en substituant les métadonnées d’une propriété de dépendance, plutôt que de remplacer l’implémentation réelle des propriétés existantes ou la création de nouvelles propriétés.

Dans la référence du Kit de développement logiciel (SDK), vous pouvez identifier une propriété de dépendance en présence d’une section Informations sur la propriété de dépendance dans la page de référence managée de cette propriété. La section Informations sur la propriété de dépendance inclut un lien vers le DependencyProperty champ d’identificateur de cette propriété de dépendance. Il inclut également la liste des options de métadonnées pour cette propriété, les informations de remplacement par classe et d’autres détails.

Les propriétés CLR reposent sur les propriétés de dépendance

Les propriétés de dépendance et le système de propriétés WPF étendent les fonctionnalités de propriété en fournissant un type qui sauvegarde une propriété, comme alternative au modèle standard de sauvegarde d’une propriété avec un champ privé. Le nom de ce type est DependencyProperty. L’autre type important qui définit le système de propriétés WPF est DependencyObject, qui définit la classe de base qui peut inscrire et posséder une propriété de dépendance.

Voici une terminologie couramment utilisée :

  • Propriété de dépendance, qui est une propriété sauvegardée par un DependencyProperty.

  • Identificateur de propriété de dépendance, qui est une DependencyProperty instance obtenue en tant que valeur de retour lors de l’inscription d’une propriété de dépendance, puis stocké en tant que membre statique d’une classe. La plupart des API qui interagissent avec le système de propriétés WPF utilisent l’identificateur de propriété de dépendance comme paramètre.

  • CLR « wrapper », qui est les implémentations et set les get implémentations de la propriété. Ces implémentations incorporent l’identificateur de propriété de dépendance en l’utilisant dans les appels et SetValue les GetValue appels. De cette façon, le système de propriétés WPF fournit le stockage de la propriété.

L’exemple suivant définit la IsSpinning propriété de dépendance pour afficher la relation de l’identificateur DependencyProperty à la propriété qu’elle sauvegarde.

public static readonly DependencyProperty IsSpinningProperty = DependencyProperty.Register(
    "IsSpinning", typeof(bool),
    typeof(MainWindow)
    );

public bool IsSpinning
{
    get => (bool)GetValue(IsSpinningProperty);
    set => SetValue(IsSpinningProperty, value);
}
Public Shared ReadOnly IsSpinningProperty As DependencyProperty =
    DependencyProperty.Register("IsSpinning", GetType(Boolean), GetType(MainWindow))

Public Property IsSpinning As Boolean
    Get
        Return GetValue(IsSpinningProperty)
    End Get
    Set(value As Boolean)
        SetValue(IsSpinningProperty, value)
    End Set
End Property

La convention de nommage de la propriété et de son champ DependencyProperty de stockage est importante. Le nom du champ est toujours le nom de la propriété, auquel est ajouté le suffixe Property. Pour plus d’informations sur cette convention et les raisons de celle-ci, consultez les propriétés des dépendances personnalisées.

Définition de valeurs de propriété

Vous pouvez définir des propriétés dans le code ou en XAML.

Définition de valeurs de propriété en XAML

L’exemple XAML suivant définit la couleur d’arrière-plan d’un bouton sur rouge. La valeur de chaîne de l’attribut XAML est convertie en type par l’analyseur XAML WPF en type WPF. Dans le code généré, le type WPF est un Color, par le biais d’un SolidColorBrush.

<Button Content="I am red" Background="Red"/>

XAML prend en charge plusieurs formulaires de syntaxe pour définir des propriétés. La syntaxe à utiliser pour une propriété particulière dépend du type valeur utilisé par une propriété et d’autres facteurs, tels que la présence d’un convertisseur de type. Pour plus d’informations sur la syntaxe XAML pour définir des propriétés, consultez XAML dans WPF et syntaxe XAML en détail.

L’exemple XAML suivant montre un autre arrière-plan de bouton qui utilise la syntaxe d’élément de propriété au lieu de la syntaxe d’attribut. Au lieu de définir une couleur unie simple, le code XAML définit la propriété de bouton Background sur une image. Un élément représente cette image et un attribut de l’élément imbriqué spécifie la source de l’image.

<Button Content="I have an image background">
    <Button.Background>
        <ImageBrush ImageSource="stripes.jpg"/>
    </Button.Background>
</Button>

Définition de propriétés dans le code

La définition des valeurs de propriété de dépendance dans le code n’est généralement qu’un appel à l’implémentation set exposée par le CLR « wrapper » :

Button myButton = new();
myButton.Width = 200.0;
Dim myButton As New Button With {
    .Width = 200.0
}

L’obtention d’une valeur de propriété est essentiellement un appel à l’implémentation get « wrapper » :

double whatWidth = myButton.Width;
Dim whatWidth As Double = myButton.Width

Vous pouvez également appeler les API GetValue système de propriétés et SetValue directement. L’appel direct des API est approprié pour certains scénarios, mais généralement pas lorsque vous utilisez des propriétés existantes. En règle générale, les wrappers sont plus pratiques et offrent une meilleure exposition de la propriété pour les outils de développement.

Vous pouvez aussi définir les propriétés en XAML et y accéder ultérieurement dans le code, par l’intermédiaire du code-behind. Pour plus d’informations, consultez Code-behind et XAML dans WPF.

Fonctionnalité de propriété fournie par une propriété de dépendance

Contrairement à une propriété soutenue par un champ, une propriété de dépendance étend les fonctionnalités d’une propriété. Souvent, la fonctionnalité ajoutée représente ou prend en charge l’une des fonctionnalités suivantes :

Ressources

Vous pouvez définir une valeur de propriété de dépendance en référençant une ressource. Les ressources sont généralement spécifiées comme valeur Resources de propriété d’un élément racine de page ou de l’application, car ces emplacements offrent un accès pratique à la ressource. Dans cet exemple, nous définissons une SolidColorBrush ressource :

<StackPanel.Resources>
    <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
</StackPanel.Resources>

Maintenant que la ressource est définie, nous pouvons référencer la ressource pour fournir une valeur pour la Background propriété :

<Button Background="{DynamicResource MyBrush}" Content="I am gold" />

En XAML WPF, vous pouvez utiliser une référence de ressource statique ou dynamique. Cette ressource particulière est référencée en tant que DynamicResource. Une référence de ressource dynamique ne peut être utilisée que pour définir une propriété de dépendance. Il s’agit donc spécifiquement de l’utilisation de référence des ressources dynamiques activée par le système de propriétés WPF. Pour plus d’informations, consultez les ressources XAML.

Remarque

Les ressources sont traitées comme une valeur locale, ce qui signifie que si vous définissez une autre valeur locale, vous éliminerez la référence de ressource. Pour plus d’informations, consultez Priorité des valeurs de propriété de dépendance.

Liaison de données

Une propriété de dépendance peut référencer une valeur par l’intermédiaire d’une liaison de données. La liaison de données fonctionne via une syntaxe d’extension de balisage spécifique en XAML, ou via l’objet Binding dans du code. Avec la liaison de données, la détermination de la valeur de propriété finale est différée jusqu’au moment de l’exécution, à laquelle la valeur est obtenue à partir d’une source de données.

L’exemple suivant définit la Content propriété pour un Button, à l’aide d’une liaison déclarée en XAML. La liaison utilise un contexte de données hérité et une source de données XmlDataProvider (non illustrée). La liaison elle-même spécifie la propriété source dans la source de données par XPath.

<Button Content="{Binding Source={StaticResource TestData}, XPath=test[1]/@text}"/>

Remarque

Les liaisons sont traitées comme une valeur locale, ce qui signifie que si vous définissez une autre valeur locale, vous éliminerez la liaison. Pour plus d’informations, consultez Priorité des valeurs de propriété de dépendance.

Les propriétés de dépendance, ou la DependencyObject classe, ne prennent pas en charge INotifyPropertyChanged en mode natif la notification des modifications apportées à DependencyObject la valeur de propriété source pour les opérations de liaison de données. Pour plus d’informations sur la création de propriétés à utiliser dans la liaison de données qui peuvent signaler des modifications à une cible de liaison de données, consultez vue d’ensemble de la liaison de données.

Styles

Les styles et les modèles sont des raisons intéressantes d’utiliser les propriétés de dépendance. Les styles sont particulièrement utiles pour définir des propriétés qui définissent l’interface utilisateur de l’application. Ils sont généralement définis en tant que ressources en XAML. Les styles interagissent avec le système de propriétés, car ils contiennent généralement des « setters » pour des propriétés particulières et des « déclencheurs » qui modifient une valeur de propriété en fonction de la valeur d’exécution d’une autre propriété.

L’exemple suivant crée un style simple, qui serait défini à l’intérieur d’un Resources dictionnaire (non affiché). Ensuite, ce style est appliqué directement à la Style propriété pour un Button. La méthode setter contenue dans le style définit la propriété Background pour un Button mis en vert.

<Style x:Key="GreenButtonStyle">
    <Setter Property="Control.Background" Value="Green"/>
</Style>
<Button Style="{StaticResource GreenButtonStyle}" Content="I am green"/>

Pour plus d’informations, consultez Application d’un style et création de modèles.

Animations

Les propriétés de dépendance peuvent être animées. Lorsqu’une animation appliquée s’exécute, la valeur animée est plus prioritaire que toute autre valeur de propriété, y compris une valeur locale.

L’exemple suivant anime la Background propriété d’un Button. Techniquement, la syntaxe de l’élément de propriété définit un vide SolidColorBrush comme étant le Background, et la Color propriété de l’élément SolidColorBrush est animée.

<Button Content="I am animated">
    <Button.Background>
        <SolidColorBrush x:Name="AnimBrush"/>
    </Button.Background>
    <Button.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <ColorAnimation
                        Storyboard.TargetName="AnimBrush" 
                        Storyboard.TargetProperty="(SolidColorBrush.Color)"
                        From="Blue" To="White" Duration="0:0:1" 
                        AutoReverse="True" RepeatBehavior="Forever" />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Button.Triggers>
</Button>

Pour plus d’informations sur l’animation des propriétés, consultez Vue d’ensemble de l’animation et Vue d’ensemble des storyboards.

Substitutions de métadonnées

Vous pouvez modifier des comportements spécifiques d’une propriété de dépendance en substituant ses métadonnées lorsque vous dérivez de la classe qui a initialement inscrit la propriété de dépendance. La substitution de métadonnées s’appuie sur l’identificateur DependencyProperty et ne nécessite pas de réexédition de la propriété. La modification des métadonnées est gérée en mode natif par le système de propriétés. Chaque classe contient potentiellement des métadonnées individuelles pour toutes les propriétés héritées des classes de base, par type.

L’exemple suivant remplace les métadonnées d’une DefaultStyleKey propriété de dépendance. La substitution de métadonnées pour cette propriété de dépendance particulière fait partie d’un modèle d’implémentation permettant de créer des contrôles qui peuvent utiliser des styles par défaut à partir de thèmes.

public class SpinnerControl : ItemsControl
{
    static SpinnerControl() => DefaultStyleKeyProperty.OverrideMetadata(
            typeof(SpinnerControl),
            new FrameworkPropertyMetadata(typeof(SpinnerControl))
        );
}
Public Class SpinnerControl
    Inherits ItemsControl
    Shared Sub New()
        DefaultStyleKeyProperty.OverrideMetadata(GetType(SpinnerControl), New FrameworkPropertyMetadata(GetType(SpinnerControl)))
    End Sub
End Class

Pour plus d’informations sur la substitution ou l’accès aux métadonnées pour les propriétés de dépendance, consultez Remplacer les métadonnées d’une propriété de dépendance.

Héritage d’une valeur de propriété

Un élément peut hériter de la valeur d’une propriété de dépendance de son parent dans l’arborescence d’objets.

Remarque

Le comportement d’héritage des valeurs de propriété n’est pas globalement activé pour toutes les propriétés de dépendance, car le temps de calcul de l’héritage affecte les performances. L’héritage des valeurs de propriété est généralement activé uniquement dans les scénarios qui suggèrent l’applicabilité. Vous pouvez vérifier si une propriété de dépendance hérite en examinant la section Informations sur la propriété de dépendance pour cette propriété de dépendance dans la référence du Kit de développement logiciel (SDK).

L’exemple suivant montre une liaison qui inclut la DataContext propriété pour spécifier la source de la liaison. Par conséquent, les liaisons dans les objets enfants n’ont pas besoin de spécifier la source et peuvent utiliser la valeur héritée de DataContext l’objet parent StackPanel . Ou bien, un objet enfant peut spécifier directement son propre DataContext ou un Source objet dans le Binding, et n’utilise pas la valeur héritée.

<StackPanel Canvas.Top="50" DataContext="{Binding Source={StaticResource TestData}}">
    <Button Content="{Binding XPath=test[2]/@text}"/>
</StackPanel>

Pour plus d’informations, consultez Héritage des valeurs de propriété.

Intégration du concepteur WPF

Contrôles personnalisés avec des propriétés implémentées en tant que propriétés de dépendance s’intègrent bien au Concepteur WPF pour Visual Studio. L’un des exemples est la possibilité de modifier les propriétés de dépendance directes et jointes dans la fenêtre Propriétés . Pour plus d’informations, consultez vue d’ensemble de la création de contrôles.

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

Toutes les entrées basées sur des propriétés dans le système de propriétés WPF peuvent définir la valeur d’une propriété de dépendance. La priorité des valeurs de propriété de dépendance existe afin que les différents scénarios de la façon dont les propriétés obtiennent leurs valeurs interagissent de manière prévisible.

Remarque

La documentation du Kit de développement logiciel (SDK) utilise parfois le terme « valeur locale » ou « valeur définie localement » lors de la discussion des propriétés de dépendance. Une valeur définie localement est une valeur de propriété définie directement sur une instance d’objet dans le code ou en tant qu’attribut d’élément en XAML.

L’exemple suivant inclut un style qui s’applique à la Background propriété d’un bouton, mais spécifie un bouton avec une propriété définie Background localement. Techniquement, ce bouton a sa Background propriété définie deux fois, bien qu’une seule valeur s’applique, la valeur ayant la priorité la plus élevée. Une valeur définie localement a la priorité la plus élevée, à l’exception d’une animation en cours d’exécution, qui n’existe pas ici. Par conséquent, le deuxième bouton utilise la valeur définie localement pour la Background propriété, au lieu de la valeur de l’éditeur de style. Le premier bouton n’a pas de valeur locale ou d’autre valeur avec une priorité supérieure à un setter de style, et utilise donc la valeur de l’élément setter de style pour la Background propriété.

<StackPanel>
    <StackPanel.Resources>
        <Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
            <Setter Property="Background" Value="Orange"/>
        </Style>
    </StackPanel.Resources>
    <Button>I am styled orange</Button>
    <Button Background="Pink">I am locally set to pink (not styled orange)</Button>
</StackPanel>

Pourquoi la priorité des propriétés de dépendance existe-t-elle ?

Les valeurs définies localement sont prioritaires sur les valeurs setter de style, qui prennent en charge le contrôle local des propriétés d’élément. Pour plus d’informations, consultez Priorité des valeurs de propriété de dépendance.

Remarque

Un certain nombre de propriétés définies sur les éléments WPF ne sont pas des propriétés de dépendance, car les propriétés de dépendance ont généralement été implémentées uniquement lorsqu’une fonctionnalité du système de propriétés WPF a été requise. Les fonctionnalités incluent la liaison de données, le style, l’animation, la prise en charge des valeurs par défaut, l’héritage, les propriétés jointes et l’invalidation.

En savoir plus sur les propriétés de dépendance

  • Les développeurs de composants ou les développeurs d’applications peuvent souhaiter créer leur propre propriété de dépendance pour ajouter des fonctionnalités, telles que la prise en charge de la liaison de données ou des styles, ou l’invalidation et la prise en charge du forçage de valeur. Pour plus d’informations, consultez propriétés de dépendance personnalisées.

  • Considérez les propriétés de dépendance comme des propriétés publiques, accessibles ou détectables par n’importe quel appelant ayant accès à une instance. Pour plus d’informations, consultez La sécurité des propriétés de dépendance.

  • Une propriété jointe est un type de propriété qui prend en charge une syntaxe spécialisée en XAML. Une propriété jointe n’a souvent pas de correspondance 1:1 avec une propriété Common Language Runtime et n’est pas nécessairement une propriété de dépendance. L’objectif principal d’une propriété jointe est d’autoriser les éléments enfants à signaler des valeurs de propriété à un élément parent, même si l’élément parent et l’élément enfant n’incluent pas cette propriété dans le cadre des listes des membres de classe. Un scénario principal consiste à permettre à un élément enfant d’informer les éléments parents comment les présenter dans l’interface utilisateur. Pour obtenir des exemples, consultez Dock et Left. Pour plus d’informations, consultez la vue d’ensemble des propriétés jointes.

Voir aussi