Observable Collection replace item Observable Collection replace item wpf wpf

Observable Collection replace item


Updated: Indexer uses overridden SetItem and notifies about changes.

I think the answer about using indexer may be wrong, because the question was about replace and notify.

Just to clarify: ObservableCollection<T> uses indexer from its base Collection<T> class, which in turn is a wrapper of List<T>, which is a wrapper of simple array of T. And there's no override for indexer method in ObservableCollection implementation.

So when you use indexer to replace an item in ObservableCollection it invokes the following code from Collection class:

public T this[int index] {        get { return items[index]; }        set {            if( items.IsReadOnly) {                ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);            }            if (index < 0 || index >= items.Count) {                ThrowHelper.ThrowArgumentOutOfRangeException();            }            SetItem(index, value);        }

It just checks boundaries and calls SetItem that uses indexer of underlying List class:

protected virtual void SetItem(int index, T item) {        items[index] = item;    }

During assignment there is no call to the CollectionChanged event, because underlying collections know nothing of it.

But when you use SetItem method, it is called from ObservableCollection class:

protected override void SetItem(int index, T item)    {        CheckReentrancy();        T originalItem = this[index];        base.SetItem(index, item);        OnPropertyChanged(IndexerName);        OnCollectionChanged(NotifyCollectionChangedAction.Replace, originalItem, item, index);    }

After assignment it calls OnCollectionChanged method, which fires CollectionChanged event with NotifyCollectionChangedAction.Replace action parameter.

    protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)    {        if (CollectionChanged != null)        {            using (BlockReentrancy())            {                CollectionChanged(this, e);            }        }    }

As a conclusion: the idea with custom class inherited from ObservableCollection and Replace method that calls base.SetItem() worth a try.