dotnet/wpf · error · InvalidOperationException

SR.CollectionView_MissingSynchronizationCallback

Error message

SR.CollectionView_MissingSynchronizationCallback

What it means

ViewManager.AccessCollection invokes a CollectionView's synchronization callback on the correct (UI/dispatcher) context. Before invoking, it dereferences the weak reference to the callback's target; if the target has been garbage collected, it throws InvalidOperationException(SR.CollectionView_MissingSynchronizationCallback).

Solutions

  1. Keep the CollectionView's owning context alive (store a strong reference) while background threads use it
  2. Route all cross-thread collection updates through Dispatcher.Invoke/BeginInvoke on the UI thread instead of touching the view directly
  3. Recreate the CollectionView (GetDefaultView) from a live source on the UI thread before use
  4. Bind via BindingOperations.EnableCollectionSynchronization for correct cross-thread access

Example fix

// before
// background thread:
myView.Refresh(); // view's creator already collected
// after
Application.Current.Dispatcher.Invoke(() => myView.Refresh());
Defensive patterns

Strategy: try-catch

Try / catch

try { Dispatcher.Invoke(() => view.Refresh()); }
catch (InvalidOperationException) { view = (ICollectionView)CollectionViewSource.GetDefaultView(liveSource); /* recreate */ }

Prevention

When it happens

Trigger: A background thread accesses a CollectionView (e.g. Add/Remove/enumeration with cross-thread checks) after the object that created the view's synchronization callback has been collected; the weak _callbackTarget.Target returns null.

Common situations: Long-lived CollectionViews whose owning window/view was closed and collected but the view is still touched from worker threads; holding views in statics while their creators die.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/ViewManager.cs:394

                // target gets GC'd
                object target = callback.Target;
                _callbackTarget = (target != null) ? new WeakReference(target) : ViewManager.StaticWeakRef;
            }
        }

        public bool IsSynchronized
        {
            get { return _context != null || _callbackMethod != null; }
        }

        public void AccessCollection(IEnumerable collection, Action accessMethod, bool writeAccess)
        {
            if (_callbackMethod != null)
            {
                // make sure the callback's target is still available
                object target = _callbackTarget.Target;
                if (target == null)
                    throw new InvalidOperationException(SR.Format(SR.CollectionView_MissingSynchronizationCallback, collection));

                // invoke the callback
                if (_callbackTarget == ViewManager.StaticWeakRef)
                    target = null;          // static method

                WeakReference wrContext = _context as WeakReference;
                object context = (wrContext != null) ? wrContext.Target : _context;
                _callbackMethod.Invoke(target, new object[] { collection, context, accessMethod, writeAccess });
            }
            else if (_context != null)
            {
                lock (_context)
                {
                    accessMethod();
                }
            }
            else
            {

View on GitHub (pinned to 81131a70a4)