开发者

Observable Collection replace item

I have a ObservableCollection, I can add and remove item from the collection. But I can't replace an existing item in the collection. There is a way to replace an item and reflect that on my bound开发者_StackOverflow components.

System.Collections.Specialized.NotifyCollectionChangedAction.Replace

Can anyone please show me how to accomplish this?


collection[someIndex] = newItem;


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.


Simple extension method for replace item in observable collection:

public static void ReplaceItem<T>(this ObservableCollection<T> items, Func<T, bool> predicate, T newItem)
{
    for (int i = 0; i < items.Count; i++)
    {
        if (predicate(items[i]))
        {
            items[i] = newItem;
            break;
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