Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bound view model property updated in background thread; will the UI always see the updated value?

If I have some (non-volatile) data bound to the UI via a view model, and I update this data from a background thread without locking anything, and trigger a PropertyChanged event, am I guaranteed that the UI will see this update? If I am, then why?

I can see that CLRBindingWorker calls Dispatcher.BeginInvoke and thus makes sure the property is read from the UI thread. What I want to know is whether the property value will always be "fresh" in the UI thread (e.g. whether a scenario similar to http://www.yoda.arachsys.com/csharp/threads/volatility.shtml can happen).

A previous answer suggested this is indeed the case, but without any explanation.

Example:

public class MyViewModel : INotifyPropertyChanged
{
    // Bound to the view as <TextBlock Text="{Binding Data}" />
    private long _data;
    public long Data
    {
        get { return _data; }
        set
        {
            _data = value;
            FirePropertyChanged("Data");
        }
    }

    public MyViewModel()
    {
        new Thread(Updater).Start();
    }

    private void Updater()
    {
        while (true)
        {
            Data++;
            Thread.Sleep(1000);
        }
    }

    private void FirePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null) 
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}
like image 533
ehnmark Avatar asked Mar 03 '11 07:03

ehnmark


2 Answers

That's not an ideal explanation, but corresponding to this article the lock statement produce full fence memory barrier. The current implementation of Dispatcher.BeginInvoke use lock to update Dispatcher's queue. It means that there is full fence after field assignment and before field usage in UI thread.

like image 135
Marat Khasanov Avatar answered Oct 30 '22 04:10

Marat Khasanov


Here are my comments

1) As the message-pump itseld has only 1 thread of execution, you do not need to worry about full or partial fences, and the volatile keyword wont have any effect.

2) INotifyPropertyChanged is about events, and if one delegate on the event's invocation list fails then the remainder will not get called, with the effect that the property wont get updated.

3) If you are running nested message-pumps (e.g. modal windows) then the child dispatcher may update your property before the parent dispatcher, thus making the update out of sync to what may be expected.

4) if you use a IValueConverter and the conversion fails, your property wont be updated.

5) If you use explicit update triggers in your bindings then this may have an effect (depending on your scenario)

like image 23
Dean Chalk Avatar answered Oct 30 '22 04:10

Dean Chalk