29

I'm trying to get the content of a label to bind to the string property of a class instance without much success.

XAML:

<Window x:Class="WPFBindingTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">    
<Grid>        
    <Label Height="28" Margin="12,55,106,0" Name="label1" Background="Bisque"
           Content="{Binding Source=MyFoo, Path=W1}" VerticalAlignment="Top" />

    <Label Height="28" Margin="12,12,106,0" Name="label2" Background="Bisque"
           Content="{Binding Source=MyFoo, Path=W2}"  VerticalAlignment="Top" />

    <Button Height="23" HorizontalAlignment="Right" Margin="0,0,32,48"
            Name="button1" VerticalAlignment="Bottom" Width="89"
            Click="button1_Click">
        Set Properties
    </Button>

</Grid>   
</Window>

C#:

namespace WPFBindingTest
{
   public partial class Window1 : Window
    {
        public Foo MyFoo;

        public Window1()
        {
            InitializeComponent();            

            MyFoo = new Foo();           
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {      
            MyFoo.W1 = "Hello";
            MyFoo.W2 = "Dave";
        }
    }

    public class Foo
    {
        public string W1 { get; set; }
        public string W2 { get; set; }
    }
}

i.e. when I click the button, I set the properties of MyFoo to "Hello" and "Dave", and want that reflected in the labels on the UI. I've set the Content as a binding but something isn't right. What am I doing wrong here?

sisharp
  • 157
  • 11
Gareth
  • 2,746
  • 4
  • 30
  • 44

2 Answers2

24

You may make your MyFoo a dependency property and set the DataContext to your Window1 instance:

<Window DataContext="{Binding RelativeSource={RelativeSource Self}}" ...>

See this article for more details.

Making MyFoo a dependency property is not compulsory. it may work with just a property if you set the property value before assigning the DataContext. (But never with a field.) However if you want the labels to pick up the changing values of W1 and W2 (or you don't know/care if the values are set before or after assigning the DataContect), you need Foo to be either a DependencyObject, or implement interface INotifyPropertyChanged.

croxy
  • 4,082
  • 9
  • 28
  • 46
Vlad
  • 35,022
  • 6
  • 77
  • 199
  • 1
    Thanks, this pointed me in the right direction. Made Foo implement INotifyPropertyChanged, then set the DataContext of Window1 to that of a BindingList, which contains MyFoo. Label content is now: {Binding Path=W1, UpdateSourceTrigger=PropertyChanged} And it works a treat! – Gareth Feb 23 '10 at 11:31
  • 2
    @Vlad What would the difference be between using a `DependencyProperty` and implementing the `INotifyPropertyChanged` or should this be a question of itself? – ywm Aug 01 '13 at 14:18
  • @ymw: this is a different question, in fact quite big. In short: both will work for just binding, but `INotifyPropertyChanged` is more lightweight, `DependencyProperty` however doesn't take memory if not used and can be used for animations, styling, templates, be inherited (from parent container to the contained element) and much more. See for example [this answer](http://stackoverflow.com/a/3674530/276994). – Vlad Aug 01 '13 at 16:59
  • @Vlad I know it's 6 years ago, but props must be given for a clear, concise and more importantly, UNDERSTANDABLE answer. I don't know why so many people struggle to depict the WPF UI element binding in a clear and simple way, but you've done it here! – Redgum Dec 23 '21 at 22:51
14

Or give your Window a name: like NameOfWindow and use a ElementName binding:

Content="{Binding ElementName=NameOfWindow, Path=MyFoo.W1}"

Complete sample XAML:

<Window x:Class="WPFBindingTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300" Name="NameOfWindow">    
<Grid>        
    <Label Height="28" Margin="12,55,106,0" Name="label1" Background="Bisque" Content="{Binding ElementName=NameOfWindow, Path=MyFoo.W1}" VerticalAlignment="Top" />
    <Label Height="28" Margin="12,12,106,0" Name="label2" Background="Bisque" Content="{Binding ElementName=NameOfWindow, Path=MyFoo.W2}"  VerticalAlignment="Top" />
    <Button Height="23" HorizontalAlignment="Right" Margin="0,0,32,48" Name="button1" VerticalAlignment="Bottom" Width="89" Click="button1_Click">Set Properties</Button>
</Grid> 
Arcturus
  • 26,677
  • 10
  • 92
  • 107