stride3d/stride · error · InvalidOperationException

PropertyChanged is invoked without PropertyChanging, or…

Error message

PropertyChanged is invoked without PropertyChanging, or multiple items in the collection are changing concurrently.

What it means

ItemPropertyChanged validates that a PropertyChanged notification is matched by a prior PropertyChanging for the same item. If both ChangingItem and AddedItem are set (a new item was added while another item reports a property change) the tracking state is inconsistent, so it throws. This can also fire when PropertyChanged arrives with no PropertyChanging at all.

Solutions

  1. Raise PropertyChanging before every PropertyChanged for the same property on the same object (use SetProperty/PropertyChangedBase helpers)
  2. Do not add items to the collection while another item's property change is in flight
  3. Fix the item class's INotifyPropertyChanged ordering (Changing first, then Changed)
  4. Verify all item types derive from a base implementing correct change-notification pairs

Example fix

// before
public string Name
{
    get => name;
    set { name = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name))); }
}
// after
public string Name
{
    get => name;
    set
    {
        PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(nameof(Name)));
        name = value;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify item types raise Changing before Changed: raiseChanging(name); value = x; raiseChanged(name);

Try / catch

try { collection.Add(item); } catch (InvalidOperationException ex) { logger.Error(ex, "unmatched PropertyChanged"); }

Prevention

When it happens

Trigger: An item raising PropertyChanged without ever raising PropertyChanging; an item added to the collection inside another item's property-change scope; mis-ordered raise calls in a SetProperty helper.

Common situations: Hand-written setters that only raise PropertyChanged; adding items inside a property setter; third-party view-models with incomplete INotifyPropertyChanged implementations used as collection items.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/2dba06a8a2371959. Report an issue: GitHub.

Appendix: source

Thrown at sources/presentation/Stride.Core.Presentation/Collections/AutoUpdatingSortedObservableCollection.cs:132

            throw new InvalidOperationException("Multiple items in the collection are changing concurrently.");

        ++changeCount;

        ChangingItem = item;
        ChangingIndex = GetIndex(item, false);
        AddedItem = null;
    }

    protected virtual void ItemPropertyChanged(object? sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName is null || propertyNames?.Contains(e.PropertyName) == false)
            return;

        var item = (T?)sender;

        // An object has been added while a property of an existing object has been modified
        if (ChangingItem is not null && AddedItem is not null)
            throw new InvalidOperationException("PropertyChanged is invoked without PropertyChanging, or multiple items in the collection are changing concurrently.");

        // The object has been added to the collection during the property change, so it was not preregistered by the ItemPropertyChanging event
        if (ChangingItem is null && AddedItem is not null)
        {
            ChangingItem = AddedItem;
            ChangingIndex = AddedIndex;
            ++changeCount;
        }

        // No object is changing, or a different object is currently changing
        if (ChangingItem is null || !ReferenceEquals(ChangingItem, item))
        {
            throw new InvalidOperationException("PropertyChanged is invoked without PropertyChanging, or multiple items in the collection are changing concurrently.");
        }

        --changeCount;
        if (changeCount == 0)
        {

View on GitHub (pinned to 96fad776d2)