绑定视图模型属性在后台线程中更新; UI会始终看到更新的值吗?

时间:2011-03-03 07:43:40

标签: c# .net wpf multithreading memory-model

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

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

previous answer建议确实如此,但没有任何解释。

示例:

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

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

以下是我的评论

1)由于消息泵itseld只有1个执行线程,你不必担心完全或部分栅栏,而volatile关键字也不会有任何影响。

2)INotifyPropertyChanged是关于事件的,如果事件调用列表上的一个委托失败,则不会调用其余部分,导致该属性不会更新。

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

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

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

答案 2 :(得分:0)

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