如果我通过视图模型将某些(非易失性)数据绑定到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;
}
答案 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线程上的绑定值。