我有一个 WPF 应用程序,它在计时器内更新其数据模型,该计时器以 1 Hz 的频率更新其数据。据我了解,计时器在与 GUI 不同的线程上工作。一切似乎都工作得很好,但我正在阅读并看到关于是否可以在不同于 GUI 线程的线程上更新数据的相互冲突的报告。我们正在使用 .NET Framework 4 Client Profile 运行。下面的文章说事情在 4.5 中得到了修复,但我仍然不清楚它是否是这样。有人可以帮我澄清一下吗?到目前为止,我们还没有在绑定(bind)中使用集合。这就是我们没有遇到麻烦的原因。
最佳答案
是的。它是线程安全的。 INotifyPropertyChanged
始终从其他线程编码到 UI 线程。
无需将 PropertyChanged
从另一个线程调度到 UI 线程,因为 PropertyChanged
事件会自动编码到 UI 调度程序。
Note that in WPF, things are different and the code shown in Figure 5 works even if the Status property is data-bound to a TextBlock. This is because WPF automatically dispatches the PropertyChanged event to the main thread, unlike all the other XAML frameworks. In all other frameworks, a dispatching solution is needed.
但是,这只适用于标量属性的更改通知(即 PropertyChanged
事件)。集合更改通知(INotifyCollectionChanged.CollectionChanged
事件)不会以这种方式工作,它们必须在 UI 线程上手动引发。也就是说,当使用 INotifyCollectionChanged
(例如使用 ObservableCollection
)时,这些更改不会编码(marshal)到 UI 线程。这意味着如果您从非 UI 线程修改集合,则会出现异常。例如,有一些 ViewModel
我们在 ViewModel
类中,我们不使用 Dispatcher 来更新 UI。所以我建议你使用 David Rickard 的方法:
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 线程的说法是不正确的。从MVVM Light
的ViewModelBase
类源码可以看出 there is no marshal between threads to update scalar property 。请参阅 RaisePropertuChanged()
方法。
为了消除对分派(dispatch)标量属性的任何疑问,我做了一个测试:
XAML:
<TextBlock Text="{Binding Number}" FontSize="188" Foreground="Red" />
View 模型:
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 自动分派(dispatch)到 UI 线程。我相信a MSDN article和 link你已经在你的问题中表明了:)。
请注意这一点:这是因为 WPF 会自动将 PropertyChanged 事件分派(dispatch)到主线程,这与所有其他 XAML 框架不同。
关于c# - 将 WPF 控件绑定(bind)到 Timer 中更新的数据是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36578957/