Reputation: 2675
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
Reputation: 9827
There are a couple of things to take note of.
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.
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.
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
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
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