为什么CollectionChanged不是线程安全的?

Mik*_*ike 2 c# wpf multithreading

我正在研究一个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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

注意:来自后台线程的CollectionChanged事件会使应用程序崩溃,但后台线程中的PropertyChanged事件会更新UI而不会出现任何问题,是的,这是在.NET 4.0中

Jon*_*Jon 5

此问题与线程安全无关.问题是该CollectionChanged事件是从工作线程引发的,这意味着处理程序在同一个线程中执行,当处理程序试图触摸UI时,您有一个例外,因为只允许从UI线程执行.

PropertyChanged如果情况相同,事件也会发生同样的情况,对这两种情况都没有特别的待遇.

如果需要从事件处理程序中触摸UI,则必须确保在UI线程上引发事件,否则事件处理程序必须检查Dispatcher.CheckAccess是否需要对UI线程进行编组更改并Dispatcher.BeginInvoke执行此操作.