Vue d'ensemble des propriétés jointes

Une propriété jointe est un concept défini par XAML. Une propriété jointe est destinée à être utilisée comme type de propriété globale qui est settable sur n’importe quel objet de dépendance. Dans Windows Presentation Foundation (WPF), les propriétés jointes sont généralement définies comme une forme spécialisée de propriété de dépendance qui n’a pas la propriété conventionnelle « wrapper ».

Conditions préalables

Cet article suppose 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 (Windows Presentation Foundation) et que vous avez lu la vue d’ensemble des propriétés de dépendance. Pour suivre les exemples de cet article, vous devez également comprendre XAML et savoir comment écrire des applications WPF.

Pourquoi utiliser les propriétés jointes

L’un des objectifs d’une propriété jointe est de permettre à différents éléments enfants de spécifier des valeurs uniques pour une propriété définie dans un élément parent. Une application spécifique de ce scénario fait en sorte que les éléments enfants informent l’élément parent de la façon dont ils doivent être présentés dans l’interface utilisateur (IU). L’un des exemples est la DockPanel.Dock propriété. La DockPanel.Dock propriété est créée en tant que propriété jointe, car elle est conçue pour être définie sur les éléments contenus dans un DockPanel élément plutôt que sur DockPanel lui-même. La DockPanel classe définit le champ statique DependencyProperty nommé DockProperty, puis fournit les méthodes et SetDock les GetDock méthodes en tant qu’accesseurs publics pour la propriété jointe.

Propriétés jointes en XAML

En XAML, vous définissez des propriétés jointes à l’aide de la syntaxe FournisseurPropriétéJointe.NomPropriété

Voici un exemple de la façon dont vous pouvez définir DockPanel.Dock en XAML :

<DockPanel>
    <TextBox DockPanel.Dock="Top">Enter text</TextBox>
</DockPanel>

L’utilisation est un peu similaire à une propriété statique ; vous référencez toujours le type DockPanel qui possède et inscrit la propriété jointe, plutôt que de faire référence à une instance spécifiée par nom.

En outre, comme une propriété jointe en XAML est un attribut que vous définissez dans le balisage, seule l’opération définie est pertinente. Vous ne pouvez pas obtenir directement une propriété en XAML, bien que des mécanismes indirects permettent de comparer des valeurs, telles que les déclencheurs dans les styles (pour plus d’informations, consultez Application d’un style et création de modèles).

Implémentation des propriétés jointes dans WPF

Dans Windows Presentation Foundation (WPF), la plupart des propriétés jointes liées à l’interface utilisateur sur les types WPF sont implémentées en tant que propriétés de dépendance. Les propriétés jointes sont un concept XAML, tandis que les propriétés de dépendance sont un concept WPF. Étant donné que les propriétés jointes WPF sont des propriétés de dépendance, elles prennent en charge les concepts de propriété de dépendance tels que les métadonnées de propriété et les valeurs par défaut de ces métadonnées de propriété.

Utilisation des propriétés jointes par le type propriétaire

Bien que les propriétés jointes puissent être définies sur tout objet, cela ne signifie pas systématiquement que leur définition produira un résultat concret ou que leur valeur sera jamais utilisée par un autre objet. En général, les propriétés jointes sont utilisées pour que les objets provenant de diverses relations logiques ou hiérarchies de classes possibles puissent chacun communiquer des informations communes au type qui définit la propriété jointe. Le type qui définit la propriété jointe suit en général l’un de ces modèles :

  • Le type qui définit la propriété jointe est conçu pour pouvoir être l’élément parent des éléments qui définiront les valeurs de la propriété jointe. Le type itère ensuite ses objets enfants par le biais de la logique interne au sein d’une structure d’objets arborescente, obtient les valeurs et agit sur elles.

  • Le type qui définit la propriété jointe est utilisé comme élément enfant pour divers éléments parents et modèles de contenu possibles.

  • Le type qui définit la propriété jointe représente un service. D’autres types définissent les valeurs de la propriété jointe. Quand l’élément qui définit la propriété est évalué dans le contexte du service, les valeurs de la propriété jointe sont obtenues par le biais de la logique interne de la classe de service.

