Beispiel #1
0
 /// <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));
 }
Beispiel #2
0
        /// <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);
        }
Beispiel #3
0
        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;
            }
            }
        }
Beispiel #4
0
        /// <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);
        }
Beispiel #5
0
 /// <summary>
 /// Adds the specified item.
 /// </summary>
 /// <param name="item">The item.</param>
 public void Add(Change <TObject, TKey> item)
 {
     Add(item, false);
 }