I'm trying to get my first WPF app working using MVVM, and I've hit a little binding problem.
The setup is that I have a view & viewModel which holds User details (the parent), and to try and keep things simple I've put a section of that view into a separate view & viewModel (the child). The child view is defined as a UserControl.
The issue I'm having is how to set the DataContext of the child view (the UserControl). My parent ViewModel has a property which exposes the child ViewModel, like so:
class ParentViewModel: INotifyPropertyChanged
{
public ChildViewModel childViewModel { get; set; }
//...
}
In the XAML for my parent view (which has it's DataContext set to the ParentViewModel), I try to set the DataContext of the child view as follows:
<views:ChildView
x:Name="ChildView"
DataContext="{Binding childViewModel}"/>
However, this doesn't work. The DataContext of the child view is set to the same DataContext as the parent view (i.e. the ParentViewModel), as if I wasn't setting it at all. I also tried setting the DataContext in the child view itself, which also doesn't work:
<UserControl x:Class="DietRecorder.Client.View.ChildView"
DataContext="childViewModel"
I have found a couple of ways around this. In the child view, I can bind everything by including the ChildViewModel in the path:
<SomeControl Visibility="{Binding Path=childViewModel.IsVisible}">
but I don't want the child view to have this level of awareness of the hierarchy. Setting the DataContext in code also works - however, I have to do this after showing the parent view, otherwise the DataContext just gets overwritten when I call Show():
parentView.Show();
parentView.ChildView.DataContext = parentViewModel.childViewModel;
This code also makes me feel uneasy, what with the LOD violation and all.
It's just the DataContext that seems to be the problem - I can bind other things in the child, for example I tried binding the FontSize to an int property just to test it:
<views:ChildView
x:Name="ChildView"
FontSize="{Binding Path=someVal}"/>
And that works fine.
But I'm sure binding the DataContext should work - I've seen similar examples of this kind of thing. Have I missed something obvious here? Is there a reason this won't work? Is there a spelling mistake somewhere? (I renamed things for your benefit so you won't be able to help me there anyway).
Any thoughts welcome.
Edit
Reviewing this code again, it seems I've made a mistake somewhere, as the following XAML in the parent view does now appear to work:
<views:ChildView
x:Name="ChildView"
DataContext="{Binding childViewModel}"/>
I'm not sure why I couldn't get it to work originally, or what I might have changed to make it work. Perhaps it was the INotifyPropertyChanged issue like one of the answers suggests. Oh well, onwards and upwards..
I suspect it is because the childViewModel property does not raise the PropertyChanged event. When the binding is evaluated, it is possible that this property is null (in which case the DataContext will just fall back to the parent's one). When the childViewModel is instantiated later, no PropertyChanged event is raised, and the binding is never informed that there is now a DataContext.
Try to raise PropertyChanged event in the childViewModel property.
Cheers, Laurent
This is not an answer to the question, but might help others in the same circumstances.
I hit exactly this problem and found that the
parentView.ChildView.DataContext = parentViewModel.childViewModel;
approach worked (though I found that it worked before doing Show()), but had the same qualms about it as the original questioner so tried the
DataContext="{Binding ElementName=_topLevel, Path=DataContext.childViewModel}"
approach, which also seemed to work. But then I tried going back to the original code and original XAML again, and now it suddenly also worked. This mirrors the original questioner's behaviour where the author thought they had made a mistake somewhere as the XAML seemed to start working for no obvious reason.
The only change I can see is that Visual Studio is now showing sample data in the UserControl at design time, so it has cached some sample data somewhere, and that seems to make it work. I am not sure which of the two changes made this occur, unfortunately.
The appearance of sample data makes me wonder if the issue is connected with the use of d:DataContext, which I have in the parent and child XAML files, but that is just speculation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With