Exemple d’une propriété jointe définie par le parent

Le scénario le plus courant où WPF définit une propriété jointe est lorsqu’un élément parent prend en charge une collection d’éléments enfants, et implémente également un comportement où les spécificités du comportement sont signalées individuellement pour chaque élément enfant.

DockPaneldéfinit la propriété jointe et DockPanel a du code au niveau de la DockPanel.Dock classe dans le cadre de sa logique de rendu (en particulier, MeasureOverride et ArrangeOverride). Une DockPanel instance case activée toujours pour déterminer si l’un de ses éléments enfants immédiats a défini une valeur pour DockPanel.Dock. Si tel est le cas, ces valeurs sont entrées pour la logique de rendu appliquée à l’élément enfant en question. Les instances imbriquées traitent chacune leurs propres collections d’éléments enfants immédiats DockPanel , mais ce comportement est spécifique à l’implémentation de la façon dont DockPanel les valeurs sont traitées DockPanel.Dock . Il est théoriquement possible d’avoir des propriétés jointes qui influent sur les éléments au-delà du parent immédiat. Si la DockPanel.Dock propriété jointe est définie sur un élément qui n’a pas DockPanel d’élément parent à agir dessus, aucune erreur ou exception n’est générée. Cela signifie simplement qu’une valeur de propriété globale a été définie, mais qu’elle n’a pas de parent actuel DockPanel pouvant consommer les informations.

Propriétés jointes dans le code

Les propriétés jointes dans WPF n’ont pas les méthodes « wrapper » CLR classiques pour obtenir/définir facilement l’accès. Cela est dû au fait que la propriété jointe ne fait pas nécessairement partie de l’espace de noms CLR pour les instances où la propriété est définie. Toutefois, un processeur XAML doit pouvoir définir ces valeurs quand XAML est analysé. Pour prendre en charge une utilisation efficace des propriétés jointes, le type propriétaire de la propriété jointe doit implémenter des méthodes d’accesseur dédiées sous la forme Get PropertyName et SetPropertyName. Ces méthodes d’accesseur dédiées sont également utiles pour obtenir ou définir la propriété jointe dans le code. Du point de vue du code, une propriété jointe s’apparente à un champ de stockage comportant des accesseurs de méthode au lieu d’accesseurs de propriété, et ce champ de stockage peut exister sur tout objet plutôt que devoir être défini de manière spécifique.

L’exemple suivant illustre la définition d’une propriété jointe dans le code. Dans cet exemple, myCheckBox est une instance de la CheckBox classe.

DockPanel myDockPanel = new DockPanel();
CheckBox myCheckBox = new CheckBox();
myCheckBox.Content = "Hello";
myDockPanel.Children.Add(myCheckBox);
DockPanel.SetDock(myCheckBox, Dock.Top);
Dim myDockPanel As New DockPanel()
Dim myCheckBox As New CheckBox()
myCheckBox.Content = "Hello"
myDockPanel.Children.Add(myCheckBox)
DockPanel.SetDock(myCheckBox, Dock.Top)

Comme pour le cas XAML, s’il myCheckBox n’avait pas déjà été ajouté en tant qu’élément enfant de myDockPanel la quatrième ligne de code, la cinquième ligne de code ne déclencherait pas d’exception, mais la valeur de propriété n’interagirait pas avec un DockPanel parent et ne ferait donc rien. Seule une DockPanel.Dock valeur définie sur un élément enfant combiné à la présence d’un DockPanel élément parent entraîne un comportement efficace dans l’application rendue. (Dans ce cas, vous pouvez définir la propriété jointe, puis l’attacher à l’arborescence. Vous pouvez également vous attacher à l’arborescence, puis définir la propriété jointe. L’un ou l’autre ordre d’action fournit le même résultat.)

Métadonnées de propriété jointe

