WPF databinding with a user control

data-bindinguser-controlswpf

I have a wpf user control, which exposes a single custom dependency property. Inside the user control, a textblock binds to the value of the dp. This databinding works in all scenarios except when the data source is an object.

The minimal code necessary to reproduce this is:

this is the main part of the user control

<StackPanel Orientation="Horizontal">
    <TextBlock Text="**SimpleUC** UCValue: "/>
    <TextBlock Text="{Binding UCValue}"/>
</StackPanel>

and the user control code behind:

    public SimpleUC()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    public string UCValue
    {
        get { return (string)GetValue(UCValueProperty); }
        set { SetValue(UCValueProperty, value); }
    }

    public static readonly DependencyProperty UCValueProperty =
        DependencyProperty.Register("UCValue", typeof(string), typeof(SimpleUC), new UIPropertyMetadata("value not set"));

this is the test window. I imported my project xml namespace as "custom"

<Window.Resources>
    <Style TargetType="{x:Type StackPanel}">
        <Setter Property="Margin" Value="20"/>
    </Style>
</Window.Resources>
<StackPanel>
    <StackPanel>
        <TextBlock Text="This fails to bind:"/>
        <custom:SimpleUC UCValue="{Binding SomeData}"/> 
    </StackPanel>
    <StackPanel>
        <TextBlock>The same binding on a regular control like Label</TextBlock>
        <Label Content="{Binding SomeData}"/>
    </StackPanel>
    <Slider x:Name="sld" />
    <StackPanel>
        <TextBlock>However, binding the UC to another element value, like a slider works</TextBlock>
        <custom:SimpleUC UCValue="{Binding ElementName=sld,Path=Value}"/>
    </StackPanel>
</StackPanel>

and the test window code behind is:

public TestWindow()
{
    InitializeComponent();
    this.DataContext = this;
}

//property to bind to
public string SomeData { get { return "Hello S.O."; } } 

When I turn on the diagnostic tracing on the TestWindow, it spits out the error "BindingExpression path error:
'SomeData' property not found on 'object' ''SimpleUC' (Name='')' ... "
The binding expression is the same as the one I used in the neighboring label and it worked fine. This behavior seems really bizarre to me. Can anyone shed some light?

Best Answer

You set DataContext of your SimpleUC to itself here

public SimpleUC()
{
    InitializeComponent();
    this.DataContext = this; // wrong way!
}

so when you use binding here

<custom:SimpleUC UCValue="{Binding SomeData}"/>

it searches property SomeData in control's data context which is set to this object because code in SimpleUC constructor overrides value of DataContext and it is not set to TestWindow object anymore as you expected. That's why your solution works - it doesn't affect DataContext which is inherited from window. Also you can keep this.DataContext = this; but set element where to search property explicitly like this (skipped irrelevant)

<Window ... Name="wnd1">
    <custom:SimpleUC UCValue="{Binding SomeData, ElementName=wnd1}"/>
...

But my oppinion is that your variant from the answer looks more convenient to me, setting data context to this is not very good practice.

Hope it helps.

Related Topic