@@ -39,35 +39,50 @@ public class ObservableRangeCollection<T> : ObservableCollection<T>
3939 /// <summary>
4040 /// Initializes a new instance of <see cref="ObservableCollection{T}"/> that is empty and has default initial capacity.
4141 /// </summary>
42- public ObservableRangeCollection ( )
43- { }
42+ /// <param name="allowDuplicates">Whether duplicate items are allowed in the collection.</param>
43+ /// <param name="comparer">Support for <see cref="AllowDuplicates"/>.</param>
44+ public ObservableRangeCollection ( bool allowDuplicates = true , EqualityComparer < T > ? comparer = null )
45+ {
46+ AllowDuplicates = allowDuplicates ;
47+ Comparer = comparer ?? EqualityComparer < T > . Default ;
48+ }
4449
4550 /// <summary>
46- /// Initializes a new instance of the ObservableCollection class that contains
51+ /// Initializes a new instance of the <see cref=" ObservableCollection{T}"/> class that contains
4752 /// elements copied from the specified collection and has sufficient capacity
4853 /// to accommodate the number of elements copied.
4954 /// </summary>
5055 /// <param name="collection">The collection whose elements are copied to the new list.</param>
56+ /// <param name="allowDuplicates">Whether duplicate items are allowed in the collection.</param>
57+ /// <param name="comparer">Support for <see cref="AllowDuplicates"/>.</param>
5158 /// <remarks>
52- /// The elements are copied onto the ObservableCollection in the
59+ /// The elements are copied onto the <see cref=" ObservableCollection{T}"/> in the
5360 /// same order they are read by the enumerator of the collection.
5461 /// </remarks>
5562 /// <exception cref="ArgumentNullException"><paramref name="collection"/> is a null reference.</exception>
56- public ObservableRangeCollection ( IEnumerable < T > collection ) : base ( collection )
57- { }
63+ public ObservableRangeCollection ( IEnumerable < T > collection , bool allowDuplicates = true , EqualityComparer < T > ? comparer = null ) : base ( collection )
64+ {
65+ AllowDuplicates = allowDuplicates ;
66+ Comparer = comparer ?? EqualityComparer < T > . Default ;
67+ }
5868
5969 /// <summary>
60- /// Initializes a new instance of the ObservableCollection class
70+ /// Initializes a new instance of the <see cref=" ObservableCollection{T}"/> class
6171 /// that contains elements copied from the specified list.
6272 /// </summary>
6373 /// <param name="list">The list whose elements are copied to the new list.</param>
74+ /// <param name="allowDuplicates">Whether duplicate items are allowed in the collection.</param>
75+ /// <param name="comparer">Support for <see cref="AllowDuplicates"/>.</param>
6476 /// <remarks>
65- /// The elements are copied onto the ObservableCollection in the
77+ /// The elements are copied onto the <see cref=" ObservableCollection{T}"/> in the
6678 /// same order they are read by the enumerator of the list.
6779 /// </remarks>
6880 /// <exception cref="ArgumentNullException"><paramref name="list"/> is a null reference.</exception>
69- public ObservableRangeCollection ( List < T > list ) : base ( list )
70- { }
81+ public ObservableRangeCollection ( List < T > list , bool allowDuplicates = true , EqualityComparer < T > ? comparer = null ) : base ( list )
82+ {
83+ AllowDuplicates = allowDuplicates ;
84+ Comparer = comparer ?? EqualityComparer < T > . Default ;
85+ }
7186
7287 #endregion Constructors
7388
@@ -79,8 +94,6 @@ public ObservableRangeCollection(List<T> list) : base(list)
7994
8095 #region Public Properties
8196
82- private EqualityComparer < T > ? _comparer ;
83-
8497 /// <summary>
8598 /// Gets or sets a value indicating whether this collection acts as a <see cref="HashSet{T}"/>,
8699 /// disallowing duplicate items, based on <see cref="Comparer"/>.
@@ -92,11 +105,7 @@ public ObservableRangeCollection(List<T> list) : base(list)
92105 /// <summary>
93106 /// Support for <see cref="AllowDuplicates"/>.
94107 /// </summary>
95- public EqualityComparer < T > Comparer
96- {
97- get => _comparer ??= EqualityComparer < T > . Default ;
98- private set => _comparer = value ;
99- }
108+ public EqualityComparer < T > Comparer { get ; }
100109
101110 #endregion Public Properties
102111
@@ -182,7 +191,7 @@ public void InsertRange(int index, IEnumerable<T> collection)
182191 /// Iterates over the collection and removes all items that satisfy the specified match.
183192 /// </summary>
184193 /// <remarks>The complexity is O(n).</remarks>
185- /// <param name="match"></param>
194+ /// <param name="match">Match the item to be removed </param>
186195 /// <returns>Returns the number of elements that where </returns>
187196 /// <exception cref="ArgumentNullException"><paramref name="match"/> is null.</exception>
188197 public int RemoveAll ( Predicate < T > match )
@@ -192,11 +201,12 @@ public int RemoveAll(Predicate<T> match)
192201
193202 /// <summary>
194203 /// Iterates over the specified range within the collection and removes all items that satisfy the specified match.
204+ /// <para>NOTE: Consecutively matching elements will trigger the <see cref="ObservableCollection{T}.CollectionChanged"/> event at once.</para>
195205 /// </summary>
196206 /// <remarks>The complexity is O(n).</remarks>
197207 /// <param name="index">The index of where to start performing the search.</param>
198208 /// <param name="count">The number of items to iterate on.</param>
199- /// <param name="match"></param>
209+ /// <param name="match">Match the item to be removed. </param>
200210 /// <returns>Returns the number of elements that where.</returns>
201211 /// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is out of range.</exception>
202212 /// <exception cref="ArgumentOutOfRangeException"><paramref name="count"/> is out of range.</exception>
@@ -279,6 +289,7 @@ public int RemoveAll(int index, int count, Predicate<T> match)
279289
280290 /// <summary>
281291 /// Removes the first occurence of each item in the specified collection from the <see cref="ObservableCollection{T}"/>.
292+ /// <para>NOTE: Removed items starting index is not set because items are not guaranteed to be consecutive.</para>
282293 /// </summary>
283294 /// <param name="collection">The items to remove.</param>
284295 /// <exception cref="ArgumentNullException"><paramref name="collection"/> is null.</exception>
@@ -307,29 +318,16 @@ public void RemoveRange(IEnumerable<T> collection)
307318
308319 CheckReentrancy ( ) ;
309320
310- var clusters = new Dictionary < int , List < T > > ( ) ;
311- int lastIndex = - 1 ;
312- List < T > ? lastCluster = null ;
321+ bool raiseEvents = false ;
313322
314323 foreach ( var item in collection )
315324 {
316- int index = IndexOf ( item ) ;
317-
318- if ( index < 0 )
319- {
320- continue ;
321- }
322-
323- Items . RemoveAt ( index ) ;
325+ raiseEvents |= Items . Remove ( item ) ;
326+ }
324327
325- if ( lastIndex == index && lastCluster is not null )
326- {
327- lastCluster . Add ( item ) ;
328- }
329- else
330- {
331- clusters [ lastIndex = index ] = lastCluster = new List < T > { item } ;
332- }
328+ if ( ! raiseEvents )
329+ {
330+ return ;
333331 }
334332
335333 OnEssentialPropertiesChanged ( ) ;
@@ -376,6 +374,7 @@ public void RemoveRange(int index, int count)
376374 if ( count == 1 )
377375 {
378376 RemoveItem ( index ) ;
377+
379378 return ;
380379 }
381380
@@ -400,8 +399,7 @@ public void RemoveRange(int index, int count)
400399 }
401400
402401 /// <summary>
403- /// Clears the current collection and replaces it with the specified item,
404- /// using <see cref="Comparer"/>.
402+ /// Clears the current collection and replaces it with the specified item, using <see cref="Comparer"/>.
405403 /// </summary>
406404 /// <param name="item">The item to fill the collection with, after clearing it.</param>
407405 public void Replace ( T item )
@@ -410,8 +408,7 @@ public void Replace(T item)
410408 }
411409
412410 /// <summary>
413- /// Clears the current collection and replaces it with the specified collection,
414- /// using <see cref="Comparer"/>.
411+ /// Clears the current collection and replaces it with the specified collection, using <see cref="Comparer"/>.
415412 /// </summary>
416413 /// <param name="collection">The items to fill the collection with, after clearing it.</param>
417414 /// <exception cref="ArgumentNullException"><paramref name="collection"/> is null.</exception>
@@ -681,15 +678,15 @@ protected override void SetItem(int index, T item)
681678 #region Private Methods
682679
683680 /// <summary>
684- /// Helper to raise CollectionChanged event to any listeners
681+ /// Helper to raise CollectionChanged event to any listeners.
685682 /// </summary>
686683 private void OnCollectionChanged ( NotifyCollectionChangedAction action , object oldItem , object newItem , int index )
687684 {
688685 OnCollectionChanged ( new NotifyCollectionChangedEventArgs ( action , newItem , oldItem , index ) ) ;
689686 }
690687
691688 /// <summary>
692- /// Helper to raise CollectionChanged event with action == Reset to any listeners
689+ /// Helper to raise CollectionChanged event with action == Reset to any listeners.
693690 /// </summary>
694691 private void OnCollectionReset ( )
695692 {
@@ -706,8 +703,8 @@ private void OnEssentialPropertiesChanged()
706703 }
707704
708705 /// <summary>
709- /// /// Helper to raise a PropertyChanged event for the Indexer property
710- /// /// </summary>
706+ /// Helper to raise a PropertyChanged event for the Indexer property.
707+ /// </summary>
711708 private void OnIndexerPropertyChanged ( )
712709 {
713710 OnPropertyChanged ( EventArgsCache . IndexerPropertyChanged ) ;
0 commit comments