6

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;
}
Community
  • 1
  • 1
ehnmark
  • 2,656
  • 3
  • 24
  • 20

3 Answers3

2

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.

Marat Khasanov
  • 3,808
  • 19
  • 22
  • Nice catch. I'm surprised that this is not a documented feature but rather what seems to be a side effect of the fact that the dispatcher's internal queue is protected with a lock. – ehnmark Mar 03 '11 at 22:20
  • Based on [this answer](http://stackoverflow.com/questions/5208926/), the lock in `BeginInvoke` would only ensure that the write gets propagated to main memory directly from the background thread, right? We still need the UI thread to read a fresh value. However, since the dispatcher locks again in `ProcessQueue`, called on the main thread in response to the window message, we should be OK. Do you agree? Maybe that's what you meant? – ehnmark Mar 06 '11 at 08:56
  • I am sorry for replying late. Yes, that's what I meant. Locking in each thread guarantee value synchronization because of full fence visible by each thread. – Marat Khasanov Mar 09 '11 at 08:28
  • @MaratKhasanov, though the first write will be safe due to the lock, what happens if the background thread once again updates the value before the UI has done its read but hasn't yet got around to locking and invoking the UI thread again? – bgura Feb 27 '20 at 17:26
1

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)

Dean Chalk
  • 20,076
  • 6
  • 59
  • 90
  • Hi Dean, I agree with your points 2-5. However, I don't see how the first one provides any guarantee that, when a posted message is handled in the UI thread (`Dispatcher.ProcessQueue` I assume), any data written in the background thread will be fresh. But maybe I'm misunderstanding. – ehnmark Mar 03 '11 at 22:44
0

No, it won't in all cases. To make sure that your UI updates you should always update bound values on the UI thread using the Dispatcher.

OJ.
  • 28,944
  • 5
  • 56
  • 71
  • 1
    I disagree. Veiw model should not take care about dispatcher. And we can achieve this functionality today, but not for collections. That's sad, but CollectionView doesn't support update from another thread. As I know, Microsoft will do this in the next WPF. – Marat Khasanov Mar 03 '11 at 08:23