How to correctly bind to a dependency property of a usercontrol in a MVVM framework

That is one of the many reasons you should never set the DataContext directly from the UserControl itself.

When you do so, you can no longer use any other DataContext with it because the UserControl’s DataContext is hardcoded to an instance that only the UserControl has access to, which kind of defeats one of WPF’s biggest advantages of having separate UI and data layers.

There are two main ways of using UserControls in WPF

  1. A standalone UserControl that can be used anywhere without a specific DataContext being required.

    This type of UserControl normally exposes DependencyProperties for any values it needs, and would be used like this:

    <v:InkStringView TextInControl="{Binding SomeValue}" />
    

    Typical examples I can think of would be anything generic such as a Calendar control or Popup control.

  2. A UserControl that is meant to be used with a specific Model or ViewModel only.

    These UserControls are far more common for me, and is probably what you are looking for in your case. An example of how I would use such a UserControl would be this:

    <v:InkStringView DataContext="{Binding MyInkStringViewModelProperty}" />
    

    Or more frequently, it would be used with an implicit DataTemplate. An implicit DataTemplate is a DataTemplate with a DataType and no Key, and WPF will automatically use this template anytime it wants to render an object of the specified type.

    <Window.Resources>
        <DataTemplate DataType="{x:Type m:InkStringViewModel}">
            <v:InkStringView />
        </DataTemplate>
    <Window.Resources>
    
    <!-- Binding to a single ViewModel -->
    <ContentPresenter Content="{Binding MyInkStringViewModelProperty}" />
    
    <!-- Binding to a collection of ViewModels -->
    <ItemsControl ItemsSource="{Binding MyCollectionOfInkStringViewModels}" />
    

    No ContentPresenter.ItemTemplate or ItemsControl.ItemTemplate is needed when using this method.

Don’t mix these two methods up, it doesn’t go well 🙂


But anyways, to explain your specific problem in a bit more detail

When you create your UserControl like this

<v:InkStringView TextInControl="{Binding text}"  />

you are basically saying

var vw = new InkStringView()
vw.TextInControl = vw.DataContext.text;

vw.DataContext is not specified anywhere in the XAML, so it gets inherited from the parent item, which results in

vw.DataContext = Strings[x];

so your binding that sets TextInControl = vw.DataContext.text is valid and resolves just fine at runtime.

However when you run this in your UserControl constructor

this.DataContext = new InkStringViewModel();

the DataContext is set to a value, so no longer gets automatically inherited from the parent.

So now the code that gets run looks like this:

var vw = new InkStringView()
vw.DataContext = new InkStringViewModel();
vw.TextInControl = vw.DataContext.text;

and naturally, InkStringViewModel does not have a property called text, so the binding fails at runtime.

Leave a Comment