@@ -105,7 +105,19 @@ public class OrderedPairedData : IList<Ordinate>, INotifyCollectionChanged
105105 private List < Ordinate > _ordinates ;
106106
107107 /// <inheritdoc/>
108- public event NotifyCollectionChangedEventHandler CollectionChanged ;
108+ public event NotifyCollectionChangedEventHandler ? CollectionChanged ;
109+
110+ /// <summary>
111+ /// Gets or sets a value indicating whether collection changed events are suppressed.
112+ /// </summary>
113+ /// <remarks>
114+ /// <para>
115+ /// Set this to <c>true</c> before performing a batch of mutations and then
116+ /// call <see cref="RaiseCollectionChangedReset"/> when the batch is complete.
117+ /// This avoids firing an event for every individual mutation.
118+ /// </para>
119+ /// </remarks>
120+ public bool SuppressCollectionChanged { get ; set ; } = false ;
109121
110122 /// <summary>
111123 /// Represents if the paired dataset has valid ordinates and order.
@@ -265,20 +277,24 @@ public OrderedPairedData(XElement el)
265277 {
266278 // Get Strictness
267279 bool strict = false ;
268- if ( el . Attribute ( nameof ( StrictX ) ) != null ) { bool . TryParse ( el . Attribute ( nameof ( StrictX ) ) . Value , out strict ) ; }
280+ var strictXAttr = el . Attribute ( nameof ( StrictX ) ) ;
281+ if ( strictXAttr != null ) { bool . TryParse ( strictXAttr . Value , out strict ) ; }
269282 StrictX = strict ;
270283
271284 strict = false ;
272- if ( el . Attribute ( nameof ( StrictY ) ) != null ) { bool . TryParse ( el . Attribute ( nameof ( StrictY ) ) . Value , out strict ) ; }
285+ var strictYAttr = el . Attribute ( nameof ( StrictY ) ) ;
286+ if ( strictYAttr != null ) { bool . TryParse ( strictYAttr . Value , out strict ) ; }
273287 StrictY = strict ;
274288
275289 // Get Order
276290 SortOrder order = SortOrder . None ;
277- if ( el . Attribute ( nameof ( OrderX ) ) != null ) { Enum . TryParse ( el . Attribute ( nameof ( OrderX ) ) . Value , out order ) ; }
291+ var orderXAttr = el . Attribute ( nameof ( OrderX ) ) ;
292+ if ( orderXAttr != null ) { Enum . TryParse ( orderXAttr . Value , out order ) ; }
278293 OrderX = order ;
279294
280295 order = SortOrder . None ;
281- if ( el . Attribute ( nameof ( OrderY ) ) != null ) { Enum . TryParse ( el . Attribute ( nameof ( OrderY ) ) . Value , out order ) ; }
296+ var orderYAttr = el . Attribute ( nameof ( OrderY ) ) ;
297+ if ( orderYAttr != null ) { Enum . TryParse ( orderYAttr . Value , out order ) ; }
282298 OrderY = order ;
283299
284300 // Ordinates
@@ -299,6 +315,22 @@ public OrderedPairedData(XElement el)
299315
300316 #region Methods
301317
318+ /// <summary>
319+ /// Raises a <see cref="NotifyCollectionChangedAction.Reset"/> event
320+ /// unconditionally, regardless of the <see cref="SuppressCollectionChanged"/> flag.
321+ /// </summary>
322+ /// <remarks>
323+ /// <para>
324+ /// Call this after a bulk operation once <see cref="SuppressCollectionChanged"/>
325+ /// has been set back to <c>false</c> (or while still <c>true</c> if desired)
326+ /// to notify listeners that the collection has changed.
327+ /// </para>
328+ /// </remarks>
329+ public void RaiseCollectionChangedReset ( )
330+ {
331+ CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Reset ) ) ;
332+ }
333+
302334 /// <summary>
303335 /// Get or set the ordinate at a specified index.
304336 /// </summary>
@@ -321,14 +353,11 @@ public Ordinate this[int index]
321353 {
322354 if ( OrdinateValid ( index ) == true ) { Validate ( ) ; }
323355 }
324- //
325- //We might need to add this check if performance suffers
326- //if (SupressCollectionChanged == false)
327- //{
328- CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Replace , value , oldValue ) ) ;
329- //}
356+ if ( SuppressCollectionChanged == false )
357+ {
358+ CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Replace , value , oldValue , index ) ) ;
359+ }
330360 }
331-
332361 }
333362 }
334363
@@ -427,7 +456,8 @@ public bool Remove(Ordinate item)
427456 if ( itemIndex == - 1 ) return false ;
428457 _ordinates . RemoveAt ( itemIndex ) ;
429458 Validate ( ) ;
430- CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Remove , item , itemIndex ) ) ;
459+ if ( SuppressCollectionChanged == false )
460+ CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Remove , item , itemIndex ) ) ;
431461 return true ;
432462 }
433463
@@ -441,7 +471,8 @@ public void RemoveAt(int index)
441471 var item = _ordinates [ index ] ;
442472 _ordinates . RemoveAt ( index ) ;
443473 Validate ( ) ;
444- CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Remove , item , index ) ) ;
474+ if ( SuppressCollectionChanged == false )
475+ CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Remove , item , index ) ) ;
445476 }
446477
447478 /// <summary>
@@ -456,7 +487,8 @@ public void RemoveRange(int index, int count)
456487 for ( int i = index ; i < count ; i ++ ) { items . Add ( _ordinates [ i ] ) ; }
457488 _ordinates . RemoveRange ( index , count ) ;
458489 Validate ( ) ;
459- CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Remove , items , index ) ) ;
490+ if ( SuppressCollectionChanged == false )
491+ CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Remove , items , index ) ) ;
460492 }
461493
462494 /// <summary>
@@ -467,7 +499,8 @@ public void Add(Ordinate item)
467499 {
468500 _ordinates . Add ( item ) ;
469501 IsValid = OrdinateValid ( _ordinates . Count - 1 ) ;
470- CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Add , item , _ordinates . Count - 1 ) ) ;
502+ if ( SuppressCollectionChanged == false )
503+ CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Add , item , _ordinates . Count - 1 ) ) ;
471504 }
472505
473506 /// <summary>
@@ -480,17 +513,26 @@ public void Insert(int index, Ordinate item)
480513 _ordinates . Insert ( index , item ) ;
481514 // only need to set valid state if it is true. if it is already false then inserting can't make it true.
482515 if ( IsValid ) IsValid = OrdinateValid ( index ) ;
483- CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Add , item , index ) ) ;
516+ if ( SuppressCollectionChanged == false )
517+ CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Add , item , index ) ) ;
484518 }
485519
486520 /// <summary>
487521 /// Removes all ordinates form the collection and sets count to zero.
488522 /// </summary>
489523 public void Clear ( )
490524 {
525+ if ( _ordinates . Count == 0 )
526+ return ;
527+
528+ bool wasSuppressed = SuppressCollectionChanged ;
529+ SuppressCollectionChanged = true ;
491530 _ordinates . Clear ( ) ;
531+ SuppressCollectionChanged = wasSuppressed ;
532+
492533 IsValid = true ;
493- CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Reset ) ) ;
534+ if ( SuppressCollectionChanged == false )
535+ CollectionChanged ? . Invoke ( this , new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction . Reset ) ) ;
494536 }
495537
496538 /// <summary>
@@ -612,7 +654,7 @@ IEnumerator IEnumerable.GetEnumerator()
612654 /// </summary>
613655 /// <param name="obj">The object to compare with the current object.</param>
614656 /// <returns>True if the specified object is equal to the current object; otherwise, False.</returns>
615- public override bool Equals ( object obj )
657+ public override bool Equals ( object ? obj )
616658 {
617659 if ( obj is OrderedPairedData other )
618660 {
@@ -1432,7 +1474,7 @@ private double TriangleArea(Ordinate point1, Ordinate point2, Ordinate point3)
14321474 /// and number of points in the search region.</returns>
14331475 public OrderedPairedData LangSimplify ( double tolerance , int lookAhead )
14341476 {
1435- if ( _ordinates == null | lookAhead <= 1 | tolerance <= 0 )
1477+ if ( _ordinates == null || lookAhead <= 1 | | tolerance <= 0 )
14361478 return this ;
14371479
14381480 List < Ordinate > ordinates = new List < Ordinate > ( ) ;
0 commit comments