views:

266

answers:

2

Hi!

I'm fairly new to WPF and I have some problems getting databinding to work as I want. I've written a user control which contains a TextBox whose Text-Property I want to bind to a property of my UserControl, which I want to bind again to something else.

What am I missing?

XAML

<!-- User Control -->
<TextBox Text="{Binding Path=TheText}" />

<!-- Window -->
<WpfApplication1:SomeControl TheText="{Binding Path=MyStringProp}" />

C#

// User Control ----

public partial class SomeControl : UserControl
{
    public DependencyProperty TheTextProperty = DependencyProperty
        .Register("TheText", typeof (string), typeof (SomeControl));

    public string TheText
    {
        get
        {
            return (string)GetValue(TheTextProperty);
        }
        set
        {
            SetValue(TheTextProperty, value);
        }
    }

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

// Window ----

public partial class Window1 : Window
{
    private readonly MyClass _myClass;

    public Window1()
    {
        InitializeComponent();

        _myClass = new MyClass();
        _myClass.MyStringProp = "Hallo Welt";

        DataContext = _myClass;
    }
}

public class MyClass// : DependencyObject
{
//  public static DependencyProperty MyStringPropProperty = DependencyProperty
//      .Register("MyStringProp", typeof (string), typeof (MyClass));

    public string MyStringProp { get; set; }
//  {
//      get { return (string)GetValue(MyStringPropProperty); }
//      set { SetValue(MyStringPropProperty, value); }
//  }
}

Best Regards
Oliver Hanappi

PS: I've tried to implement the INotifyPropertyChanged interface on my user control, but it did not help.

+1  A: 

You want to bind the Text property of your TextBox back to the TheText property of the UserControl it lives in, right? So you need to tell the binding where the property lives. There's a couple of ways to do this (you can do it with a RelativeSource using FindAncestor) but the easiest way is to give the UserControl a "name" in the XAML and bind using element binding:

<UserControl ...
    x:Name="me" />
    <TextBox Text="{Binding TheText,ElementName=me}" />
</UserControl>

Now your TextBox will reflect the value you've assigned (or bound) to your "SomeControl.TheText" property - you needn't change any of your other code, although you'll probably want to implement INotifyPropertyChanged on your underlying MyClass object so that the binding knows when the property has changed.

Matt Hamilton
I'm setting the DataContext of the UserControl to 'this' in its constructor, therefore the Binding knows which property is meant. The value of the textbox is also bound correctly to the UserControl's property, but it seems that the databinding gets lost in my Windows.
Oliver Hanappi
Ah right - yeah, I've seen people try that. I think that's what confuses the bindings up at the Window level. Doing it with an Element Binding eliminates the need for that.
Matt Hamilton
Okay, I solved it now. The problem was that I need to set the binding mode to TwoWay in my window. Thank you for your help!
Oliver Hanappi
+1  A: 

Matt has provided a solution to your problem. Here is a little more explanation and a hint to stop this problem in future.

As SomeControl.DataContext is set in the SomeControl constructor, the window's binding TheText="{Binding Path=MyStringProp}" has a Source of type SomeControl, not MyClass as you intended.

Any bindings that fail at runtime cause debug messages to be logged to the output panel of Visual Studio. In this case, you would have seen that no such property 'MyStringProp' exists on object of type 'SomeControl', which should have raised your suspicions.

I think everyone finds WPF data binding takes some time to learn and especially to debug, but persevere. Data binding in WPF is really fantastic, and I still get a kick out of knowing how easily it makes the data on my UIs stay up to date.

Drew Noakes
Thank you for your advice;)
Oliver Hanappi