public static IDisposable OnItems <TSource>(this INotifyCollectionChanged notifyingCollection, Func <TSource, IDisposable> onNewItem) { if (notifyingCollection == null) { throw new ArgumentNullException("notifyingCollection"); } var collection = (ICollection)notifyingCollection; var subscriptions = new Dictionary <TSource, IDisposable>(); var handleNewItem = new Action <TSource>(item => subscriptions.Add(item, onNewItem(item))); var handleOldItem = new Action <TSource>(item => { IDisposable subscription; if (subscriptions.TryGetValue(item, out subscription)) { subscriptions.Remove(item); subscription.Dispose(); } }); var handleDispose = new Action(() => { foreach (var item in subscriptions.Keys.ToArray()) { handleOldItem(item); } }); foreach (var item in collection.OfType <TSource>()) { handleNewItem(item); } var collectionObservation = notifyingCollection.ObserveCollection() .Subscribe(e => { switch (e.Action) { case NotifyCollectionChangedAction.Add: if (e.NewItems != null) { foreach (var item in e.NewItems.OfType <TSource>()) { handleNewItem(item); } } break; case NotifyCollectionChangedAction.Remove: if (e.OldItems != null) { foreach (var item in e.OldItems.OfType <TSource>()) { handleOldItem(item); } } break; case NotifyCollectionChangedAction.Replace: if (e.OldItems != null) { foreach (var item in e.OldItems.OfType <TSource>()) { handleOldItem(item); } } if (e.NewItems != null) { foreach (var item in e.NewItems.OfType <TSource>()) { handleNewItem(item); } } break; case NotifyCollectionChangedAction.Reset: handleDispose(); if (e.NewItems != null) { foreach (var item in e.NewItems.OfType <TSource>()) { handleNewItem(item); } } break; } }); return(Disposable.Create(() => { handleDispose(); collectionObservation.Dispose(); })); }