WPF + MVVM - How to Bind a Property to the Parent View Data Context

Working with the MVVM template, I have a couple of classes of presentation models that represent a two-level hierarchy of data, each of which has a corresponding UserControl that represents its presentation. Both classes of the view model implement INotifyPropertyChanged , and the root level view model provides a property that is related to both its own view and the view of the child.

In the root level view, the root level view model is considered as a data context and explicitly assigns the data context to the view it contains. However, it must also bind one of the properties of the child view to the aforementioned general property. This is how I tried to achieve this, but it does not work:

 <UserControl x:Name="rootView"> <StackPanel> <!-- other controls here --> <my:ChildView DataContext="{Binding Path=SelectedChild}" EditingMode="{Binding ElementName=rootView, Path=DataContext.EditingMode /> </StackPanel> </UserControl> 

Although there are no binding errors at run time, and the child view is correctly bound to the corresponding instance of the child view model, its EditingMode property EditingMode never set. I checked the tests to verify that the corresponding property of the view model will be changed, and that it notifies this change with INotifyPropertyChanged , but the binding cannot detect it.

Is there a better way to declare this binding or have I made a more basic architecture mistake?

Thanks so much for your advice,

Tim

Update: As requested, I am posting some code to show a very simplified version of my views and viewing models, as well as the results of my experiment, which may provide some additional hints.

 // 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 } 

My intention is that the ParentViewModel will be assigned to the DataContext parent view instance, and it will in turn assign the value of its SelectedChild property to the DataContext nested ChildView . All this works correctly, but the problem arises because the binding between ParentViewModel.EditingMode and ChildView.EditingMode does not work.

In an attempt to check if there is a problem with my binding expression, I entered a TextBlock next to ChildView and linked it similarly to the ParentViewModel.EditingMode property:

 <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> 

In this test, the TextBlock updated correctly every time the source property changes. However, if I set a breakpoint on the ChildView.EditingMode setter, it never hits.

I am puzzled!

+4
source share
2 answers

The easiest way to fix this is in your view model. Add the EditingMode property to the child view model and bind it. Thus, you do not need to make any guesses about what the correct way to establish a binding might be; Also, this is something you can check outside of the interface.

Edit

In fact, the right decision is not so simple, but it is worth knowing how to do it.

What you want is for EditingMode in the child control to effectively inherit its value from the parent control. Does this look like something that does something else in WPF? Like every element of a structure that implements dependency properties?

EditingMode as a dependency property in both the parent and child UserControl and use property value inheritance as described here . This completely removes the inheritance behavior from the view model and places it where it belongs.

+2
source

See if you can simply use the full path to get the editing mode of the selected child:

 <my:childView DataContext="{Binding SelectedChild}" EditingMode="{Binding SelectedChild.EditingMode /> 
+2
source

Source: https://habr.com/ru/post/1314616/


All Articles