Partager via


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

Windows Presentation Foundation (WPF) fournit un ensemble de services qui peuvent être utilisés pour étendre les fonctionnalités 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. Cette vue d’ensemble présente également des aspects spécialisés des propriétés de dépendance, tels que les métadonnées de propriété de dépendance et la création de votre propre propriété de dépendance dans une classe personnalisée.

Conditions préalables

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 champ d’identificateur DependencyProperty pour 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.

Propriétés de dépendance en arrière des propriétés CLR

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é soutenue par un DependencyProperty.

  • 'identificateur de propriété de dépendance, qui est une instance DependencyProperty obtenue comme valeur de retour lors de l’inscription d’une propriété de dépendance, puis stockée 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 sont les implémentations get et set pour la propriété. Ces implémentations incorporent l’identificateur de propriété de dépendance en l’utilisant dans les appels GetValue et SetValue. De cette façon, le système de propriétés WPF fournit le support de la propriété.

L'exemple suivant définit la propriété de dépendance IsSpinning pour afficher la relation de l'identificateur DependencyProperty à la propriété qu'il soutient.

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 son champ de stockage DependencyProperty est importante. Le nom du champ est toujours le nom de la propriété, avec le suffixe Property ajouté. Pour plus d’informations sur cette convention et les raisons de celle-ci, consultez propriétés de dépendance personnalisées.

Définition des valeurs de propriété

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

Définition des 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 attribue au bouton Background la propriété d'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 des 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 « wrapper » de get :

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

Vous pouvez également appeler les API système de propriétés GetValue 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 visibilité de la propriété pour les outils de développement.

Les propriétés peuvent également être définies en XAML, puis accessibles ultérieurement dans le code, via code-behind. Pour de plus amples 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 de propriété Resources 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 ressource SolidColorBrush :

<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 propriété Background :

<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 ressources XAML.

Note

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é de valeur de propriété de dépendance.

Liaison de données

Une propriété de dépendance peut référencer une valeur par le biais de la liaison de données. La liaison de données fonctionne via une syntaxe d’extension de balisage spécifique en XAML ou l’objet Binding dans le 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 propriété Content 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 affiché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}"/>

Note

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 Précédence des valeurs de propriété de dépendance.

Les propriétés de dépendance, ou la classe DependencyObject, ne prennent pas en charge nativement INotifyPropertyChanged pour la notification des changements dans la valeur de la propriété source DependencyObject lors des 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. Les styles 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 dictionnaire Resources (non affiché). Ensuite, ce style est appliqué directement à la propriété Style pour un Button. Dans le cadre des styles, le setter définit la propriété Background d’un Button stylisé à la couleur verte.

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

Pour plus d’informations, consultez style et modélisation.

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 propriété Background d’un Button. Techniquement, la syntaxe de l’élément de propriété définit une SolidColorBrush vide comme Background, et la propriété Color de l'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.

Remplacements 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 la réimplémentation 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 propriété de dépendance DefaultStyleKey. 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 en savoir plus sur la façon de redéfinir ou d'accéder aux métadonnées pour les propriétés dépendantes, consultez Remplacer les métadonnées pour une propriété dépendante.

Héritage des valeurs 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.

Note

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 de 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 propriété DataContext 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 dans l'objet parent StackPanel. Ou bien, un objet enfant peut spécifier directement son propre DataContext ou un Source dans le Binding, et ne pas utiliser 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 de valeur de propriété.

Intégration du designer 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 des propriétés de dépendance directes et jointes dans la fenêtre Propriétés . Pour en savoir plus, consultez Vue d’ensemble de la création des contrôles.

Priorité de la valeur de 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. Priorité de valeur de propriété-de-dépendance existe afin que les différents scénarios de la manière dont les propriétés obtiennent leurs valeurs s'articulent 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 propriété Background d’un bouton quelconque, mais spécifie un bouton avec une propriété Background définie localement. Techniquement, ce bouton a sa propriété Background 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 propriété Background, au lieu de la valeur setter de style. Le premier bouton n’a pas de valeur locale ni d'autre valeur ayant une priorité supérieure à une valeur définissant le style, et utilise donc la valeur définie pour la propriété Background.

<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 Précédence des valeurs des propriétés de dépendance.

Note

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, voir : 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 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 aperçu des propriétés attachées.

Voir aussi