dotnet/wpf · error · InvalidOperationException

throw new…

Error message

throw new InvalidOperationException(SR.CompositeCollectionResetOnlyOnClear);

What it means

CompositeCollectionView supports a Reset (collection changed) notification only when the composite collection was cleared. Any other Reset (the source CompositeCollection changed structurally in a way other than clearing) cannot be reconciled with currency and live grouping bookkeeping, so ProcessCollectionChanged throws InvalidOperationException.

Solutions

  1. Fire Reset only when the CompositeCollection was actually emptied; otherwise raise granular Add/Remove/Replace/Move notifications.
  2. Replace the whole CompositeCollection instance (assign a new object) instead of mutating it and signaling Reset.
  3. Wrap the update so each contained collection's own changes propagate individually rather than being collapsed into a parent Reset.

Example fix

// before
compositeCollection.Clear();
compositeCollection.Add(newContainer);
onCollectionChanged(NotifyCollectionChangedAction.Reset);

// after
compositeCollection.Clear(); // Reset is legal here
compositeCollection.Add(newContainer); // raise Add for this change instead of Reset
Defensive patterns

Strategy: validation

Validate before calling

if (action == NotifyCollectionChangedAction.Reset && compositeCollection.Count > 0)
    throw new InvalidOperationException("Reset is only supported when the CompositeCollection is cleared");

Try / catch

try { ApplyChange(e); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Reset"))
{ RefreshViewFromScratch(); }

Prevention

When it happens

Trigger: Raising/forwarding a CollectionChanged Reset event on a CompositeCollection whose items were not simply emptied - e.g. replacing the whole CompositeCollection contents with new CollectionContainers and firing Reset instead of Add/Remove, or re-initializing the CompositeCollection in place.

Common situations: Rebuilding a CompositeCollection at runtime by mutating it and firing Reset; third-party sources that coalesce all changes into a Reset; code that mimics ObservableCollection.Clear with Reset after substituting containers.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/CompositeCollectionView.cs:624

                    break;


                case NotifyCollectionChangedAction.Reset:
                    {
                        _traceLog?.Add("ProcessCollectionChanged  action = {0}", args.Action);

                        if (_collection.Count != 0)
                        {
                            //
                            //  This is to verify that a Reset event is raised IFF the CompositionCollection
                            //  was cleared.  To fully implement a Reset event otherwise can prove to be
                            //  quite complex.  For example, you must unhook the listeners to each of the
                            //  CollectionContainers that are no longer in the collection, hook up the new
                            //  ones, and figure out how to restore the currency to the correct item in
                            //  the correct sub-collection, or to BeforeFirst or AfterLast.
                            //

                            throw new InvalidOperationException(SR.CompositeCollectionResetOnlyOnClear);
                        }

                        _count = 0; // OnCollectionChanged(arg) below will raise PropChange for Count
                        if (_currentPositionX >= 0) // if current item was in view
                        {
                            OnCurrentChanging();
                            SetCurrentBeforeFirst();
                            OnCurrentChanged();

                            OnPropertyChanged(IsCurrentBeforeFirstPropertyName);
                            OnPropertyChanged(CurrentPositionPropertyName);
                            OnPropertyChanged(CurrentItemPropertyName);
                        }
                    }
                    break;

                default:
                    throw new NotSupportedException(SR.Format(SR.UnexpectedCollectionChangeAction, args.Action));

View on GitHub (pinned to 81131a70a4)