Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ public class ObservableCollection<T> : Collection<T>, INotifyCollectionChanged,
[NonSerialized]
private int _blockReentrancyCount;

[NonSerialized]
private bool _skipRaisingEvents;

/// <summary>
/// <c>true</c> to opt into raising <see cref="NotifyCollectionChangedEventArgs"/> with list
/// of items when a range is inserted, removed or replaced. Instead of resets
/// </summary>
private static bool RaiseBatchCollectionChangedEvents => false;

/// <summary>
/// Initializes a new instance of ObservableCollection that is empty and has default initial capacity.
/// </summary>
Expand Down Expand Up @@ -107,9 +116,116 @@ protected override void RemoveItem(int index)

base.RemoveItem(index);

OnCountPropertyChanged();
OnIndexerPropertyChanged();
OnCollectionChanged(NotifyCollectionChangedAction.Remove, removedItem, index);
if (!_skipRaisingEvents)
{
OnCountPropertyChanged();
OnIndexerPropertyChanged();
OnCollectionChanged(NotifyCollectionChangedAction.Remove, removedItem, index);
}
}

/// <summary>
/// Called by base class Collection&lt;T&gt; when a count of items is removed from the list;
/// raises a CollectionChanged event to any listeners.
/// </summary>
protected override void RemoveItemsRange(int index, int count)
{
CheckReentrancy();

NotifyCollectionChangedEventArgs collectionChangedEventArgs = EventArgsCache.ResetCollectionChanged;
bool skipEvents = _skipRaisingEvents;
if (!skipEvents)
{
_skipRaisingEvents = true;

if (RaiseBatchCollectionChangedEvents && count > 0 && CollectionChanged is not null)
{
T[] removedItems = new T[count];
for (int i = 0; i < count; i++)
{
removedItems[i] = this[index + i];
}

collectionChangedEventArgs = new(NotifyCollectionChangedAction.Remove, removedItems, index);
}
}

try
{
base.RemoveItemsRange(index, count);
}
finally
{
if (!skipEvents)
{
_skipRaisingEvents = false;
}
}

if (count > 0 && !_skipRaisingEvents)
{
OnCountPropertyChanged();
OnIndexerPropertyChanged();
OnCollectionChanged(collectionChangedEventArgs);
}
}

/// <summary>
/// Called by base class Collection&lt;T&gt; when a collection of items is added to list;
/// raises a CollectionChanged event to any listeners.
/// </summary>
protected override void ReplaceItemsRange(int index, int count, IEnumerable<T> collection)
{
CheckReentrancy();

int countBefore = default;
bool skipEvents = _skipRaisingEvents;
if (!skipEvents)
{
_skipRaisingEvents = true;
countBefore = Count;
}

NotifyCollectionChangedEventArgs collectionChangedEventArgs = EventArgsCache.ResetCollectionChanged;
if (!skipEvents && RaiseBatchCollectionChangedEvents && CollectionChanged is not null)
{
T[] itemsToReplace = new T[count];
for (int i = 0; i < count; i++)
{
itemsToReplace[i] = this[i + index];
}

IList newItems = collection as IList ?? new List<T>(collection);
collectionChangedEventArgs = new(NotifyCollectionChangedAction.Replace, newItems, itemsToReplace, index);
}

try
{
base.ReplaceItemsRange(index, count, collection);
}
finally
{
if (!skipEvents)
{
_skipRaisingEvents = false;
}
}

if (!skipEvents)
{
if (countBefore != Count)
{
OnCountPropertyChanged();
OnIndexerPropertyChanged();
OnCollectionChanged(collectionChangedEventArgs);
}
else if (count > 0)
{
// We replaced positive number of items with the same number of items, only the contents changed
OnIndexerPropertyChanged();
OnCollectionChanged(collectionChangedEventArgs);
}
}
}

/// <summary>
Expand All @@ -121,9 +237,58 @@ protected override void InsertItem(int index, T item)
CheckReentrancy();
base.InsertItem(index, item);

OnCountPropertyChanged();
OnIndexerPropertyChanged();
OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
if (!_skipRaisingEvents)
{
OnCountPropertyChanged();
OnIndexerPropertyChanged();
OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
}
}

/// <summary>
/// Called by base class Collection&lt;T&gt; when a collection of items is added to list;
/// raises a CollectionChanged event to any listeners.
/// </summary>
protected override void InsertItemsRange(int index, IEnumerable<T> collection)
{
CheckReentrancy();

int countBefore = default;
bool skipEvents = _skipRaisingEvents;
if (!skipEvents)
{
_skipRaisingEvents = true;
countBefore = Count;
}

try
{
base.InsertItemsRange(index, collection);
}
finally
{
if (!skipEvents)
{
_skipRaisingEvents = false;
}
}

if (!_skipRaisingEvents)
{
NotifyCollectionChangedEventArgs collectionChangedEventArgs = EventArgsCache.ResetCollectionChanged;
if (RaiseBatchCollectionChangedEvents && CollectionChanged is not null)
{
IList newItems = collection as IList ?? new List<T>(collection);
collectionChangedEventArgs = new(NotifyCollectionChangedAction.Add, newItems, index);
}

if (countBefore != Count)
{
OnCountPropertyChanged();
OnIndexerPropertyChanged();
OnCollectionChanged(collectionChangedEventArgs);
}
}
}

/// <summary>
Expand Down
Loading