@@ -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