1

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.

aXu_AP
  • 63
  • 6
  • You need to implement INotifyPropertyChanged, have a look here https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-implement-property-change-notification – Alfie May 24 '19 at 13:58
  • I have tried, no difference. If I understand it right, dependency property takes care of notifying changes? I'm not sure, though. – aXu_AP May 24 '19 at 14:02
  • One way to test if that is the issue is to put `InitializeComponent();` at the end of the constructor - That way `BoundableText` will be set before the `TextBlock` is rendered – Alfie May 24 '19 at 14:07
  • You need to set a name on a root element of your UserControl then set the dataContext of that element, NOT the entire UserControl! Then you will have Binding. – XAMlMAX May 24 '19 at 14:07
  • @XAMlMAX that should't matter as in the constructor there is `DataContext = this;` – Alfie May 24 '19 at 14:08
  • That WILL MATTER! As that's where you will get the values from!!! – XAMlMAX May 24 '19 at 14:09
  • @XAMlMAX It's correct that `DataContext = this;` breaks bindings from the parent, but setting DataContext to a root element inside the UserControl isn't a very good idea. It'll just break things when he starts using UserControls properly, with a viewmodel. If there's no viewmodel, it shouldn't really be a usercontrol; it should be a Control subclass with a Template set via a Style. In a UserControl, RelativeSource bindings are the best way to bind XAML in the UserControl to properties of the UserControl class itself. – 15ee8f99-57ff-4f92-890c-b56153 May 24 '19 at 14:15
  • @EdPlunkett I agree with the usage of UC vs Controls. This could easily be a `PlaceholderTextBox` for all I know. But if the OP is asking why Binding isn't working I am going to say that it's the `this.DataContext = this;` line will cause it. The idea behind setting DataContext of a root element was to show why the Data Binding doesn't work. I hope this makes sense. – XAMlMAX May 24 '19 at 14:25

1 Answers1

5

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}}" />
mm8
  • 163,881
  • 10
  • 57
  • 88
  • Thank you for helping! Seems to work in test case, but I still have some problems within actual use case. I think I'll sort it out however. If I can't make it, I'll post more specific question... – aXu_AP May 24 '19 at 14:22