我正在开发一个 WPF 应用程序,发现绑定属性上的属性更改通知可以从后台线程发生,但是对 observablecollection 进行任何更改(例如添加或删除项目)必须从 UI 线程发生。我的问题是为什么会这样? INotifyPropertyChanged 和 INotifyCollectionChanged 都是 UI 控件订阅的,那么为什么 INotifyPropertyChanged 会例外呢?
例如:
public class ViewModel : INotifyPropertyChanged
{
ObservableCollection<Item> _items = new ObservableCollection<Item>();
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
//Can fire this from a background thread without any crash and my
//Name gets updated in the UI
InvokePropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
public void Add(Item item)
{
//Cant do this from a background thread and has to marshal.
_items.Add(item);
}
public event PropertyChangedEventHandler PropertyChanged;
public void InvokePropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, e);
}
}
NOTE:来自后台线程的 CollectionChanged 事件会使应用程序崩溃,但是来自后台线程的 PropertyChanged 事件更新 UI 时没有任何问题,是的,这是在 .NET 4.0 中
这个问题与线程安全无关。问题是CollectionChanged
事件是从工作线程引发的,这意味着处理程序在同一个线程中执行,当处理程序尝试触摸 UI 时,您会遇到异常,因为这只允许从 UI 线程进行。
同样的情况也会发生在PropertyChanged
如果情况相同,则不会对任一事件给予特殊处理。
如果您需要从事件处理程序中触摸 UI,那么您必须确保该事件在 UI 线程上引发 https://stackoverflow.com/q/2091988/50079否则事件处理程序必须检查Dispatcher.CheckAccess
如果需要对 UI 线程进行编组更改并且Dispatcher.BeginInvoke
这样做。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)