Comment utiliser RelativeSource
avec les liaisons WPF et quels sont les différents cas d'utilisation?
.net
wpf
xaml
data-binding
relativesource
David Schmitt
la source
la source
AncestorType
.FindAncestor
, avantAncestorType
, j'obtiens l'erreur suivante: "RelativeSource n'est pas en mode FindAncestor". (Dans VS2013, version communautaire){Binding Path=DataContext.SomeProperty, RelativeSource=...
. Cela était quelque peu inattendu pour moi en tant que débutant lorsque j'essayais de me lier au DataContext d'un parent dans un DataTemplate.L'attribut par défaut de
RelativeSource
est laMode
propriété. Un ensemble complet de valeurs valides est donné ici (à partir de MSDN ):PreviousData Vous permet de lier l'élément de données précédent (pas le contrôle qui contient l'élément de données) dans la liste des éléments de données affichés.
TemplatedParent Fait référence à l'élément auquel le modèle (dans lequel l'élément lié aux données existe) est appliqué. Ceci est similaire à la définition d'un TemplateBindingExtension et n'est applicable que si la liaison est dans un modèle.
Self Fait référence à l'élément sur lequel vous définissez la liaison et vous permet de lier une propriété de cet élément à une autre propriété sur le même élément.
FindAncestor Fait référence à l'ancêtre dans la chaîne parent de l'élément lié aux données. Vous pouvez l'utiliser pour vous lier à un ancêtre d'un type spécifique ou à ses sous-classes. C'est le mode que vous utilisez si vous souhaitez spécifier AncestorType et / ou AncestorLevel.
la source
Voici une explication plus visuelle dans le contexte d'une architecture MVVM:
la source
{Binding Message}
(un peu plus simple ...)Path=DataContext.Message
pour que la liaison fonctionne. Cela a du sens, étant donné que vous pouvez faire des liaisons relatives à largeur / hauteur / etc. d'un contrôle.Bechir Bejaoui expose les cas d'utilisation des RelativeSources dans WPF dans son article ici :
la source
ListView
. Le parent a 2ListView
niveaux de plus en dessous. Cela m'a permis d' éviter le passage de données dans chaque vm subséquente de chaqueListView
s »DataTemplate
Dans WPF, la
RelativeSource
liaison en expose troisproperties
à définir:1. Mode: c'est un
enum
qui pourrait avoir quatre valeurs:2. AncestorType: lorsque le mode est
FindAncestor
alors définir quel type d'ancêtre3. AncestorLevel: quand le mode est
FindAncestor
alors à quel niveau d'ancêtre (s'il y a deux mêmes types de parentvisual tree
)Voici un lien de référence .
la source
N'oubliez pas TemplatedParent:
ou
la source
Il est à noter que pour ceux qui tombent sur cette pensée de Silverlight:
Silverlight propose uniquement un sous-ensemble réduit de ces commandes
la source
J'ai créé une bibliothèque pour simplifier la syntaxe de liaison de WPF, notamment en facilitant l'utilisation de RelativeSource. Voici quelques exemples. Avant:
Après:
Voici un exemple de simplification de la liaison de méthode. Avant:
Après:
Vous pouvez trouver la bibliothèque ici: http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html
Notez dans l'exemple «AVANT» que j'utilise pour la liaison de méthode que le code a déjà été optimisé en utilisant la
RelayCommand
dernière que j'ai vérifiée n'est pas une partie native de WPF. Sans cela, l'exemple «AVANT» aurait été encore plus long.la source
Quelques morceaux utiles:
Voici comment le faire principalement dans le code:
J'ai largement copié cela depuis Binding Relative Source dans le code Behind .
De plus, la page MSDN est assez bonne en ce qui concerne les exemples: Classe RelativeSource
la source
Je viens de publier une autre solution pour accéder au DataContext d'un élément parent dans Silverlight qui fonctionne pour moi. Il utilise
Binding ElementName
.la source
Je n'ai pas lu toutes les réponses, mais je veux juste ajouter ces informations en cas de liaison de commande source relative d'un bouton.
Lorsque vous utilisez une source relative avec
Mode=FindAncestor
, la liaison doit être comme:Si vous n'ajoutez pas DataContext dans votre chemin, au moment de l'exécution, il ne peut pas récupérer la propriété.
la source
Ceci est un exemple de l'utilisation de ce modèle qui a fonctionné pour moi sur des datagrids vides.
la source
Si un élément ne fait pas partie de l'arborescence visuelle, RelativeSource ne fonctionnera jamais.
Dans ce cas, vous devez essayer une technique différente, mise au point par Thomas Levesque.
Il a la solution sur son blog sous [WPF] Comment se lier aux données lorsque le DataContext n'est pas hérité . Et cela fonctionne absolument avec brio!
Dans le cas peu probable où son blog serait en panne, l'annexe A contient une copie miroir de son article .
Veuillez ne pas commenter ici, veuillez commenter directement sur son article de blog .
Annexe A: Miroir d'un article de blog
La propriété DataContext dans WPF est extrêmement pratique, car elle est automatiquement héritée par tous les enfants de l'élément où vous l'assignez; vous n'avez donc pas besoin de le redéfinir sur chaque élément que vous souhaitez lier. Cependant, dans certains cas, le DataContext n'est pas accessible: il se produit pour des éléments qui ne font pas partie de l'arborescence visuelle ou logique. Il peut alors être très difficile de lier une propriété sur ces éléments…
Illustrons avec un exemple simple: nous voulons afficher une liste de produits dans un DataGrid. Dans la grille, nous voulons pouvoir afficher ou masquer la colonne Price, en fonction de la valeur d'une propriété ShowPrice exposée par ViewModel. L'approche évidente consiste à lier la visibilité de la colonne à la propriété ShowPrice:
Malheureusement, la modification de la valeur de ShowPrice n'a aucun effet et la colonne est toujours visible… pourquoi? Si nous regardons la fenêtre Sortie dans Visual Studio, nous remarquons la ligne suivante:
Nous pouvons essayer de modifier la liaison pour obtenir le résultat souhaité, par exemple en définissant RelativeSource sur le DataGrid lui-même:
Ou nous pouvons ajouter un CheckBox lié à ShowPrice et essayer de lier la visibilité de la colonne à la propriété IsChecked en spécifiant le nom de l'élément:
Mais aucune de ces solutions de contournement ne semble fonctionner, nous obtenons toujours le même résultat…
À ce stade, il semble que la seule approche viable serait de modifier la visibilité des colonnes en code-behind, ce que nous préférons généralement éviter lors de l'utilisation du modèle MVVM… Mais je ne vais pas abandonner si tôt, du moins pas alors qu'il existe d'autres options à considérer 😉
La solution à notre problème est en fait assez simple et tire parti de la classe Freezable. Le but principal de cette classe est de définir des objets qui ont un état modifiable et en lecture seule, mais la caractéristique intéressante dans notre cas est que les objets Freezable peuvent hériter du DataContext même lorsqu'ils ne sont pas dans l'arborescence visuelle ou logique. Je ne connais pas le mécanisme exact qui permet ce comportement, mais nous allons en profiter pour faire fonctionner notre reliure…
L'idée est de créer une classe (je l'ai appelée BindingProxy pour des raisons qui devraient devenir évidentes très bientôt) qui hérite de Freezable et déclare une propriété de dépendance des données:
Nous pouvons ensuite déclarer une instance de cette classe dans les ressources du DataGrid et lier la propriété Data au DataContext actuel:
La dernière étape consiste à spécifier cet objet BindingProxy (facilement accessible avec StaticResource) comme source pour la liaison:
Notez que le chemin de liaison a été préfixé avec «Data», car le chemin est maintenant relatif à l'objet BindingProxy.
La liaison fonctionne désormais correctement et la colonne est correctement affichée ou masquée en fonction de la propriété ShowPrice.
la source