private void Update(Chunk <NotifyCollectionChangedEventArgs> changes) { if (changes == null || changes.Count == 0) { return; } using (changes.ClearTransaction()) { if (changes.Count > 1) { this.Refresh(changes); return; } var e = changes[0]; switch (e.Action) { case NotifyCollectionChangedAction.Add: { if (!e.TryGetSingleNewItem(out TSource newSource)) { goto case NotifyCollectionChangedAction.Reset; } var index = e.NewStartingIndex; var value = this.GetOrCreate(newSource, index); this.Tracker.Insert(index, value); var args = this.UpdateRange(index + 1, this.Count - 1); args.Add(Diff.CreateAddEventArgs(value, index)); this.Notify(args); break; } case NotifyCollectionChangedAction.Remove: { if (!e.TryGetSingleOldItem(out TSource oldSource)) { goto case NotifyCollectionChangedAction.Reset; } var index = e.OldStartingIndex; var value = this.Tracker[index]; this.Tracker.RemoveAt(index); var argses = this.UpdateRange(index, this.Count - 1); argses.Add(Diff.CreateRemoveEventArgs(value, index)); this.Notify(argses); this.factory.Remove(oldSource, value); break; } case NotifyCollectionChangedAction.Replace: { if (!e.TryGetSingleNewItem(out TSource newSource) || !e.TryGetSingleOldItem(out TSource oldSource)) { goto case NotifyCollectionChangedAction.Reset; } var index = e.NewStartingIndex; var value = this.GetOrCreate(newSource, index); var oldValue = this.Tracker[e.OldStartingIndex]; this.Tracker[index] = value; var arg = Diff.CreateReplaceEventArgs(value, oldValue, index); this.Notify(arg); this.factory.Remove(oldSource, oldValue); break; } case NotifyCollectionChangedAction.Move: { var value = this.Tracker[e.OldStartingIndex]; this.Tracker.RemoveAt(e.OldStartingIndex); this.Tracker.Insert(e.NewStartingIndex, value); var args = this.UpdateRange(Math.Min(e.OldStartingIndex, e.NewStartingIndex), Math.Max(e.OldStartingIndex, e.NewStartingIndex)); args.Add(Diff.CreateMoveEventArgs(value, e.NewStartingIndex, e.OldStartingIndex)); this.Notify(args); break; } case NotifyCollectionChangedAction.Reset: using (this.factory.RefreshTransaction()) { this.Refresh(changes); } break; default: throw new ArgumentOutOfRangeException(nameof(changes)); } } }
protected virtual void OnSourceCollectionChanged(IReadOnlyList <NotifyCollectionChangedEventArgs> changeCollection) { if (changeCollection == null || changeCollection.Count == 0) { return; } if (changeCollection.Count > 1) { this.Refresh(); return; } var singleChange = changeCollection[0]; try { switch (singleChange.Action) { case NotifyCollectionChangedAction.Add: { var index = singleChange.NewStartingIndex; var value = this.GetOrCreateValue(this.source.ElementAt(index), index); this.mapped.Insert(index, value); var changes = this.UpdateIndicesFrom(index + 1); var change = Diff.CreateAddEventArgs(value, index); changes.Add(change); base.Refresh(changes); break; } case NotifyCollectionChangedAction.Remove: { var index = singleChange.OldStartingIndex; var value = this.mapped[index]; this.mapped.RemoveAt(index); var changes = this.UpdateIndicesFrom(index); var change = Diff.CreateRemoveEventArgs(value, index); changes.Add(change); base.Refresh(changes); break; } case NotifyCollectionChangedAction.Replace: { var index = singleChange.NewStartingIndex; var value = this.GetOrCreateValue(this.source.ElementAt(index), index); var oldValue = this.mapped[singleChange.OldStartingIndex]; this.mapped[index] = value; var change = Diff.CreateReplaceEventArgs(value, oldValue, index); base.Refresh(new[] { change }); break; } case NotifyCollectionChangedAction.Move: { var value = this.mapped[singleChange.OldStartingIndex]; this.mapped.RemoveAt(singleChange.OldStartingIndex); this.mapped.Insert(singleChange.NewStartingIndex, value); this.UpdateIndex(singleChange.OldStartingIndex); this.UpdateIndex(singleChange.NewStartingIndex); var change = Diff.CreateMoveEventArgs(this.mapped[singleChange.NewStartingIndex], singleChange.NewStartingIndex, singleChange.OldStartingIndex); base.Refresh(new[] { change }); break; } case NotifyCollectionChangedAction.Reset: this.Refresh(); break; default: throw new ArgumentOutOfRangeException(); } } catch (Exception) { this.Refresh(); // Resetting } }