Quelle est la différence entre une propriété de dépendance (personnalisée) et une propriété jointe dans WPF? Quelles sont les utilisations de chacun? En quoi les implémentations diffèrent-elles généralement?
Réponses:
Comme je n'ai trouvé que peu ou pas de documentation sur le sujet, il a fallu un peu de fouille dans le code source , mais voici une réponse.
Il y a une différence entre l'enregistrement d'une propriété de dépendance en tant que propriété régulière et en tant que propriété jointe, autre qu'une propriété "philosophique" ( les propriétés régulières sont destinées à être utilisées par le type déclarant et ses types dérivés, les propriétés jointes sont destinées à être utilisées comme extensions sur des DependencyObject
instances arbitraires ). "Philosophique", car, comme @MarqueIV l'a remarqué dans son commentaire à la réponse de @ ReedCopsey, les propriétés régulières peuvent également être utilisées avec des DependencyObject
instances arbitraires .
De plus, je ne suis pas d'accord avec les autres réponses indiquant que la propriété attachée est un "type de propriété de dépendance", car c'est trompeur - il n'y a pas de "types" de propriétés de dépendance. Le cadre ne se soucie pas de savoir si la propriété a été enregistrée comme attachée ou non - il n'est même pas possible de déterminer (dans le sens où cette information n'est pas enregistrée, car elle n'est pas pertinente). En fait, toutes les propriétés sont enregistrées comme si elles étaient des propriétés attachées, mais dans le cas des propriétés normales, certaines choses supplémentaires sont effectuées qui modifient légèrement leur comportement.
Pour vous éviter de parcourir le code source vous-même, voici une version résumée de ce qui se passe.
Lors de l'enregistrement d'une propriété sans métadonnées spécifiées, appel
DependencyProperty.Register(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass))
donne exactement le même résultat que l'appel
DependencyProperty.RegisterAttached(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass))
Cependant, lors de la spécification des métadonnées, l'appel
DependencyProperty.Register(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass),
typeMetadata: new FrameworkPropertyMetadata
{
CoerceValueCallback = CoerceCallback,
DefaultValue = "default value",
PropertyChangedCallback = ChangedCallback
});
équivaut à appeler
var property = DependencyProperty.RegisterAttached(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass),
defaultMetadata: new PropertyMetadata
{
DefaultValue = "default value",
});
property.OverrideMetadata(
forType: typeof(MyClass),
typeMetadata: new FrameworkPropertyMetadata
{
CoerceValueCallback = CoerceCallback,
DefaultValue = "default value",
PropertyChangedCallback = ChangedCallback
});
La principale différence (et unique) entre les propriétés de dépendance normales et attachées réside dans les métadonnées par défaut disponibles via la propriété DependencyProperty.DefaultMetadata . Ceci est même mentionné dans la section Remarques :
Pour les propriétés non attachées, le type de métadonnées renvoyé par cette propriété ne peut pas être converti en types dérivés de type PropertyMetadata , même si la propriété a été initialement inscrite avec un type de métadonnées dérivé. Si vous souhaitez que les métadonnées enregistrées à l'origine incluent leur type de métadonnées d'origine éventuellement dérivé, appelez plutôt GetMetadata (Type) , en transmettant le type d'enregistrement d'origine en tant que paramètre.
Pour les propriétés attachées, le type des métadonnées renvoyées par cette propriété correspondra au type indiqué dans la méthode d'inscription RegisterAttached d' origine .
Ceci est clairement visible dans le code fourni. De petits indices sont également cachés dans les méthodes d'enregistrement, c'est-à-dire que RegisterAttached
le paramètre de métadonnées est nommé defaultMetadata
, alors que pour Register
lui est nommé typeMetadata
. Pour les propriétés jointes, les métadonnées fournies deviennent les métadonnées par défaut. Cependant, dans le cas de propriétés normales, les métadonnées par défaut sont toujours une nouvelle instance de PropertyMetadata
avec uniquement DefaultValue
défini (soit à partir des métadonnées fournies, soit automatiquement). Seul l'appel suivant à OverrideMetadata
utilise réellement les métadonnées fournies.
La principale différence pratique est que dans le cas de propriétés régulières, les CoerceValueCallback
et PropertyChangedCallback
ne s'appliquent qu'aux types dérivés du type déclaré comme type de propriétaire, et aux propriétés attachées, ils s'appliquent à tous les types. Par exemple, dans ce scénario:
var d = new DependencyObject();
d.SetValue(SomeClass.SomeProperty, "some value");
la propriété enregistrée PropertyChangedCallback
sera appelée si la propriété a été enregistrée comme propriété attenante, mais ne sera pas appelée si elle a été enregistrée comme propriété ordinaire. Il en va de même CoerceValueCallback
.
Une différence secondaire provient du fait que OverrideMetadata
nécessite que le type fourni dérive DependencyObject
. En pratique, cela signifie que le type de propriétaire pour les propriétés régulières doit dériver de DependencyObject
, alors que pour les propriétés attachées, in peut être n'importe quel type (y compris les classes statiques, les structures, les énumérations, les délégués, etc.).
Outre la suggestion de @ MarqueIV, j'ai rencontré à plusieurs reprises des opinions selon lesquelles les propriétés régulières et attachées diffèrent dans la façon dont elles peuvent être utilisées en XAML . À savoir, que les propriétés régulières nécessitent une syntaxe de nom implicite par opposition à une syntaxe de nom explicite requise par les propriétés attachées. Ce n'est techniquement pas vrai , même si dans la pratique c'est généralement le cas. Pour plus de clarté:
<!-- Implicit property name -->
<ns:SomeClass SomeProperty="some value" />
<!-- Explicit property name -->
<DependencyObject ns:SomeClass.SomeProperty="some value" />
En XAML pur , les seules règles régissant l'utilisation de ces syntaxes sont les suivantes:
Le respect de ces conditions vous permet d'utiliser la syntaxe correspondante, que la propriété de dépendance de support ait été enregistrée comme régulière ou attachée.
Maintenant, l'idée fausse mentionnée est causée par le fait que la grande majorité des didacticiels (ainsi que des extraits de code Visual Studio ) vous demandent d'utiliser la propriété CLR pour les propriétés de dépendance normales et d'obtenir / définir des accesseurs pour ceux qui sont attachés. Mais rien ne vous empêche d'utiliser les deux en même temps, vous permettant d'utiliser la syntaxe que vous préférez.
Les propriétés jointes sont un type de propriété de dépendance. La différence réside dans la façon dont ils sont utilisés.
Avec une propriété jointe, la propriété est définie sur une classe qui n'est pas la même classe pour laquelle elle est utilisée. Ceci est généralement utilisé pour la mise en page. De bons exemples sont Panel.ZIndex ou Grid.Row - vous appliquez ceci à un contrôle (par exemple: Button), mais il est en fait défini dans Panel ou Grid. La propriété est "attachée" à l'instance du bouton.
Cela permet à un conteneur, par exemple, de créer des propriétés qui peuvent être utilisées sur n'importe quel élément UI.
En ce qui concerne les différences d'implémentation, il s'agit simplement d'utiliser Register vs RegisterAttached lorsque vous définissez la propriété.
Les propriétés attachées sont essentiellement destinées aux éléments du conteneur, comme si vous avez une grille et que vous avez grid.row maintenant, cela est considéré comme une propriété attachée d'un élément de grille.Vous pouvez également utiliser cette propriété dans texbox, bouton, etc.pour définir son place dans la grille.
La propriété de dépendance est comme la propriété appartient fondamentalement à une autre classe et est utilisée dans une autre classe. par exemple: comme vous avez un rectangle ici, la hauteur et la largeur sont des propriétés régulières du rectangle, mais left et top sont la propriété de dépendance car elle appartient à la classe Canvass.
Les propriétés jointes sont un type spécial de DependencyProperties. Ils vous permettent d'attacher une valeur à un objet qui ne sait rien de cette valeur. Les panneaux de disposition sont un bon exemple de ce concept. Chaque panneau de disposition a besoin de données différentes pour aligner ses éléments enfants. Le canevas a besoin du haut et de la gauche, le DockPanel a besoin du Dock, etc. Puisque vous pouvez écrire votre propre panneau de mise en page, la liste est infinie. Vous voyez donc qu'il n'est pas possible d'avoir toutes ces propriétés sur tous les contrôles WPF. La solution sont des propriétés attachées. Ils sont définis par le contrôle qui a besoin des données d'un autre contrôle dans un contexte spécifique. Par exemple, un élément aligné par un panneau de disposition parent.
Je pense que vous pouvez définir la propriété jointe dans la classe elle-même ou vous pouvez la définir dans une autre classe. Nous pourrions toujours utiliser la propriété jointe pour étendre les contrôles Microsoft standard. Mais propriété de dépendance, vous la définissez dans votre propre contrôle personnalisé. Par exemple, vous pouvez hériter de votre contrôle d'un contrôle standard, définir une propriété de dépendance dans votre propre contrôle et l'utiliser. Cela équivaut à définir une propriété jointe et à utiliser cette propriété jointe dans le contrôle standard.