EngineerSpock
EngineerSpock

Reputation: 2675

Binding from XAML doesn't work

When I create binding in code like in the following example, everything works fine:

 public partial class BindingToCustomType : Window {
    public Craftsman Craftsman { get; set; }
    public BindingToCustomType() {
        InitializeComponent();

        Craftsman = new Craftsman() {Age = 45, LastName = "Joe", Name = "Grok"};

        Binding binding = new Binding();  
        binding.Source = Craftsman;    
        binding.Path = new PropertyPath("Name");   
        NameBlock.SetBinding(TextBlock.TextProperty, binding);
    }

XAML:

<Window x:Class="DataBinding.BindingToCustomType"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    x:Name="Window"
    Title="BindingToCustomType">

    <TextBlock x:Name="NameBlock" Width="120" FontSize="16" Foreground="Red" />
</Window>

When I try to set that binding purely in XAML, it doesn't work:

<TextBlock x:Name="NameBlock" Width="120" FontSize="16" Foreground="Red" Text="{Binding Source=Craftsman, Path=Name, Mode=OneWay}"/>

Even if I set data context on the Window element, it doesn't work:

  DataContext="{Binding RelativeSource={RelativeSource Self}}"

I don't want the solution to this problem. I want to understand WHY this doesn't work in XAML either with DataContext, or without.

Upvotes: 0

Views: 2880

Answers (3)

AnjumSKhan
AnjumSKhan

Reputation: 9827

There are a couple of things to take note of.

  1. You are creating the craftsman object after InitializeComponent(), so your Window doesnt know if it has changed. Implement INotifyPropertyChanged in your window class for notification of craftsman. Or, create your object before InitializeComponent(). So, everything would be available right before Window is created, so first time binding will work.

  2. In your first case, do this

            Craftsman = new Craftsman() { Age = 45, LastName = "Joe", Name = "Grok" };
    
            Binding binding = new Binding();
            binding.Source = TheCraftsman;
            binding.Path = new PropertyPath("Name");
            NameBlock.SetBinding(TextBlock.TextProperty, binding);
    
            Craftsman = new Craftsman() { Age = 45, LastName = "Joe", Name = "NewGrok" };
    

    TextBlock will keep showing Grok as value.

  3. Your path is wrong, it should be Text="{Binding Path=TheCraftsman.Name, Mode=OneWay}", Source is for values coming from resources/property-coming-from-element etc.

Conclusion : It's related to InitilizeComponent(), change notification, and your path.

Upvotes: -1

Janne Matikainen
Janne Matikainen

Reputation: 5121

If you would take a look at your Output in visual studio you would find the following line in your xaml binding.

System.Windows.Data Error: 40 : BindingExpression path error: 'Name' property not found on 'object' ''String' (HashCode=538009415)'.
BindingExpression:Path=Name; DataItem='String' (HashCode=538009415); target element is 'TextBlock' (Name='NameBlock'); target property is 'Text' (type 'String')

This means that the

Text="{Binding Source=Craftsman, Path=Name, Mode=OneWay}"

Is actually binding to a string literal 'Craftsman' and not the property of your window.

To get your bindings work you would need to set the datacontext for the window

DataContext="{Binding RelativeSource={RelativeSource Self}}"

And your binding could be either (this is stupid)

Text="{Binding Path=DataContext.Craftsman.Name, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"

Or very simply

Text="{Binding Craftsman.Name, Mode=OneWay}"

You could set a resource for the window

<Window.Resources>
    <wpfApplication2:Craftsman x:Key="CraftsmanResource" Age="45" LastName="Joe" Name="Grok"/>
</Window.Resources>

And then use the binding

Text="{Binding Path=Name, Mode=OneWay, Source={StaticResource CraftsmanResource}}"

Upvotes: 1

toadflakz
toadflakz

Reputation: 7944

You are correct to set the Window DataContext as you have but your Binding on the TextBlock is wrong.

Your XAML should be:

<TextBlock x:Name="NameBlock" Width="120" FontSize="16" Foreground="Red" Text="{Binding Path=Craftsman.Name, Mode=OneWay}"/>

Upvotes: 1

Related Questions