tags:

views:

797

answers:

2

Say I have a very simple UserControl that - for all intents and purposes - is nothing more than TextBox:

public partial class FooBox : UserControl
{
    public static readonly DependencyProperty FooTextProperty =
        DependencyProperty.Register("FooText", typeof(string), typeof(FooBox));

    public FooBox()
    {
        InitializeComponent();
    }

    public string FooText
    {
        get { return textBlock.Text; }
        set { textBlock.Text = value; }
    }
}

<UserControl x:Class="Namespace.FooBox"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <Grid>
        <TextBlock x:Name="textBlock" />
    </Grid>
</UserControl>

On the form it's declared as:

<local:FooBox FooText="{Binding Name}" />

The form's DataContext is set to an object that has a Name property. But this is not working for me. What am I missing?

+1  A: 

The "get" and "set" parts of a property declaration in a DependencyProperty aren't actually called by the databinding system of WPF - they're there essentially to satisfy the compiler only.

Instead, change your property declaration to look like this:

public string FooText
{
    get { return (string)GetValue(FooTextProperty); }
    set { SetValue(FooTextProperty, value); }
}

... and your XAML to:

<UserControl ...
    x:Name="me">
    <Grid>
        <TextBlock Text="{Binding FooText,ElementName=me}" />
    </Grid>
</UserControl>

Now your TextBox.Text simply binds directly to the "FooText" property, so you can in turn bind the FooText property to "Name" just like you're currently doing.

Another way is to bind TextBlock.Text to a RelativeSource binding that finds the FooText property on the first ancestor of type "FooBox", but I've found that this is more complex than just giving the control an internal x:Name and using element binding.

Matt Hamilton
I'll vote you up since you helped me get close to what I was missing. But my test case here was too simple to expose the real problem. See my answer.
xanadont
A: 

Turns out the real problem is I was expecting the WPF framework to set my public property whereupon my code would respond to the changes and render according to the new value. Not so. What WPF does is call SetValue() directly and completely circumvents the public property. What I had to do was receive property change notifications using DependencyPropertyDescriptor.AddValueChanged and respond to that. It looks something like (inside the ctor):

var dpd = DependencyPropertyDescriptor
    .FromProperty(MyDependencyProperty, typeof(MyClass));
dpd.AddValueChanged(this, (sender, args) =>
{
    // Do my updating.
});
xanadont
Also note that the Register method for dependency properties has overloads that can accept event handlers that are fired whenever the property is changing or has changed. That might be a place to put the logic you have there.
Matt Hamilton