简体   繁体   中英

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 (eg 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;
}

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.

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 (eg 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)

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM