'WPF nested data binding to control - why does it not work
I have searched google and stackoverflow alot to find a answer to my question without any luck. I find the solution to the problem. Ex:
Data Binding to Nested Properties?
But i already know the solution. I want to know WHY wpf doesn't support nested/dotted data bindings on controls.
The solution is to set the DataContext of the parent control to the parent data object in my case my ViewModel property on my controller/window datacontext. So i could set the DataContext of my grid and my code would work if i change my TextBox binding to only use the Name property.
Another solution is to explicity set the UpdateSourceTrigger on my TextBox and keep my nested data binding on the TextBox control like below.
But why? Why doesn't WPF support nested binding like i do below without setting the UpdateSourceTrigger explicit? I would like to know that :).
I have this textbox control:
<Window>
<Grid>
<StackPanel>
<Label Content="Name" FontWeight="Bold"/>
<TextBox x:Name="NameTextBox" Text="{Binding Path=CreateEditAssetViewModel.Name, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" Width="475" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalContentAlignment="Stretch" Margin="0, 5" />
</StackPanel>
</Grid>
</Window>
My window datacontext is bound like this:
var createEditWindow = new CreateEditWindow();
var createEditController = new CreateEditWindowController();
createEditWindow.DataContext = createEditController;
createEditWindow.Show();
My controller looks like this:
public class CreateEditWindowController : ViewModelBase, ICreateEditWindowController
{
private ICreateEditWindowViewModel _createEditWindowViewModel;
public ICreateEditWindowViewModel CreateEditAssetViewModel
{
get { return _createEditWindowViewModel; }
set
{
if (_createEditWindowViewModel == value) return;
_createEditWindowViewModel = value;
OnPropertyChanged(nameof(CreateEditAssetViewModel));
}
}
}
My ViewModel with the Name property that the textbox control binds to looks like this:
public class CreateEditWindowViewModel : ViewModelBase, ICreateEditWindowViewModel
{
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name == value) return;
_name = value;
OnPropertyChanged(nameof(Name));
}
}
}
And my ViewModelBase:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Solution 1:[1]
Here's https://msdn.microsoft.com/en-us/library/ms752347%28v=vs.100%29.aspx
Look at the Providing Visual Feedback section, it's a Trigger binding property but they used a dotted property
Same for collection views section sub -> How to create a view
They used a dotted property on Application object.
Look at your output view when you are debugging your GUI, if WPF does not find a property in a Data context, it will throw a log !
Solution 2:[2]
WPF do support dotted property, but yes you always have to specify your control data context.
Solution 3:[3]
I think wpf does support nested/dotted data bindings. I have posted an answer in the link you mentioned. where
<TextBox Text="{Binding Path=MyModel.MyCounter.CurrentNumber}"/>
binding is just working fine. Not here but I've done many examples where nested properties needs to bound to some control property. In fact WPF has to support such type of binding else providing separate DataContext to separate controls would be much difficult work.
Some examples:
1.
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type iDP:DataRecordCellArea}},Path=Record.DataItem.IsParentRow}" Value="true">
<Setter Property="IsEnabled" Value="False"/>
2.
<CheckBox HorizontalAlignment="Center"
VerticalAlignment="Center"
Cursor="Arrow"
IsChecked="{Binding Path=DataItem.IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type view:DeleteSubLocationsView}},Path=DataContext.ImportWizardViewModel.ContextObject.IsRQSReviewFieldChecked}">
Solution 4:[4]
One thing you have to watch out for in WPF is to make your properties "Dependency Properties". This helps with notifying for value changes:
C#
public static readonly DependencyProperty SelectedNodeProperty = DependencyProperty.Register(nameof(SelectedNode), typeof(FileSystemEntry), typeof(MainWindow));
public FileSystemEntry SelectedNode
{
get => (FileSystemEntry)GetValue(SelectedNodeProperty);
set => SetValue(SelectedNodeProperty, value);
}
XAML:
<TextBox DataContext="{Binding ElementName=MainAppWindow,Path=SelectedNode}" Text="{Binding Name,Mode=OneWay}"/>
<TextBox Text="{Binding ElementName=MainAppWindow,Mode=OneWay,Path=SelectedNode.Name}"/>
Now, if SelectedNode
changes value, the UI will be updated.
I hope this helps.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | A.Caillet |
Solution 2 | A.Caillet |
Solution 3 | Community |
Solution 4 | NoOne |