Search code examples
c#wpfdata-binding

Why databinding doesn't work on UserControl?


I'm trying to make a simple user control in WPF/C#. Everything seems to work except for databinding to property in datacontext.

I tried making extremely simplified example to see better what I'm doing wrong. I'm quite new to WPF in general, so I think I'm doing Dependency Properties wrong somehow. Might be in the binding itself, but that works normally for other elements, like TextBox. This seemed to be similiar problem, but answer didn't seem to work in my case: Why DataBinding is not propagating to UserControl

MainWindow.xaml (root tag omitted)

    <StackPanel>
        <local:UserControl1 TextToDisplay="{Binding BoundableText}" />
        <TextBlock Text="{Binding BoundableText}" />
    </StackPanel>

UserControl1.xaml (root tag omitted)

    <TextBlock Text="{Binding TextToDisplay}" />

MainWindow.xaml.cs:

using System.Windows;
using System.Windows.Controls;

namespace UserControlTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
            BoundableText = "This text is bound";
        }

        public string BoundableText { get; set; }
    }

    public partial class UserControl1 : UserControl
    {
        public static readonly DependencyProperty TextToDisplayProperty = 
            DependencyProperty.Register(nameof(TextToDisplay), typeof(string), typeof(UserControl1), new PropertyMetadata("Default text"));
        public string TextToDisplay
        {
            get => (string)GetValue(TextToDisplayProperty);
            set => SetValue(TextToDisplayProperty, value);
        }

        public UserControl1()
        {
            InitializeComponent();
            DataContext = this;
        }
    }
}

The 2 elements should be also identical in content, displaying text which is set in code-behind ("This text is bound"). TextBox works as it should, but UserControl1 has just the default text. What makes this case different from the first? Can I get it to work the same? Note: I also tried to bind to other element's property, that works nicely. Also binding from code-behind works. However, this should be possible from xaml itself. In actual use case the control will be in a DataTemplate.


Solution

  • Don't set the DataContext of the UserControl to itself in the constructor:

    DataContext = this;
    

    Then it won't inherit the DataContext from the parent window.

    To bind to the TextToDisplay dependency property in the UserControl, you could use a RelativeSource:

    <TextBlock Text="{Binding TextToDisplay, RelativeSource={RelativeSource AncestorType=UserControl}}" />