是的。它是線程安全的。 INotifyPropertyChanged
總是從其他線程封送到UI線程。
由於PropertyChanged
事件被自動封送到UI調度程序,所以不需要從另一個線程調度PropertyChanged
到UI線程。
由於a MSDN article說:
注意,在WPF中,事情是不同的,在圖5所示 代碼工作即使狀態屬性數據綁定到一個TextBlock。這個 是因爲WPF自動調度PropertyChanged事件到 主線程,不像所有其他XAML框架。在所有其他 框架中,需要調度解決方案。
然而,這是僅適用於標量屬性(即PropertyChanged
事件)更改通知真。收集更改通知(INotifyCollectionChanged.CollectionChanged
事件)不以這種方式工作,它們必須手動在UI線程上引發。也就是說,在使用INotifyCollectionChanged
(例如ObservableCollection
)時,這些更改不會封送到UI線程。這意味着如果您從非UI線程修改集合,則會發生異常。例如,有一些ViewModel
我們在ViewModel
類中,我們不使用分派器來更新UI。所以,我建議你使用大衛·裏卡德的做法:
public static class DispatchService
{
public static void Invoke(Action action)
{
Dispatcher dispatchObject = Application.Current.Dispatcher;
if (dispatchObject == null || dispatchObject.CheckAccess())
{
action();
}
else
{
dispatchObject.Invoke(action);
}
}
}
和:
DispatchService.Invoke(() =>
{
this.MyCollection.Add("new value");
});
David Rickard article at msdn blog.
更新:
呀,article使用MVVMLight框架。但是,MVVM Light使用Dispatcher
將標量屬性編組爲UI線程是不正確的。可以從ViewModelBase
類的源代碼MVVM Light
看出there is no marshal between threads to update scalar property。請參閱RaisePropertuChanged()
方法。
爲了打消調度標性質的任何疑問,我做了一個試驗:
XAML:
<TextBlock Text="{Binding Number}" FontSize="188" Foreground="Red" />
視圖模型:
public int Number { get; set; }
private void UpdateNumber()
{
Task.Run(() =>
{
System.Timers.Timer timer = new System.Timers.Timer(250);
timer.Elapsed += (sender, eventArgs) =>
{
Number++;
OnPropertyChanged("Number");//No exceptions, no errors
};
timer.Enabled = true;
});
}
更新1:
毫無疑問,INotifyProperyChanged
事件由WPF自動發送給UI主題。我相信a MSDN article和你在問題中顯示的link :)。
請注意:這是因爲WPF自動將PropertyChanged事件分派到主線程,與所有其他XAML框架不同。
使用DispatcherTimer。它的Tick事件在UI線程中引發。 – Clemens