![]()
The System.InvalidOperationException with the message “Cannot change ObservableCollection during a CollectionChanged event” occurs in C# when you attempt to modify an ObservableCollection<T> while it is in the process of raising its CollectionChanged event. This typically happens when a handler for the CollectionChanged event modifies the collection, causing a re-entrant modification.
Common Causes and Solutions
- Modifying Collection in
CollectionChangedHandler:
If you modify the collection (e.g., add, remove, or clear items) inside aCollectionChangedevent handler, it will trigger the exception.
var collection = new ObservableCollection<int>();
collection.CollectionChanged += (sender, e) =>
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
collection.Add(42); // InvalidOperationException – Cannot modify collection during CollectionChanged event
}
};
collection.Add(10); // Triggers the exception
Fix: Avoid modifying the collection directly in the CollectionChanged handler. Use a queue or defer the modification.
var collection = new ObservableCollection<int>();
var pendingChanges = new Queue<int>();
collection.CollectionChanged += (sender, e) =>
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
pendingChanges.Enqueue(42); // Queue the change instead of applying it directly
}
};
collection.Add(10);
// Apply pending changes after the event is complete
while (pendingChanges.Count > 0)
{
collection.Add(pendingChanges.Dequeue());
}
- Nested Modifications:
If multipleCollectionChangedhandlers are registered and one handler modifies the collection while another is still processing, this exception can occur. Fix: Ensure that modifications are deferred or handled in a way that avoids re-entrant changes.
var collection = new ObservableCollection<int>();
var isProcessing = false;
collection.CollectionChanged += (sender, e) =>
{
if (isProcessing) return; // Avoid re-entrant modifications
isProcessing = true;
if (e.Action == NotifyCollectionChangedAction.Add)
{
// Perform modifications safely
collection.Add(42);
}
isProcessing = false;
};
collection.Add(10);
- Using
ObservableCollectionwith Data Binding:
In WPF or other UI frameworks, data binding can triggerCollectionChangedevents. Modifying the collection in response to these events can cause this exception. Fix: UseDispatcherto defer modifications until the event is complete.
var collection = new ObservableCollection<int>();
collection.CollectionChanged += (sender, e) =>
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
collection.Add(42); // Defer the modification
}));
}
};
collection.Add(10);
- Batch Updates:
If you need to make multiple changes to the collection, modifying it repeatedly duringCollectionChangedevents can trigger this exception. Fix: Use a temporary list or disable notifications temporarily.
var collection = new ObservableCollection<int>();
var tempList = new List<int>();
collection.CollectionChanged += (sender, e) =>
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
tempList.Add(42); // Store changes in a temporary list
}
};
collection.Add(10);
// Apply changes after the event is complete
foreach (var item in tempList)
{
collection.Add(item);
}
- Custom Collections:
If you are using a custom collection that inherits fromObservableCollection<T>, ensure that modifications are handled safely. Fix: Override methods likeInsertItemorRemoveItemto handle modifications safely.
public class SafeObservableCollection<T> : ObservableCollection<T>
{
protected override void InsertItem(int index, T item)
{
// Perform custom logic safely
base.InsertItem(index, item);
}
}
