views:

52

answers:

4

Hi everyone, Just learning WPF databinding and have a gap in my understanding. I've seen a few similar questions on StackOverflow, but I'm still struggling in determining what I have done wrong.

I have a simple Person class with a Firstname and Surname property (standard CLR properties). I also have a standard CLR property on my Window class that exposes an instance of Person.

I've then got some XAML, with two methods of binding. The first works, the second doesn't. Can anybody help me to understand why the second method fails? There's no binding error message in the Output log.

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="Window1" Height="300" Width="300"
    DataContext="{Binding RelativeSource={RelativeSource Self}, Path=MyPerson}">
<StackPanel>
    <Label>My Person</Label>
    <WrapPanel>
        <Label>First Name:</Label>
        <Label Content="{Binding RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}, Path=MyPerson.FirstName}"></Label>
    </WrapPanel>
    <WrapPanel>
        <Label>Last Name:</Label>
        <Label Content="{Binding MyPerson.Surname}"></Label>
    </WrapPanel>
</StackPanel>

Edit: Ok, thanks so far. I've changed the second expression to:

<Label Content="{Binding Surname}"></Label>

I still can't get it to work though!

+1  A: 

For the second method to work, you just need

<Label Content="{Binding Surname}"/>

because you've already set the DataContext to the person in the window element at the top.

The top datacontext works for me, however the binding doesn't show up in the designer unless I have a separate class containing the data. For this to work you would then do something like this:

<Window.Resources>
    <local:BindingClass x:Key="bindingClass"/>
</Window.Resources>
<Grid DataContext="{StaticResource bindingClass.MyPerson}">
    <Label Content="{Binding Surname}"/>
</Grid>

This requires you to create a separate class (called BindingClass in this case) that contains the MyPerson property.

I think this works in the designer because I'm explicitly creating a new instance of the class in xaml.

Dave Arkell
Ah, thanks I see that. I think that's just a typo from when I was changing things back and forward trying to get it to work. If I remove the MyPerson qualifier it still doesn't work.
nukefusion
What about {Binding Path=Surname}
Adam Driscoll
Tried that too. I think the problem lies somewhere in the way I've declared the DataContext. Just not sure what....
nukefusion
+1  A: 

Firstly you won't see binding errors most of the time unless you set up diagnostics on that binding. The reason the second one doesn't work is that you have set the DataContext to be MyPerson. Since that is the DataContext all you need to do is bind to the property Surname. The way you have it right now its trying to call MyPerson.MyPerson.Surname.

Craig Suchanec
A: 

Another simple way to handle that first binding would be to give your Window a name and reference it by ElementName in the binding:

<Window x:Class="WpfApplication1.Window1"
    Name="MyWindow"
    ...>
<StackPanel>
    <Label>My Person</Label>
    <WrapPanel>
        <Label>First Name:</Label>
        <Label Content="{Binding Path=MyPerson.FirstName, ElementName=MyWindow}"></Label>
    </WrapPanel>
    <WrapPanel>
        <Label>Last Name:</Label>
        <Label Content="{Binding MyPerson.Surname}"></Label>
    </WrapPanel>
</StackPanel>
MojoFilter
+1  A: 

Ok, I've discovered the problem here. New to WPF, so it took me a while to figure it out.

In the code behind I'm setting the MyPerson property after the call to InitializeComponent.

The first method I used works because the Window is initialised and the MyPerson property set by the time the label is initialised and it's databinding expression evaluated.

The second method doesn't work because the MyPerson property hasn't been set when the Window and associated DataContext get initialised.

Simple when you know how!

nukefusion