dotnet/wpf · critical · NotSupportedException

SR.MultiThreadedCollectionChangeNotSupported

Error message

SR.MultiThreadedCollectionChangeNotSupported

What it means

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.

Solutions

  1. Marshal mutations to the UI thread via Dispatcher.Invoke/BeginInvoke (or SynchronizationContext.Post)
  2. Use BindingOperations.EnableCollectionSynchronization with a lock so the binding engine can handle cross-thread updates
  3. Update the collection only on the thread that created the view
  4. Build the data on the background thread and assign the finished collection to ItemsSource on the UI thread

Example fix

// before
Task.Run(() => items.Add(newItem)); // NotSupportedException in view
// after
Application.Current.Dispatcher.Invoke(() => items.Add(newItem));
// or once at startup:
BindingOperations.EnableCollectionSynchronization(items, _lock);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!collectionView.CheckAccess())
    Dispatcher.CurrentDispatcher/* or view.Dispatcher */.Invoke(() => source.Add(item));
else
    source.Add(item);

Type guard

bool canChangeHere = view is CollectionView cv && cv.CheckAccess();

Try / catch

try { source.Add(item); }
catch (NotSupportedException) { view.Dispatcher.Invoke(() => source.Add(item)); }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/fe47a18dfa56bb25. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/CollectionView.cs:1165

        ///
        ///     Calls ProcessCollectionChanged() or
        ///     posts the change to the Dispatcher to process on the correct thread.
        ///</summary>
        /// <remarks>
        ///     User should override <see cref="ProcessCollectionChanged"/>
        /// </remarks>
        /// <param name="sender">
        /// </param>
        /// <param name="args">
        /// </param>
        protected void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
        {
            if (CheckFlag(CollectionViewFlags.ShouldProcessCollectionChanged))
            {
                if (!AllowsCrossThreadChanges)
                {
                    if (!CheckAccess())
                        throw new NotSupportedException(SR.MultiThreadedCollectionChangeNotSupported);
                    ProcessCollectionChanged(args);
                }
                else
                {
                    PostChange(args);
                }
            }
        }

        /// <summary>
        ///     This method is called when the value of AllowsCrossThreadChanges
        ///     is changed.   It gives a derived class an opportunity to
        ///     initialize its support for cross-thread changes (or to retire
        ///     that support).
        /// </summary>
        /// <notes>
        ///     This method will only be called if the application chooses to
        ///     change the synchronization information for a collection after

View on GitHub (pinned to 81131a70a4)