Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF databinding with a user control

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?

like image 534
dan Avatar asked Feb 12 '10 20:02

dan


People also ask

What is user control in WPF?

User controls, in WPF represented by the UserControl class, is the concept of grouping markup and code into a reusable container, so that the same interface, with the same functionality, can be used in several different places and even across several applications.

How does data binding work in WPF?

Data binding is a mechanism in WPF applications that provides a simple and easy way for Windows Runtime apps to display and interact with data. In this mechanism, the management of data is entirely separated from the way data. Data binding allows the flow of data between UI elements and data object on user interface.

What is element binding in WPF?

Data binding in Windows Presentation Foundation (WPF) provides a simple and consistent way for apps to present and interact with data. Elements can be bound to data from different kinds of data sources in the form of . NET objects and XML.


1 Answers

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.

like image 87
levanovd Avatar answered Sep 22 '22 16:09

levanovd