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

标签 c# wpf multithreading

我正在开发一个 WPF 应用程序,发现绑定(bind)属性的属性更改通知可以从后台线程发生,但是要对 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);
        }
    }

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

最佳答案

这个问题与线程安全无关。问题是 CollectionChanged 事件是从工作线程引发的,这意味着处理程序是在同一线程中执行的,当处理程序试图触摸 UI 时,您会遇到异常,因为这只允许来自UI 线程。

如果情况相同,PropertyChanged 事件也会发生同样的情况,没有对这两个事件给予特殊处理。

如果您需要从事件处理程序中触摸 UI,那么您必须确保 the event is raised on the UI thread否则,事件处理程序必须使用 Dispatcher.CheckAccess 检查是否需要对 UI 线程进行编码更改,并使用 Dispatcher.BeginInvoke 来执行此操作。

关于c# - 为什么 CollectionChanged 不是线程安全的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19183841/

相关文章:

c# - UWP : async read file into byte[]

c# - 如何为我的程序设置图标?我的意思是,桌面上的实际 .exe

c# - WPF 依赖属性 - 数据绑定(bind)不起作用

.net - 从 Alt-Tab 程序切换器隐藏窗口的最佳方法?

c++ - wxwidgets - 以正确的方式退出线程

c# - 在初始化 ViewModel 时防止执行 ValueChanged

c# - 我可以在没有存储帐户的情况下使用带有 HTTP 触发器的 Azure Function 吗

c# - 如何在 xaml 中声明 Storyboard并从代码中运行它

.net - 您在 UI 中使用 System.Component.BackgroundWorker 的频率如何? (如果曾经)

python - python asyncio call_soon_threadsafe 真的是线程安全的吗?