{"record":{"id":"fe47a18dfa56bb25","repo":"dotnet/wpf","slug":"sr-multithreadedcollectionchangenotsupported","errorCode":null,"errorMessage":"SR.MultiThreadedCollectionChangeNotSupported","messagePattern":"SR\\.MultiThreadedCollectionChangeNotSupported","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"critical","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/CollectionView.cs","lineNumber":1165,"sourceCode":"        ///\n        ///     Calls ProcessCollectionChanged() or\n        ///     posts the change to the Dispatcher to process on the correct thread.\n        ///</summary>\n        /// <remarks>\n        ///     User should override <see cref=\"ProcessCollectionChanged\"/>\n        /// </remarks>\n        /// <param name=\"sender\">\n        /// </param>\n        /// <param name=\"args\">\n        /// </param>\n        protected void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)\n        {\n            if (CheckFlag(CollectionViewFlags.ShouldProcessCollectionChanged))\n            {\n                if (!AllowsCrossThreadChanges)\n                {\n                    if (!CheckAccess())\n                        throw new NotSupportedException(SR.MultiThreadedCollectionChangeNotSupported);\n                    ProcessCollectionChanged(args);\n                }\n                else\n                {\n                    PostChange(args);\n                }\n            }\n        }\n\n        /// <summary>\n        ///     This method is called when the value of AllowsCrossThreadChanges\n        ///     is changed.   It gives a derived class an opportunity to\n        ///     initialize its support for cross-thread changes (or to retire\n        ///     that support).\n        /// </summary>\n        /// <notes>\n        ///     This method will only be called if the application chooses to\n        ///     change the synchronization information for a collection after","sourceCodeStart":1147,"sourceCodeEnd":1183,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/CollectionView.cs#L1147-L1183","documentation":"CollectionView.OnCollectionChanged throws NotSupportedException when the underlying collection raised CollectionChanged from a different thread while the view does not allow cross-thread changes. WPF collection views are bound to the thread that created them (Dispatcher affinity), so change notifications must arrive on that thread.","triggerScenarios":"Mutating an ObservableCollection from a background thread (Task, ThreadPool, socket callback) while a CollectionView bound to it lives on the UI thread; the view then calls OnCollectionChanged off-dispatcher and CheckAccess() fails.","commonSituations":"Loading data async and writing results directly into an ObservableCollection consumed by an ItemsControl; background services pushing updates into a bound collection; worker threads updating shared collections.","solutions":["Marshal mutations to the UI thread via Dispatcher.Invoke/BeginInvoke (or SynchronizationContext.Post)","Use BindingOperations.EnableCollectionSynchronization with a lock so the binding engine can handle cross-thread updates","Update the collection only on the thread that created the view","Build the data on the background thread and assign the finished collection to ItemsSource on the UI thread"],"exampleFix":"// before\nTask.Run(() => items.Add(newItem)); // NotSupportedException in view\n// after\nApplication.Current.Dispatcher.Invoke(() => items.Add(newItem));\n// or once at startup:\nBindingOperations.EnableCollectionSynchronization(items, _lock);","handlingStrategy":"try-catch","validationCode":"if (!collectionView.CheckAccess())\n    Dispatcher.CurrentDispatcher/* or view.Dispatcher */.Invoke(() => source.Add(item));\nelse\n    source.Add(item);","typeGuard":"bool canChangeHere = view is CollectionView cv && cv.CheckAccess();","tryCatchPattern":"try { source.Add(item); }\ncatch (NotSupportedException) { view.Dispatcher.Invoke(() => source.Add(item)); }","preventionTips":["Only mutate bound collections on the UI thread","Use BindingOperations.EnableCollectionSynchronization for genuinely multi-threaded collections","Marshal background results via Dispatcher.BeginInvoke before touching the collection"],"tags":["wpf","threading","collectionview","dispatcher","cross-thread"],"backgroundTag":"cross-thread-collection-access","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}