katit
katit

Reputation: 17915

How do I create UserControl that binds "normally"?

I will explain what I mean.

Let's say I wrapped TextBox into UserControl and expose property Id In order to bind to this property, it has to be Dependency property. Fine, here we go(notice stupid dance with OnIdChanged calls property setter so we get INotifyPropertyChanged working):

public static readonly DependencyProperty IdProperty =
            DependencyProperty.RegisterAttached("Id", typeof(string), typeof(MyTextBox), new PropertyMetadata(OnIdChanged));

public string Id
        {
            get
            {
                return (string)GetValue(IdProperty);
            }

            set
            {
                this.SetValue(IdProperty, value);
                this.OnPropertyChanged("Id");
            }
        }

private static void OnIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as Lookup).Id = e.NewValue as string;
        }

So, this seems like all I need. I create another User control. Drop MyTextBox on it:

    <Lookup:MyTextBox Id="{Binding Source={StaticResource DataContextProxy}, Path=DataSource.CurrentItem.DeviceId, Mode=TwoWay, NotifyOnValidationError=True}"/>

As you see - I had to use DataContextProxy. To be honest, it's little bit of magic for me, I did it once and tried it now when regular way wasn't binding. How should I code my user control so I can bind to it like so?

        <Lookup:MyTextBox Id="{Binding Path=CurrentItem.DeviceId, Mode=TwoWay, NotifyOnValidationError=True}"/>

This is how I can bind TextBox next to my custom one and it works as expected. What is the secret?

EDIT

Below is 2 screenshots. First one shows how what I get as a source when I bind to Lookup control (custom UserControl) - points to SELF

Second one - next field in my XAML - is regular textbox, binds to same CurrentItem but it sources from my ViewModel enter image description here enter image description here

EDIT 2

I figured why DataContext was pointing to UserControl itself. I figured why but do not understand why..

In my UserControl (Lookup) code behind after initializiation I set this.DataContext = this so inside control it binds to internal properties. Somehow it propogated to parent ViewModel. After I changed this code to LayoutRoot.DataContext = this - issue resolved. But I don't understand why it behaves like this and I still can't get good property routing through..

Upvotes: 1

Views: 285

Answers (1)

ColinE
ColinE

Reputation: 70142

I covered this issue in a blog post which I wrote some time ago. If you set the DataContext of the UserControl to itself, you can no longer place it within another UserControl or Window and expect it to inherit the DataContext of its parent. This means that you cannot just sit it in your view and specify bindings to your view model. The reasons for this is that you have blocked inheritence of your ViewModel DataContext. Any properties exposed by your UserControl will have their binding Source set to the UserControl.

The solution is to set DataContext of some element within the UserControl to the UserControl itself. Most typically you would set the immediate child of the UserControl.

Upvotes: 2

Related Questions