27
votes

I have a textblock:

<TextBlock HorizontalAlignment="Left" Name="StatusText" Margin="0,20" TextWrapping="Wrap" Text="{Binding StatusText}">
            ... Status ...
</TextBlock>

codebehind:

public StatusPage()
{
    InitializeComponent();
    this.DataContext = new StatusPageViewModel(this);
}

and in viewModel:

private string _statusText;
/// <summary>
/// Status text
/// </summary>
public string StatusText
{
    get { return _statusText; }
    set { _statusText = value; }
}

and in function in viewModel:

string statusText = Status.GetStatusText();
this.StatusText = statusText;

GetStatusText() returns string like "Work done" etc. Values from that functions are assinged to the this.StatusText but the TextBlock's text property don't change and is showing still placeholder "... Status..."

I'm aware of questions like this --> CLICK<--- but after reading this I'm still not able to find solution

@Update

After your suggestions i updated my code and now I have this:

public string StatusText
{
    get 
    {
        return _statusText;
    }
    set 
    {
        _statusText = value; 
        RaisePropertyChanged("StatusText");
    }
}

and declaration of viewModel:

 public class StatusPageViewModel : ObservableObject, INavigable

where:

ObservableObject class is:

public abstract class ObservableObject : INotifyPropertyChanged
{
    #region INotifyPropertyChanged Members

    /// <summary>
    /// Raises the PropertyChange event for the property specified
    /// </summary>
    /// <param name="propertyName">Property name to update. Is case-sensitive.</param>
    public virtual void RaisePropertyChanged(string propertyName)
    {
        OnPropertyChanged(propertyName);
    }

    /// <summary>
    /// Raised when a property on this object has a new value.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Raises this object's PropertyChanged event.
    /// </summary>
    /// <param name="propertyName">The property that has a new value.</param>
    protected virtual void OnPropertyChanged(string propertyName)
    {

        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }

    #endregion // INotifyPropertyChanged Members
}

But its still not working

7
Is your problem solved?Mayur Dhingra
So what was the solution? I'm facing the same problem. INotifyPropertyChanged is implemented, Mode 1way/2ways makes no difference.mischka
I have the same problem. After changing the binding properties while the application is running (e. g. OneWay/TwoWay), the property's getter gets called and everything looks fine but after restarting it's still not working.IngoB
It may help someone in the future, but despite implementing the interface, I forgot to actually reference it in my MainWindow class declaration. EG: MainWindow : Window, INotifyPropertyChangedReahreic

7 Answers

35
votes

You need to implement INotifyPropertyChanged in your ViewModel order to notify the View that the property has changed.

Here's a link to the MSDN page for it: System.ComponentModel.INotifyPropertyChanged

The most important thing to note is that you should raise the PropertyChanged event in your property setter.

9
votes

Add binding mode two way, because by default Textblock's binding mode is one way

<TextBlock HorizontalAlignment="Left" Name="StatusText" Margin="0,20" TextWrapping="Wrap" Text="{Binding StatusText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
            ... Status ...
</TextBlock>

and also, of course you need to implement INotifyPropertyChanged for the purpose, refer to this link for how to implement.

4
votes

When working with DataModels you have to be sure the model is complete at intial load. So if you do this: this.DataContext = mainViewModel and some parts of you mainViewModel are NOT loaded (=null) then you are not able to bind them. Example, I have a Model within that model an object Program. I bind to Text of a TextBlock to Model.Program.Name. The Program object is not connected at initial load so you will have to rebind to a loaded object after because otherwise no notifications can be send.

2
votes

Your view model needs to implement INotifyPropertyChanged, and you need to raise it every time one of your property changes (ie in the setter).

Without it WPF has no way of knowing that the property has changed.

0
votes

I had this problem and here is what I was doing wrong...

Note: I Had INotifyPropertyChanged coded correctly.


In my View, I had

<SomeView.DataContext>
    <SomeViewModel/>
<SomeView.DataContext/>

...and this calls the constructor of the VM (creating an instance to point to / to be bound to).

In another class (in the ViewModel code for my program's Main Window) I was also instantiating the ViewModel(s), i.e.:

private SomeAstractBaseViewModel someViewModel = new SomeViewModel();
private SomeAstractBaseViewModel someOtherViewModel = new SomeOtherViewModel(); 

They both inherited from a superclass and I was switching back and forth between instances showing different Views in a section of the Main Window - as per my intention.

How all that is wired up is another question, but when I remove the problematic xaml (at the top of this answer) that was previously instantiating another "unused" instance of the ViewModel, the View would update as per INotifyPropertyChanged mechanisms.

0
votes

In my situation, a UserControl was nested in a View and when I tried Binding to a property within the UserControl, the framework was looking for the property in the ViewModel, which does not exist. To solve this, I had to specify ElementName.

MyControl.xaml:

<UserControl
    ...
    x:Name="MyUserControl">
    ...
    <Label Content="{Binding MyProperty, ElementName=MyUserControl}"
    ...

MyControl.xaml.cs:

public partial class MyControl: UserControl, INotifyPropertyChanged
{
    ...
    private string _myProperty = "";

    public string MyProperty
    {
        get => _myProperty ;
        set
        {
            if (value == _myProperty ) return;
            _myProperty = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    ...
0
votes

When you call OnPropertyChanged, make sure you include the property name. That cost me several hours today, this fucking hidden binding magic is so frustrating. Give me an error message, or something instead of just silently failing!

So instead of just calling OnPropertyChanged() without supplying an argument, call it either inside your property setter (so CallerMemberName fills it in for you), or supply it yourself.

E.g. somewhere in xaml you have the binding:

... Value="{Binding Progress}" ...

Then in codebehind you have the DataContext object that inherits from INotifyPropertyChanged, and in a method somewhere after updating your values you call:

OnPropertyChanged("Progress");