dotnet/wpf · error · InvalidOperationException
SR.Format(SR.AccessCollectionAfterShutDown, collection)
Error message
SR.Format(SR.AccessCollectionAfterShutDown, collection)
What it means
BindingOperations.AccessCollection throws InvalidOperationException(SR.AccessCollectionAfterShutDown) when the WPF ViewManager (a dispatcher-bound singleton) is null, meaning the Dispatcher has already shut down. Any binding-collection access routed through BindingOperations after dispatcher shutdown cannot be honored, since the view manager that serializes access no longer exists.
Solutions
- Check dispatcher lifetime before accessing the collection: if (dispatcher.HasShutdownStarted || dispatcher.HasShutdownFinished) skip the update.
- Stop background producers on shutdown (CancellationToken, dispatcher ShutdownStarted event) so no collection access happens after teardown.
- Marshal pending work to run before shutdown completes, or detach collections from bindings before closing the app.
Example fix
// before
await Task.Run(() => LoadData());
BindingOperations.AccessCollection(collection, () => collection.Add(item), true); // may throw at shutdown
// after
if (!dispatcher.HasShutdownStarted && !dispatcher.HasShutdownFinished)
{
BindingOperations.AccessCollection(collection, () => collection.Add(item), true);
} Defensive patterns
Strategy: validation
Validate before calling
var d = collection is ICollection c
? Dispatcher.CurrentDispatcher : Dispatcher.CurrentDispatcher;
if (d.HasShutdownStarted || d.HasShutdownFinished)
return; // skip collection access after shutdown Type guard
bool IsDispatcherAlive(Dispatcher d) => d != null && !d.HasShutdownStarted && !d.HasShutdownFinished;
Try / catch
try { BindingOperations.AccessCollection(col, work, true); }
catch (InvalidOperationException) { /* dispatcher shut down; abandon or log */ } Prevention
- Cancel background collection producers on Dispatcher ShutdownStarted
- Check HasShutdownStarted/HasShutdownFinished before cross-thread collection access
- Detach bound collections during application teardown
When it happens
Trigger: Calling BindingOperations.AccessCollection (or APIs like CollectionView refresh/cross-thread collection access routed through it) from a background thread or during application teardown after Dispatcher.InvokeShutdown/Exit, when ViewManager.Current returns null.
Common situations: Background worker threads still pushing collection updates while the app is closing; asynchronous continuations (await/Dispatcher.BeginInvoke callbacks) firing after window close/dispatcher shutdown; unit tests that dispose the dispatcher but then touch bound collections.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- SR.DispatcherHasShutdown
- Processing is disabled while the Dispatcher is in this…
- SR.AutomationDispatcherShutdown
- SR.CollectionView_MissingSynchronizationCallback
- SR.ContextMenuInDifferentDispatcher
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/b9b2afd3f6787bfd.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/BindingOperations.cs:364
/// int index = 3;
/// int result = 0;
/// BindingOperations.AccessCollection(
/// _collection,
/// () => { result = _collection[index]; },
/// false); // read-access
/// }
/// Note that the access method refers to local variables (index, result)
/// of MyMethod, as well as to an instance variable (_collection) of the
/// 'this' object.
/// </notes>
public static void AccessCollection(
IEnumerable collection,
Action accessMethod,
bool writeAccess)
{
ViewManager vm = ViewManager.Current;
if (vm == null)
throw new InvalidOperationException(SR.Format(SR.AccessCollectionAfterShutDown, collection));
vm.AccessCollection(collection, accessMethod, writeAccess);
}
/// <summary>
/// Returns a list of all binding expressions that are:
/// a) top-level (do not belong to a parent MultiBindingExpression or BindingGroup)
/// b) source-updating (binding mode is TwoWay or OneWayToSource)
/// c) currently dirty or invalid
/// and d) attached to a descendant of the given DependencyObject (if non-null).
/// These are the bindings that may need attention before executing a command.
/// </summary>
public static ReadOnlyCollection<BindingExpressionBase> GetSourceUpdatingBindings(DependencyObject root)
{
List<BindingExpressionBase> list = DataBindEngine.CurrentDataBindEngine.CommitManager.GetBindingsInScope(root);
return new ReadOnlyCollection<BindingExpressionBase>(list);
}
View on GitHub (pinned to 81131a70a4)