If you’ve ever consumed INotifyCollectionChanged.CollectionChanged, then you’ve run into some inadequate documentation for NotifyCollectionChangedEventArgs. I’ve added the following information to the MSDN “community extensions” (my first contribution), but others have had problems with the stability of community extensions, so the results of my research and Reflector spelunking are also in this blog entry.

In short, the value of the Action property determines the validity of other properties in this class. NewItems and OldItems are null when they are invalid; NewStartingIndex and OldStartingIndex are -1 when they are invalid.

If Action is NotifyCollectionChangedAction.Add, then NewItems contains the items that were added. In addition, if NewStartingIndex is not -1, then it contains the index where the new items were added.

If Action is NotifyCollectionChangedAction.Remove, then OldItems contains the items that were removed. In addition, if OldStartingIndex is not -1, then it contains the index where the old items were removed.

If Action is NotifyCollectionChangedAction.Replace, then OldItems contains the replaced items and NewItems contains the replacement items. In addition, NewStartingIndex and OldStartingIndex are equal, and if they are not -1, then they contain the index where the items were replaced.

If Action is NotifyCollectionChangedAction.Move, then NewItems and OldItems are logically equivalent (i.e., they are SequenceEqual, even if they are different instances), and they contain the items that moved. In addition, OldStartingIndex contains the index where the items were moved from, and NewStartingIndex contains the index where the items were moved to. A Move operation is logically treated as a Remove followed by an Add, so NewStartingIndex is interpreted as though the items had already been removed.

If Action is NotifyCollectionChangedAction.Reset, then no other properties are valid.

Sources

There are two blog entries that helped me get started: Making Sense of NotifyCollectionChangedEventArgs and An Alternative to ObservableCollection. However, more details were still lacking; fortunately, Reflector saved the day! The primary .NET sources were: [WindowsBase.dll, 3.0.0.0] System.Collections.ObjectModel.ObservableCollection<T> - SetItem, RemoveItem, MoveItem, etc.; and [PresentationFramework.dll, 3.0.0.0] System.Windows.Data.CollectionView - ProcessCollectionChanged, AdjustCurrencyFor*.