6

如果我有一些(非易失性)数据通过视图模型绑定到 UI,并且我从后台线程更新这些数据而不锁定任何内容并触发PropertyChanged事件,我是否保证UI 会看到此更新?如果我是,那为什么?

我可以看到CLRBindingWorker调用Dispatcher.BeginInvoke,从而确保从 UI 线程读取属性。我想知道的是属性值在 UI 线程中是否总是“新鲜”的(例如,是否会发生类似于http://www.yoda.arachsys.com/csharp/threads/volatility.shtml的场景)。

先前的答案表明确实如此,但没有任何解释。

例子:

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;
}
4

3 回答 3

2

这不是一个理想的解释,但与本文相对应的lock语句产生了完整的栅栏内存屏障。Dispatcher.BeginInvoke 的当前实现lock用于更新 Dispatcher 的队列。这意味着在 UI 线程中字段分配之后和字段使用之前存在完整的围栏。

于 2011-03-03T08:42:09.997 回答
1

这是我的评论

1)由于message-pump本身只有1个执行线程,所以不用担心全部或部分fences,而且volatile关键字不会起任何作用。

2) INotifyPropertyChanged 是关于事件的,如果事件调用列表上的一个委托失败,那么其余的将不会被调用,效果是属性不会被更新。

3) 如果您正在运行嵌套消息泵(例如模式窗口),那么子调度程序可能会在父调度程序之前更新您的属性,从而使更新与预期不同步。

4) 如果您使用 IValueConverter 并且转换失败,您的属性将不会更新。

5)如果您在绑定中使用显式更新触发器,那么这可能会产生影响(取决于您的场景)

于 2011-03-03T17:15:48.500 回答
0

不,它不会在所有情况下。为了确保您的 UI 更新,您应该始终使用Dispatcher更新 UI 线程上的绑定值。

于 2011-03-03T07:59:31.507 回答