Lors de l’inscription de la propriété, FrameworkPropertyMetadata est défini pour spécifier les caractéristiques de la propriété, par exemple si la propriété affecte le rendu, la mesure, etc. Les métadonnées d’une propriété jointe sont en général identiques à celles d’une propriété de dépendance. Si vous spécifiez une valeur par défaut dans une substitution des métadonnées d’une propriété jointe, cette valeur devient la valeur par défaut de la propriété jointe implicite sur les instances de la classe de substitution. Spécifiquement, votre valeur par défaut est signalée si un processus demande la valeur d’une propriété jointe par le biais de l’accesseur de méthode Get de cette propriété, en spécifiant une instance de la classe dans laquelle vous avez indiqué les métadonnées, et si la valeur de cette propriété jointe n’était autrement pas définie.

Si vous souhaitez activer l’héritage des valeurs de propriété sur une propriété, vous devez utiliser des propriétés jointes plutôt que des propriétés de dépendance non jointes. Pour plus d’informations, consultez Héritage de la valeur de propriété.

Propriétés jointes personnalisées

Quand créer une propriété jointe

Vous pouvez créer une propriété jointe si un mécanisme de définition de propriété doit être disponible pour les classes autres que la classe de définition. Le scénario le plus courant à cette fin est la mise en page. Des exemples de propriétés de disposition existantes sont DockPanel.Dock, Panel.ZIndexet Canvas.Top. Le scénario activé ici implique que les éléments existant comme éléments enfants sur les éléments contrôlant la mise en page sont en mesure d’exprimer individuellement des spécifications de mise en page à leurs éléments parents de mise en page et chacun d’eux définit une valeur de propriété configurée par le parent en tant que propriété jointe.

Un autre scénario illustrant l’utilisation d’une propriété jointe s’applique quand votre classe représente un service et que vous voulez que les classes soient en mesure d’intégrer le service avec une plus grande transparence.

Pourtant, un autre scénario consiste à recevoir la prise en charge du Concepteur WPF Visual Studio, par exemple la modification de fenêtre Propriétés . Pour plus d’informations, consultez Vue d’ensemble de la création de contrôles.

Comme mentionné précédemment, vous devez enregistrer une propriété jointe si vous souhaitez utiliser l’héritage des valeurs de propriété.

Guide pratique pour créer une propriété jointe

Si votre classe définit la propriété jointe strictement à utiliser sur d’autres types, la classe n’a pas à dériver de DependencyObject. Toutefois, vous devez dériver si DependencyObject vous suivez le modèle WPF global d’avoir votre propriété jointe également une propriété de dépendance.

Définissez votre propriété jointe en tant que propriété de dépendance en déclarant un public static readonly champ de type DependencyProperty. Vous définissez ce champ à l’aide de la valeur de retour de la RegisterAttached méthode. Le nom du champ doit correspondre au nom de la propriété jointe, ajouté à la chaîne Property, pour suivre le modèle WPF établi de nommage des champs d’identification par rapport aux propriétés qu’ils représentent. Le fournisseur de propriétés attaché doit également fournir des méthodes GetPropertyName et SetPropertyName statiques en tant qu’accesseurs pour la propriété jointe . Cela entraîne l’impossibilité pour le système de propriétés d’utiliser votre propriété jointe.

Remarque

Si vous omettez l’accesseur get de la propriété jointe, la liaison de données sur la propriété ne fonctionnera pas dans les outils de conception, tels que Visual Studio et Blend pour Visual Studio.

Accesseur Get

La signature de l’accesseur GetPropertyName doit être :

public static object GetPropertyName(object target)

  • L’objet target peut être défini comme un type plus spécifique dans votre implémentation. Par exemple, la DockPanel.GetDock méthode tape le paramètre en tant que UIElement, car la propriété jointe est destinée à être définie uniquement sur UIElement les instances.

  • La valeur de retour peut être spécifiée comme un type plus spécifique dans votre implémentation. Par exemple, la GetDock méthode la tape en tant que Dock, car la valeur ne peut être définie que sur cette énumération.

Accesseur Set

La signature de l’accesseur SetPropertyName doit être :

public static void SetPropertyName(object target, object value)

  • L’objet target peut être défini comme un type plus spécifique dans votre implémentation. Par exemple, la SetDock méthode la tape en tant que UIElement, car la propriété jointe est destinée uniquement à être définie sur UIElement des instances.

  • L’objet value peut être défini comme un type plus spécifique dans votre implémentation. Par exemple, la SetDock méthode la tape en tant que Dock, car la valeur ne peut être définie que sur cette énumération. N’oubliez pas que la valeur de cette méthode est l’entrée provenant du chargeur XAML quand il rencontre votre propriété jointe dans une utilisation des propriétés jointes dans le balisage. Cette entrée est la valeur spécifiée comme valeur d’attribut XAML dans le balisage. Ainsi, la conversion de type, la sérialisation de valeur ou l’extension de balisage doit être prise en charge pour le type utilisé afin que le type approprié puisse être créé à partir de la valeur d’attribut (laquelle est en fin de compte une simple chaîne).

L’exemple suivant montre l’inscription de propriété de dépendance (à l’aide de la RegisterAttached méthode), ainsi que les accesseurs GetPropertyName et SetPropertyName. Dans cet exemple, le nom de la propriété jointe est IsBubbleSource. Les accesseurs doivent donc être nommés GetIsBubbleSource et SetIsBubbleSource.

public static readonly DependencyProperty IsBubbleSourceProperty = DependencyProperty.RegisterAttached(
  "IsBubbleSource",
  typeof(Boolean),
  typeof(AquariumObject),
  new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender)
);
public static void SetIsBubbleSource(UIElement element, Boolean value)
{
  element.SetValue(IsBubbleSourceProperty, value);
}
public static Boolean GetIsBubbleSource(UIElement element)
{
  return (Boolean)element.GetValue(IsBubbleSourceProperty);
}
Public Shared ReadOnly IsBubbleSourceProperty As DependencyProperty = DependencyProperty.RegisterAttached("IsBubbleSource", GetType(Boolean), GetType(AquariumObject), New FrameworkPropertyMetadata(False, FrameworkPropertyMetadataOptions.AffectsRender))
Public Shared Sub SetIsBubbleSource(ByVal element As UIElement, ByVal value As Boolean)
    element.SetValue(IsBubbleSourceProperty, value)
End Sub
Public Shared Function GetIsBubbleSource(ByVal element As UIElement) As Boolean
    Return CType(element.GetValue(IsBubbleSourceProperty), Boolean)
End Function

Attributs des propriétés jointes

WPF définit plusieurs attributs .NET destinés à fournir des informations sur les propriétés jointes aux processus de réflexion, ainsi qu’aux utilisateurs classiques des informations de réflexion et de propriété telles que les concepteurs. Les propriétés jointes ayant un type de portée illimitée, les concepteurs ont besoin d’un moyen d’éviter que les utilisateurs croulent sous une liste globale de toutes les propriétés jointes qui sont définies dans l’implémentation d’une technologie particulière utilisant XAML. Les attributs .NET définis par WPF pour les propriétés jointes peuvent être utilisés pour définir l’étendue des situations où une propriété jointe donnée doit être affichée dans une fenêtre de propriétés. Vous pouvez également envisager l’application de ces attributs à vos propres propriétés jointes personnalisées. L’objectif et la syntaxe des attributs .NET sont décrits sur les pages de référence appropriées :

Apprentissage plus sur les propriétés jointes

  • Pour plus d’informations sur la création d’une propriété jointe, consultez Enregistrer une propriété jointe.

  • Pour obtenir des scénarios d’usage avancés des propriétés de dépendance et des propriétés jointes, consultez Propriétés de dépendance personnalisées.

  • Vous pouvez également enregistrer une propriété en tant que propriété jointe et que propriété de dépendance ; mais dans cette situation, vous exposez encore les implémentations de « wrapper ». Dans ce cas, vous pouvez définir la propriété soit sur cet élément, soit sur tout élément par le biais de la syntaxe de propriété jointe XAML. Un exemple de propriété avec un scénario approprié pour les utilisations standard et attachées est FrameworkElement.FlowDirection.

Voir aussi