J'ai un ListBox
qui se lie à une collection enfant sur un ViewModel. Les éléments de la zone de liste sont stylisés dans un modèle de données basé sur une propriété du ViewModel parent:
<Style x:Key="curveSpeedNonConstantParameterCell">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=DataContext.CurveSpeedMustBeSpecified,
ElementName=someParentElementWithReferenceToRootDataContext}"
Value="True">
<Setter Property="Control.Visibility" Value="Hidden"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
J'obtiens l'erreur de sortie suivante:
System.Windows.Data Error: 39 : BindingExpression path error:
'CurveSpeedMustBeSpecified' property not found on
'object' ''BindingListCollectionView' (HashCode=20467555)'.
BindingExpression:Path=DataContext.CurveSpeedMustBeSpecified;
DataItem='Grid' (Name='nonConstantCurveParametersGrid');
target element is 'TextBox' (Name='');
target property is 'NoTarget' (type 'Object')
Donc, si je change l'expression de liaison, "Path=DataContext.CurrentItem.CurveSpeedMustBeSpecified"
cela fonctionne, mais seulement tant que le contexte de données du contrôle utilisateur parent est un BindingListCollectionView
. Cela n'est pas acceptable car le reste du contrôle utilisateur se lie aux propriétés du CurrentItem
sur le BindingList
automatiquement.
Comment puis-je spécifier l'expression de liaison à l'intérieur du style afin qu'elle fonctionne indépendamment du fait que le contexte de données parent soit une vue de collection ou un élément unique?
Vous pouvez utiliser
RelativeSource
pour trouver l'élément parent, comme ceci -Voir cette question SO pour plus de détails sur
RelativeSource
.la source
Mode=FindAncestor
pour que cela fonctionne, mais cela fonctionne et est bien meilleur dans un scénario MVVM car cela évite de nommer les contrôles.Binding="{Binding Path=DataContext.CurveSpeedMustBeSpecified, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:YourParentElementType}}}"
RelativeSource et ElementName
Ces deux approches peuvent aboutir au même résultat,
RelativeSrouce
Cette méthode recherche un contrôle de type Window (dans cet exemple) dans l'arborescence visuelle et quand il le trouve, vous pouvez essentiellement y accéder en
DataContext
utilisant lePath=DataContext....
. L'avantage de cette méthode est que vous n'avez pas besoin d'être lié à un nom et que c'est un peu dynamique, cependant, les modifications apportées à votre arborescence visuelle peuvent affecter cette méthode et éventuellement la casser.Nom de l'élément
Cette méthode fait référence à une statique solide
Name
donc tant que votre portée peut la voir, tout va bien.Vous devriez vous en tenir à votre convention de nommage pour ne pas casser cette méthode bien sûr.L'approche est très simple et tout ce dont vous avez besoin est de spécifier aName="..."
pour votre Window / UserControl.Bien que les trois types (
RelativeSource, Source, ElementName
) soient capables de faire la même chose, mais selon l'article MSDN suivant, chacun est mieux utilisé dans son propre domaine de spécialité.Comment: spécifier la source de liaison
Trouvez la brève description de chacun ainsi qu'un lien vers une description plus détaillée dans le tableau en bas de la page.
la source
Je cherchais comment faire quelque chose de similaire dans WPF et j'ai obtenu cette solution:
J'espère que cela fonctionne pour quelqu'un d'autre. J'ai un contexte de données qui est défini automatiquement sur les ItemsControls, et ce contexte de données a deux propriétés:
MyItems
-qui est une collection-, et une commande «CustomCommand». En raison de l'ItemTemplate
utilisation de aDataTemplate
, lesDataContext
niveaux supérieurs ne sont pas directement accessibles. Ensuite, la solution de contournement pour obtenir le contrôleur de domaine du parent consiste à utiliser un chemin d'accès relatif et à filtrer parItemsControl
type.la source
le problème est qu'un DataTemplate ne fait pas partie d'un élément qui lui est appliqué.
cela signifie que si vous vous liez au modèle, vous liez à quelque chose qui n'a pas de contexte.
Cependant, si vous mettez un élément dans le modèle, lorsque cet élément est appliqué au parent, il obtient un contexte et la liaison fonctionne alors
donc cela ne fonctionnera pas
mais cela fonctionne parfaitement
car une fois le modèle de données appliqué, la boîte de groupe est placée dans le parent et aura accès à son contexte
il vous suffit donc de supprimer le style du modèle et de le déplacer dans un élément du modèle
notez que le contexte d'un itemscontrol est l'élément pas le contrôle ie ComboBoxItem pour ComboBox pas le ComboBox lui-même auquel cas vous devriez utiliser les contrôles ItemContainerStyle à la place
la source
Oui, vous pouvez le résoudre en utilisant le
ElementName=Something
comme suggéré par la Juve.MAIS!
Si un élément enfant (sur lequel vous utilisez ce type de liaison) est un contrôle utilisateur qui utilise le même nom d'élément que celui que vous spécifiez dans le contrôle parent, alors la liaison va vers le mauvais objet !!
Je sais que cet article n'est pas une solution, mais je pensais que tous ceux qui utilisent le nom de l'élément dans la liaison devraient le savoir, car il s'agit d'un bogue d'exécution possible.
la source