Question

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

No correct solution

OTHER TIPS

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.

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);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top