/// <summary> /// Determines whether the specified object, is equal to this instance. /// </summary> /// <param name="other">The other.</param> /// <returns></returns> public bool Equals(Change <TObject, TKey> other) { return(Reason.Equals(other.Reason) && EqualityComparer <TKey> .Default.Equals(Key, other.Key) && EqualityComparer <TObject> .Default.Equals(Current, other.Current)); }
/// <summary> /// Removes the item from the specified index - intended for internal use only /// </summary> /// <param name="index"></param> /// <param name="item"></param> protected virtual void RemoveItem(int index, T item) { if (index < 0) { throw new ArgumentException($"{nameof(index)} cannot be negative"); } if (index > _innerList.Count) { throw new ArgumentException($"{nameof(index)} cannot be greater than the size of the collection"); } //attempt to batch updates as lists love to deal with ranges! (sorry if this code melts your mind) var last = Last; if (last.HasValue && last.Value.Reason == ListChangeReason.Remove) { //begin a new batch var firstOfBatch = _changes.Count - 1; var previousItem = last.Value.Item; if (index == previousItem.CurrentIndex) { _changes[firstOfBatch] = new Change <T>(ListChangeReason.RemoveRange, new[] { previousItem.Current, item }, index); } else if (index == previousItem.CurrentIndex - 1) { //Nb: double check this one as it is the same as clause above. Can it be correct? _changes[firstOfBatch] = new Change <T>(ListChangeReason.RemoveRange, new[] { item, previousItem.Current }, index); } else { _changes.Add(new Change <T>(ListChangeReason.Remove, item, index)); } } else if (last.HasValue && last.Value.Reason == ListChangeReason.RemoveRange) { //add to the end of the previous batch var range = last.Value.Range; if (range.Index == index) { //removed in order range.Add(item); } else if (range.Index == index - 1) { _changes.Add(new Change <T>(ListChangeReason.Remove, item, index)); } else if (range.Index == index + 1) { //removed in reverse order range.Insert(0, item); range.SetStartingIndex(index); } else { _changes.Add(new Change <T>(ListChangeReason.Remove, item, index)); } } else { //first remove, so cannot infer range _changes.Add(new Change <T>(ListChangeReason.Remove, item, index)); } _innerList.RemoveAt(index); }
private static void Clone <T>(this IList <T> source, Change <T> item) { var changeAware = source as ChangeAwareList <T>; switch (item.Reason) { case ListChangeReason.Add: { var change = item.Item; var hasIndex = change.CurrentIndex >= 0; if (hasIndex) { source.Insert(change.CurrentIndex, change.Current); } else { source.Add(change.Current); } break; } case ListChangeReason.AddRange: { source.AddOrInsertRange(item.Range, item.Range.Index); break; } case ListChangeReason.Clear: { source.ClearOrRemoveMany(item); break; } case ListChangeReason.Replace: { var change = item.Item; if (change.CurrentIndex >= 0 && change.CurrentIndex == change.PreviousIndex) { source[change.CurrentIndex] = change.Current; } else { //is this best? or replace + move? source.RemoveAt(change.PreviousIndex); source.Insert(change.CurrentIndex, change.Current); } break; } case ListChangeReason.Refresh: { changeAware?.RefreshAt(item.Item.CurrentIndex); break; } case ListChangeReason.Remove: { var change = item.Item; bool hasIndex = change.CurrentIndex >= 0; if (hasIndex) { source.RemoveAt(change.CurrentIndex); } else { source.Remove(change.Current); } break; } case ListChangeReason.RemoveRange: { //ignore this case because WhereReasonsAre removes the index [in which case call RemoveMany] //if (item.Range.Index < 0) // throw new UnspecifiedIndexException("ListChangeReason.RemoveRange should not have an index specified index"); if (item.Range.Index >= 0 && (source is IExtendedList <T> || source is List <T>)) { source.RemoveRange(item.Range.Index, item.Range.Count); } else { source.RemoveMany(item.Range); } break; } case ListChangeReason.Moved: { var change = item.Item; bool hasIndex = change.CurrentIndex >= 0; if (!hasIndex) { throw new UnspecifiedIndexException("Cannot move as an index was not specified"); } var extendedList = source as IExtendedList <T>; var observableCollection = source as ObservableCollection <T>; if (extendedList != null) { extendedList.Move(change.PreviousIndex, change.CurrentIndex); } else if (observableCollection != null) { observableCollection.Move(change.PreviousIndex, change.CurrentIndex); } else { //check this works whatever the index is source.RemoveAt(change.PreviousIndex); source.Insert(change.CurrentIndex, change.Current); } break; } } }
/// <summary> /// Inserts an item at the specified index /// </summary> /// <param name="index">the index where the item should be inserted</param> /// <param name="item"></param> protected virtual void InsertItem(int index, T item) { if (index < 0) { throw new ArgumentException($"{nameof(index)} cannot be negative"); } if (index > _innerList.Count) { throw new ArgumentException($"{nameof(index)} cannot be greater than the size of the collection"); } //attempt to batch updates as lists love to deal with ranges! (sorry if this code melts your mind) var last = Last; if (last.HasValue && last.Value.Reason == ListChangeReason.Add) { //begin a new batch if possible var firstOfBatch = _changes.Count - 1; var previousItem = last.Value.Item; if (index == previousItem.CurrentIndex) { _changes[firstOfBatch] = new Change <T>(ListChangeReason.AddRange, new[] { item, previousItem.Current }, index); } else if (index == previousItem.CurrentIndex + 1) { _changes[firstOfBatch] = new Change <T>(ListChangeReason.AddRange, new[] { previousItem.Current, item }, previousItem.CurrentIndex); } else { _changes.Add(new Change <T>(ListChangeReason.Add, item, index)); } } else if (last.HasValue && last.Value.Reason == ListChangeReason.AddRange) { //check whether the new item is in the specified range var range = last.Value.Range; var minimum = Math.Max(range.Index - 1, 0); var maximum = range.Index + range.Count; var isPartOfRange = index >= minimum && index <= maximum; if (!isPartOfRange) { _changes.Add(new Change <T>(ListChangeReason.Add, item, index)); } else { var insertPosition = index - range.Index; if (insertPosition < 0) { insertPosition = 0; } else if (insertPosition >= range.Count) { insertPosition = range.Count; } range.Insert(insertPosition, item); if (index < range.Index) { range.SetStartingIndex(index); } } } else { //first add, so cannot infer range _changes.Add(new Change <T>(ListChangeReason.Add, item, index)); } //finally, add the item _innerList.Insert(index, item); }
/// <summary> /// Adds the specified item. /// </summary> /// <param name="item">The item.</param> public void Add(Change <TObject, TKey> item) { Add(item, false); }