public static void Move <T>(this ThreadSafeBindingList <T> lstCollection, int intOldIndex, int intNewIndex) { using (lstCollection.LockObject.EnterWriteLock()) { bool blnOldRaiseListChangedEvents = lstCollection.RaiseListChangedEvents; try { lstCollection.RaiseListChangedEvents = false; int intParity = intOldIndex < intNewIndex ? 1 : -1; for (int i = intOldIndex; i != intNewIndex; i += intParity) { (lstCollection[intOldIndex + intParity], lstCollection[intOldIndex]) = ( lstCollection[intOldIndex], lstCollection[intOldIndex + intParity]); } } finally { lstCollection.RaiseListChangedEvents = blnOldRaiseListChangedEvents; } } }
/// <summary> /// Sorts the elements in a range of elements in an ObservableCollection using the specified /// System.Collections.Generic.IComparer`1 generic interface. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="lstCollection">The ObservableCollection to sort.</param> /// <param name="objComparer">The System.Collections.Generic.IComparer`1 generic interface /// implementation to use when comparing elements, or null to use the System.IComparable`1 generic /// interface implementation of each element.</param> public static void Sort <T>(this ThreadSafeBindingList <T> lstCollection, IComparer <T> objComparer = null) where T : IComparable { if (lstCollection == null) { throw new ArgumentNullException(nameof(lstCollection)); } using (EnterReadLock.Enter(lstCollection.LockObject)) { T[] aobjSorted = new T[lstCollection.Count]; for (int i = 0; i < lstCollection.Count; ++i) { aobjSorted[i] = lstCollection[i]; } Array.Sort(aobjSorted, objComparer); bool blnOldRaiseListChangedEvents = lstCollection.RaiseListChangedEvents; // Not BitArray because read/write performance is much more important here than memory footprint bool[] ablnItemChanged = blnOldRaiseListChangedEvents ? new bool[aobjSorted.Length] : null; using (lstCollection.LockObject.EnterWriteLock()) { // We're going to disable events while we work with the list, then call them all at once at the end lstCollection.RaiseListChangedEvents = false; for (int i = 0; i < aobjSorted.Length; ++i) { T objLoop = aobjSorted[i]; int intOldIndex = lstCollection.IndexOf(objLoop); int intNewIndex = i; if (intOldIndex == intNewIndex) { continue; } if (intOldIndex > intNewIndex) { // Account for removal happening before removal --intOldIndex; if (blnOldRaiseListChangedEvents) { for (int j = intNewIndex; j <= intOldIndex; ++j) { ablnItemChanged[j] = true; } } } else { // Account for removal happening before removal --intNewIndex; if (blnOldRaiseListChangedEvents) { for (int j = intOldIndex; j <= intNewIndex; ++j) { ablnItemChanged[j] = true; } } } lstCollection.RemoveAt(intOldIndex); lstCollection.Insert(intNewIndex, objLoop); } lstCollection.RaiseListChangedEvents = blnOldRaiseListChangedEvents; if (!blnOldRaiseListChangedEvents) { return; } // If at least half of the list was changed, call a reset event instead of a large amount of ItemChanged events int intResetThreshold = ablnItemChanged.Length / 2; int intCountTrues = 0; // ReSharper disable once ForCanBeConvertedToForeach for (int i = 0; i < ablnItemChanged.Length; ++i) { if (ablnItemChanged[i]) { ++intCountTrues; if (intCountTrues >= intResetThreshold) { lstCollection.ResetBindings(); return; } } } for (int i = 0; i < ablnItemChanged.Length; ++i) { if (ablnItemChanged[i]) { lstCollection.ResetItem(i); } } } } }