En utilisant le modèle MVVM, j'ai une paire de classes de modèle de vue qui représentent une hiérarchie de données à deux niveaux, chacune avec un UserControl
correspondant qui représente sa vue . Les deux classes de modèle de vue implémentent INotifyPropertyChanged
et le modèle de vue de niveau racine expose une propriété qui est pertinente à la fois pour sa propre vue et pour la vue enfant.WPF + MVVM - Comment lier une propriété au contexte de données de la vue parent
La vue de niveau racine acquiert le modèle de vue de niveau racine en tant que contexte de données et affecte explicitement un contexte de données à sa vue. Toutefois, il doit également lier l'une des propriétés de la vue enfant à la propriété partagée mentionnée ci-dessus. Voici comment j'ai essayé d'y parvenir, mais il ne fonctionne pas:
<UserControl x:Name="rootView">
<StackPanel>
<!-- other controls here -->
<my:ChildView
DataContext="{Binding Path=SelectedChild}"
EditingMode="{Binding ElementName=rootView, Path=DataContext.EditingMode />
</StackPanel>
</UserControl>
Bien qu'il n'y ait pas d'erreurs de liaison d'exécution et la vue de l'enfant se fixe correctement à l'instance de modèle de vue enfant approprié, sa propriété EditingMode
est jamais définie. J'ai exécuté des tests pour vérifier que la propriété de modèle de vue correspondante est en cours de modification et qu'il notifie cette modification via INotifyPropertyChanged
, mais la liaison ne parvient pas à le détecter.
Existe-t-il un meilleur moyen de déclarer cette liaison ou ai-je fait une erreur architecturale plus basique?
Un grand merci pour vos conseils,
Tim
Mise à jour: Comme l'a demandé, je signale un code pour afficher une version très simplifiée de mes vues et modèles de vue, ainsi que les résultats d'une expérience que j'ai menée qui peut fournir des indices supplémentaires.
// The relevant parts of the ParentViewModel class
public class ParentViewModel : INotifyPropertyChanged
{
// Although not shown, the following properties
// correctly participate in INotifyPropertyChanged
public ChildViewModel SelectedChild { get; private set; }
public ContentEditingMode EditingMode { get; private set; }
}
// The relevant parts of the ChildViewModel class
public class ChildViewModel : INotifyPropertyChanged
{
// No properties of ChildViewModel affect this issue.
}
// The relevant parts of the ParentView class
public partial class ParentView : UserControl
{
// No properties of ParentView affect this issue.
}
// The relevant members of the ChildView class
public partial class ChildView : UserControl
{
public static readonly DependencyProperty EditingModeProperty =
DependencyProperty.Register(
"EditingMode",
typeof(ContentEditingMode),
typeof(PostView)
);
public ContentEditingMode EditingMode
{
get { return (ContentEditingMode)GetValue(EditingModeProperty); }
set { SetValue(EditingModeProperty, value); }
}
}
// The enumeration used for the EditingMode property
public enum ContentEditingMode
{
Html,
WYSYWIG
}
Mon intention est que le DataContext
de l'instance de vue parent est assigné une instance de ParentViewModel
et il sera, à son tour, affecter la valeur de sa propriété SelectedChild
au DataContext
du ChildView
imbriquée. Tout cela semble fonctionner correctement, mais le problème se pose parce que la liaison entre ParentViewModel.EditingMode
et ChildView.EditingMode
ne fonctionne pas.
Pour tenter de vérifier s'il y a un problème avec mon expression de liaison, j'introduit un TextBlock
adjacent au ChildView
et enveloppèrent de façon similaire à la propriété ParentViewModel.EditingMode
:
<UserControl x:Name="rootView">
<StackPanel>
<!-- other controls here -->
<TextBlock Text="{Binding ElementName=rootView, Path=DataContext.EditingMode}" />
<my:ChildView
DataContext="{Binding Path=SelectedChild}"
EditingMode="{Binding ElementName=rootView, Path=DataContext.EditingMode />
</StackPanel>
</UserControl>
Dans ce test, le TextBlock
est correctement mis à jour chaque fois que la propriété source change. Cependant, si je mets un point d'arrêt sur le setter de ChildView.EditingMode
, il ne sera jamais touché.
Je suis déconcerté!
La définition d'un point d'arrêt sur le setter d'une propriété de dépendance ne fonctionnera pas. Le point entier des propriétés de dépendance est qu'elles sont définies par le système de propriété de dépendance. C'est pourquoi vous ne pouvez pas vous lier aux propriétés CLR ordinaires; les liaisons définissent les propriétés de la cible en appelant 'SetValue'. Si vous souhaitez tracer le paramètre des propriétés de dépendance, vous devez implémenter une fonction de rappel et utiliser la surcharge de 'Register' qui vous permet de le spécifier. –
Merci pour cette précision - cela me sauvera probablement d'innombrables heures de frustration. –
Cela m'aurait sauvé d'innombrables heures de frustration si je l'avais su, je peux vous dire ça. –