WPF binding not updating the view
Asked Answered
U

9

34

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

Unattended answered 27/8, 2014 at 8:20 Comment(3)
So what was the solution? I'm facing the same problem. INotifyPropertyChanged is implemented, Mode 1way/2ways makes no difference.Cribwork
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.Monegasque
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, INotifyPropertyChangedAlonzoaloof
P
44

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.

Pasty answered 27/8, 2014 at 8:23 Comment(1)
Try setting your Binding.Mode property to OneWay - it may be that the UI is not listening for the update.Pasty
F
10

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.

Floranceflore answered 27/8, 2014 at 8:25 Comment(1)
Making the binding twoway is pointless as the control can't change the text so has no need to be able to update the source.Franconian
B
6

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.

Bookplate answered 2/12, 2015 at 15:49 Comment(2)
"rebind to a loaded object". This was very helpful. Thank you.Lyon
How do you rebind and reload it??Mitchiner
G
3

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.

Glyptics answered 27/8, 2014 at 8:23 Comment(0)
A
2

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.

Arachnid answered 8/3, 2018 at 23:10 Comment(1)
Thank god for this post. I was struggling for what seemed like forever trying to figure out how to stop WPF from creating an extra instance of every viewmodel object, and calling the ctor of every vm object everytime I swapped views. I thought I did this already, but I decided to try it anyways just in case and it works perfectly. Not sure why you got downvoted but thank youPalla
S
2

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));
    }
    ...
Sutphin answered 7/1, 2020 at 18:22 Comment(0)
A
1

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");
Alba answered 20/10, 2021 at 23:24 Comment(0)
A
0

In my case the problem was, when I call the OnPropertyChanged. I passed incorrect Member Name. For example:

Incorrect

        private Student std = new Student();
        public Student Std { 
            get { return std; } 
            set { std = value; OnPropertyChanged("Student"); } 
}

Correct

        private Student std = new Student();
        public Student Std { 
            get { return std; } 
            set { std = value; OnPropertyChanged("Std"); } 
}

Here I have to pass the property name not the class name

Alliance answered 26/5, 2022 at 22:31 Comment(0)
R
0

I had a similar situation. I have a WPF UserControl with a ViewModel that implements IPropertyChanged, and it looked like I was doing everything right, except for one thing: my code is running on the main thread, and my long running operation is blocking the updating of the UI.

So in my case I get the WindowControl.Dispatcher into my ViewModel, so the thing I had to do was this:

dispatcher.Invoke(() =>   
{  
    Status = $"Processing task {number} of {total}.";
});

The dispatcher is used to run code on the UI Thread.

Rowden answered 11/4 at 9:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.