WPF XAML binding does not update

it should be something like this to work,

<Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <TextBlock x:Name="First" Text="{Binding FirstString}" Grid.Row="0"/>
            <TextBlock x:Name="Second" Text="{Binding SecondString}" Grid.Row="1"/>
            <TextBlock x:Name="Third" Text="{Binding ThirdString}" Grid.Row="2"/>
            <TextBlock x:Name="Fourth" Text="{Binding FourthString}" Grid.Row="3"/>
        </Grid>

and c# code will be like,

public string FirstString { get; set; }
public string SecondString { get; set; }
public string ThirdString { get; set; }
public string FourthString { get; set; }

public MainWindow()
{
    InitializeComponent();    

    FirstString = "First";
    SecondString = "Second";
    ThirdString = "Third";
    FourthString= "Fourth";
    this.DataContext = this;  //here you set the context to current instance of window

}

There are a few things that are incorrect. The Binding markup will look at the object in the DataContext property of the control. This property inherits the DataContext from the declaring parent unless otherwise specified. Out of the box, this is null for a Window control.

There are two options for this problem. You can either set the DataContext explicitely in the code-behind or the XAML

// In XAML
<Window DataContext={Binding RelativeSource={RelativeSource Self}}>

or

// In the code-behind
DataContext = this;

Another problem is that the binding is applied at initialization. Initially, your properties are empty. After the InitializeComponent phase, the controls will "bind" to the properties (which are empty). When you set your properties afterward, the controls have no way to know it has changed. There are two mechanism to allow this. On the control level, you can make these properties as DependencyProperty or implement the INotifyPropertyChanged interface and raise the changes. If you want to go the INPC route, you can implement your properties and Window as such:

public partial class MainWindow : INotifyPropertyChanged
{
    private string firstString;
    private string secondString;
    private string thirdString;
    private string fourthString;

    public string FirstString
    {
        get { return firstString; }
        set
        {
            firstString = value;
            RaisePropertyChanged("FirstString");
        }
    }

    public string SecondString
    {
        get { return secondString; }
        set
        {
            secondString = value;
            RaisePropertyChanged("SecondString");
        }
    }

    public string ThirdString
    {
        get { return thirdString; }
        set
        {
            thirdString = value;
            RaisePropertyChanged("ThirdString");
        }
    }

    public string FourthString
    {
        get { return fourthString; }
        set
        {
            fourthString = value;
            RaisePropertyChanged("FourthString");
        }
    }

    public MainWindow()
    {
        DataContext = this;
        InitializeComponent();

        FirstString = "First";
        SecondString = "Second";
        ThirdString = "Third";
        FourthString = "Fourth";
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    private void RaisePropertyChanged(string propertyName)
    {
        var handlers = PropertyChanged;

        handlers(this, new PropertyChangedEventArgs(propertyName));
    }
}

Unless specified otherwise, the path of the binding is relative to the DataContext of the element. In your case, I suspect you didn't specify a DataContext at all...

Since the properties are declared in the MainWindow class itself, the easiest fix is to add:

DataContext = this;

at the end of the constructor.

Tags:

C#

Wpf

Binding