Reputation: 275
i Have ViewModel
public class VM: DependencyObject, INotifyPropertyChanged
{
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(VM), new PropertyMetadata(""));
public int Length
{
get
{
return Text != null ? Text.Length : 0;
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
and View for it
<UserControl.DataContext>
<local:VM Text="{Binding ControlText, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"/>
</UserControl.DataContext>
<StackPanel>
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text="{Binding Length}"/>
</StackPanel>
yes, view has also dependency property in code behind
public string ControlText
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("ControlText", typeof(string), typeof(Writer), new PropertyMetadata(""));
I got error on Output Log
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.UserControl', AncestorLevel='1''. BindingExpression:Path=ControlText; DataItem=null; target element is 'VM' (HashCode=21019086); target property is 'Text' (type 'String')
when this technic works, i will be have tools to construct my viewmodel. maybe anyone know how to bind this view property to viewmodel property or know technic how to do it properly :)
Upvotes: 0
Views: 3021
Reputation: 69959
You seem to be somewhat confused with a few things. If you want to set your view model as the UserControl.DataContext
in XAML, that is ok, but you don't data bind to controls from there:
<UserControl.DataContext>
<local:VM />
</UserControl.DataContext>
Next, if the view model is set as the UserControl.DataContext
, then you can access its properties from the XAML in the UserControl
like this:
<StackPanel>
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text="{Binding Length}"/>
</StackPanel>
Now if you want to access the ControlText
property from the XAML, then that is when you need to use the RelativeSource Binding
. However, notice how you should reference your UserControl
, by its name/type and not using UserControl
because as your error says, there is no ControlText
property defined in UserControl
. Try this:
<StackPanel>
<TextBox Text="{Binding ControlText, RelativeSource={RelativeSource
AncestorType={x:Type local:YourUserControl}} />
<TextBlock Text="{Binding Length}"/>
</StackPanel>
Finally, if you want to data bind to the ControlText
property of your control from outside the control, then you could do that like this:
<local:YourUserControl ControlText="{Binding SomeStringProperty}" />
UPDATE >>>
When using MVVM, we generally don't try to pass data from one data source through a UIElement
to another data source. Instead, we prefer to pass the data from one data item to another data item. Your problem is that you are instantiating your view model in the view... instead, instantiate it in a parent view model and pass in whatever values you want and then set it as the UserControl.DataContext
property value from outside the control in the parent view:
<local:YourUserControl DataContext="{Binding YourChildViewModelPropertyInParentVM}" />
Once you have the correct values in the view model, then you shouldn't need the ControlText
property.
Upvotes: 1
Reputation: 81253
If you declare DataContext
in XAML, it will be initialized at time of XAML loading. Also, VM
doesn't lie in Visual Tree as that of UserControl so RelativeSource
can't work here.
But you can do that in code behind by setting DataContext from UserControl's constructor and do binding there itself:
public MainWindow()
{
InitializeComponent();
VM viewModel = new VM();
DataContext = viewModel;
Binding binding = new Binding("ControlText") { Source = this };
BindingOperations.SetBinding(viewModel, VM.TextProperty, binding);
}
Upvotes: 0