@@ -39,35 +39,50 @@ public class ObservableRangeCollection<T> : ObservableCollection<T>
39
39
/// <summary>
40
40
/// Initializes a new instance of <see cref="ObservableCollection{T}"/> that is empty and has default initial capacity.
41
41
/// </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
+ }
44
49
45
50
/// <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
47
52
/// elements copied from the specified collection and has sufficient capacity
48
53
/// to accommodate the number of elements copied.
49
54
/// </summary>
50
55
/// <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>
51
58
/// <remarks>
52
- /// The elements are copied onto the ObservableCollection in the
59
+ /// The elements are copied onto the <see cref=" ObservableCollection{T}"/> in the
53
60
/// same order they are read by the enumerator of the collection.
54
61
/// </remarks>
55
62
/// <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
+ }
58
68
59
69
/// <summary>
60
- /// Initializes a new instance of the ObservableCollection class
70
+ /// Initializes a new instance of the <see cref=" ObservableCollection{T}"/> class
61
71
/// that contains elements copied from the specified list.
62
72
/// </summary>
63
73
/// <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>
64
76
/// <remarks>
65
- /// The elements are copied onto the ObservableCollection in the
77
+ /// The elements are copied onto the <see cref=" ObservableCollection{T}"/> in the
66
78
/// same order they are read by the enumerator of the list.
67
79
/// </remarks>
68
80
/// <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
+ }
71
86
72
87
#endregion Constructors
73
88
@@ -79,8 +94,6 @@ public ObservableRangeCollection(List<T> list) : base(list)
79
94
80
95
#region Public Properties
81
96
82
- private EqualityComparer < T > ? _comparer ;
83
-
84
97
/// <summary>
85
98
/// Gets or sets a value indicating whether this collection acts as a <see cref="HashSet{T}"/>,
86
99
/// disallowing duplicate items, based on <see cref="Comparer"/>.
@@ -92,11 +105,7 @@ public ObservableRangeCollection(List<T> list) : base(list)
92
105
/// <summary>
93
106
/// Support for <see cref="AllowDuplicates"/>.
94
107
/// </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 ; }
100
109
101
110
#endregion Public Properties
102
111
@@ -182,7 +191,7 @@ public void InsertRange(int index, IEnumerable<T> collection)
182
191
/// Iterates over the collection and removes all items that satisfy the specified match.
183
192
/// </summary>
184
193
/// <remarks>The complexity is O(n).</remarks>
185
- /// <param name="match"></param>
194
+ /// <param name="match">Match the item to be removed </param>
186
195
/// <returns>Returns the number of elements that where </returns>
187
196
/// <exception cref="ArgumentNullException"><paramref name="match"/> is null.</exception>
188
197
public int RemoveAll ( Predicate < T > match )
@@ -192,11 +201,12 @@ public int RemoveAll(Predicate<T> match)
192
201
193
202
/// <summary>
194
203
/// 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>
195
205
/// </summary>
196
206
/// <remarks>The complexity is O(n).</remarks>
197
207
/// <param name="index">The index of where to start performing the search.</param>
198
208
/// <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>
200
210
/// <returns>Returns the number of elements that where.</returns>
201
211
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is out of range.</exception>
202
212
/// <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)
279
289
280
290
/// <summary>
281
291
/// 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>
282
293
/// </summary>
283
294
/// <param name="collection">The items to remove.</param>
284
295
/// <exception cref="ArgumentNullException"><paramref name="collection"/> is null.</exception>
@@ -307,29 +318,16 @@ public void RemoveRange(IEnumerable<T> collection)
307
318
308
319
CheckReentrancy ( ) ;
309
320
310
- var clusters = new Dictionary < int , List < T > > ( ) ;
311
- int lastIndex = - 1 ;
312
- List < T > ? lastCluster = null ;
321
+ bool raiseEvents = false ;
313
322
314
323
foreach ( var item in collection )
315
324
{
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
+ }
324
327
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 ;
333
331
}
334
332
335
333
OnEssentialPropertiesChanged ( ) ;
@@ -376,6 +374,7 @@ public void RemoveRange(int index, int count)
376
374
if ( count == 1 )
377
375
{
378
376
RemoveItem ( index ) ;
377
+
379
378
return ;
380
379
}
381
380
@@ -400,8 +399,7 @@ public void RemoveRange(int index, int count)
400
399
}
401
400
402
401
/// <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"/>.
405
403
/// </summary>
406
404
/// <param name="item">The item to fill the collection with, after clearing it.</param>
407
405
public void Replace ( T item )
@@ -410,8 +408,7 @@ public void Replace(T item)
410
408
}
411
409
412
410
/// <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"/>.
415
412
/// </summary>
416
413
/// <param name="collection">The items to fill the collection with, after clearing it.</param>
417
414
/// <exception cref="ArgumentNullException"><paramref name="collection"/> is null.</exception>
@@ -681,15 +678,15 @@ protected override void SetItem(int index, T item)
681
678
#region Private Methods
682
679
683
680
/// <summary>
684
- /// Helper to raise CollectionChanged event to any listeners
681
+ /// Helper to raise CollectionChanged event to any listeners.
685
682
/// </summary>
686
683
private void OnCollectionChanged ( NotifyCollectionChangedAction action , object oldItem , object newItem , int index )
687
684
{
688
685
OnCollectionChanged ( new NotifyCollectionChangedEventArgs ( action , newItem , oldItem , index ) ) ;
689
686
}
690
687
691
688
/// <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.
693
690
/// </summary>
694
691
private void OnCollectionReset ( )
695
692
{
@@ -706,8 +703,8 @@ private void OnEssentialPropertiesChanged()
706
703
}
707
704
708
705
/// <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>
711
708
private void OnIndexerPropertyChanged ( )
712
709
{
713
710
OnPropertyChanged ( EventArgsCache . IndexerPropertyChanged ) ;
0 commit comments