dotnet/wpf · error · NotSupportedException

SR.RangeActionsNotSupported

Error message

SR.RangeActionsNotSupported

What it means

ItemContainerGenerator's OnCollectionChanged only supports single-item Add and Remove notifications. If an event reports multiple items (NewItems.Count or OldItems.Count != 1) for those actions, it throws NotSupportedException SR.RangeActionsNotSupported, because range change actions are not supported by this generator's incremental update logic.

Solutions

  1. Raise one Add/Remove event per item instead of a multi-item range event.
  2. Raise NotifyCollectionChangedAction.Reset for bulk changes so the generator rebuilds.
  3. Replace custom AddRange with sequential Add calls, or use a collection that emits Reset on bulk operations.

Example fix

// before
OnCollectionChanged(new NotifyCollectionChangedEventArgs(Add, newItemsList, startIndex)); // multi-item

// after
foreach (var item in newItemsList)
{
    items.Add(item);
    OnCollectionChanged(new NotifyCollectionChangedEventArgs(Add, item, items.IndexOf(item)));
}
// or: OnCollectionChanged(new NotifyCollectionChangedEventArgs(Reset));
Defensive patterns

Strategy: validation

Validate before calling

// Guard in your collection wrapper before raising:
if (action == NotifyCollectionChangedAction.Add && args.NewItems.Count != 1)
    throw new NotSupportedException("ItemContainerGenerator supports only single-item Add; use Reset for bulk changes");

Type guard

static bool IsSingleItemChange(NotifyCollectionChangedEventArgs a) =>
    (a.Action == NotifyCollectionChangedAction.Add && a.NewItems.Count == 1) ||
    (a.Action == NotifyCollectionChangedAction.Remove && a.OldItems.Count == 1);

Try / catch

try { /* bind collection */ }
catch (NotSupportedException) { /* replace source with a Reset-emitting adapter */ }

Prevention

When it happens

Trigger: A source INotifyCollectionChanged collection raises Add or Remove with several items at once (multi-item range events), e.g. AddRange-like extensions that batch notifications.

Common situations: Custom ObservableCollection subclasses implementing AddRange with a single multi-item event instead of N single-item events or a Reset; bulk load/unload operations.

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/d7ef28e729a2acb5. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ItemContainerGenerator.cs:2392

                if (index < 0)
                    throw new InvalidOperationException(SR.Format(SR.CollectionAddEventMissingItem, item));
            }
        }

        /// <summary>
        /// Forward a CollectionChanged event
        /// </summary>
        // Called  when items collection changes.
        private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
        {
            if (sender != ItemsInternal && args.Action != NotifyCollectionChangedAction.Reset)
                return;     // ignore events (except Reset) from ItemsCollection when we're listening to group's items.

            switch (args.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    if (args.NewItems.Count != 1)
                        throw new NotSupportedException(SR.RangeActionsNotSupported);
                    OnItemAdded(args.NewItems[0], args.NewStartingIndex);
                    break;

                case NotifyCollectionChangedAction.Remove:
                    if (args.OldItems.Count != 1)
                        throw new NotSupportedException(SR.RangeActionsNotSupported);
                    OnItemRemoved(args.OldItems[0], args.OldStartingIndex);
                    break;

                case NotifyCollectionChangedAction.Replace:
                    // Don't check arguments if app targets 4.0, for compat ( 726682)
                    if (!FrameworkCompatibilityPreferences.TargetsDesktop_V4_0)
                    {
                        if (args.OldItems.Count != 1)
                            throw new NotSupportedException(SR.RangeActionsNotSupported);
                    }
                    OnItemReplaced(args.OldItems[0], args.NewItems[0], args.NewStartingIndex);
                    break;

View on GitHub (pinned to 81131a70a4)