Reputation: 5023
I'm writing a value input control can be used everywhere. The control itself has a view model which set to its DataContext as usual. But when I use the control in a parent control like:
<UserControl x:Class="X.Y.Z.ParentControl">
...
<local:ValueInput Value="{Binding Path=MyValue}" />
...
</UserControl>
I'm going to bind the MyValue
property of ParentControl
's DataContext
to the ValueInput
control, but WPF tell me it cannot find the MyValue
property in ValueInputViewModel
class, which is the view model of ValueInput
control itself. Why WPF is looking for the value from child's DataContext
?
I just want to write a control which can be used like this:
<telerik:RadNumericUpDown Value="{Binding Path=NumberValue}" />
The NumberValue
property is defined in in the parent's DataContext
, not in the control's. This pattern works for teleriks control but not for my control.
What should I do?
Upvotes: 0
Views: 1330
Reputation: 5023
My friend told me not to use DataContext
as the view model in a standalone control since DataContext would be easily overridden - define a ViewModel
property and bind in the XAML could solve the problem. Here's an example:
View model class:
public class MyValueInputViewModel
{
public string MyText { get; set; }
}
Code behind:
public partial class MyValueInput : UserControl
{
public MyValueInput()
{
InitializeComponent();
this.ViewModel = new MyValueInputViewModel
{
MyText = "Default Text"
};
}
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(MyValueInputViewModel), typeof(MyValueInput));
public MyValueInputViewModel ViewModel
{
get
{
return (MyValueInputViewModel)this.GetValue(ViewModelProperty);
}
private set
{
this.SetValue(ViewModelProperty, value);
}
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(string), typeof(MyValueInput), new PropertyMetadata(OnValuePropertyChanged));
private static void OnValuePropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
{
var input = (MyValueInput)o;
input.ViewModel.MyText = input.Value;
}
public string Value
{
get { return (string)this.GetValue(ValueProperty); }
set { this.SetValue(ValueProperty, value); }
}
}
XAML:
<UserControl x:Class="..." x:Name="Self" ...>
<Grid>
<TextBox Text="{Binding ViewModel.MyText, ElementName=Self, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</UserControl>
Upvotes: 0
Reputation: 30698
For any FrameworkElement, there can be only 1 DataContext.
If UserControl has its own DataContext, it cannot use parent's DataContext.
However you can walk up to parent and get its DataContext (each time you need to reference Parent's DataContext) using RelativeSource
Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}, Path=DataContext.NumberValue}"
For this example to work, Parent (root at any level) should be Window. If it is a UserControl,
Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type UserControl}}, Path=DataContext.NumberValue}"
The code is from this link provided by fiq
Upvotes: 1