ObservableCollection :使用多个新项目调用 OnCollectionChanged [英] ObservableCollection : calling OnCollectionChanged with multiple new items

查看:23
本文介绍了ObservableCollection :使用多个新项目调用 OnCollectionChanged的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请注意,我正在尝试使用 NotifyCollectionChangedAction.Add 操作而不是 .Reset.后者确实有效,但对于大型集合来说效率不高.

please note that I am trying to use NotifyCollectionChangedAction.Add action instead of .Reset. the latter does work, but it is not very efficient with large collections.

所以我继承了 ObservableCollection:

so i subclassed ObservableCollection:

public class SuspendableObservableCollection<T> : ObservableCollection<T>

出于某种原因,此代码:

for some reason, this code:

private List<T> _cachedItems;
...

    public void FlushCache() {
        if (_cachedItems.Count > 0) {

        foreach (var item in _cachedItems)
            Items.Add(item);

        OnCollectionChanged(new NotifyCollectionChangedEventArgs(
            NotifyCollectionChangedAction.Add, (IList<T>)_cachedItems));
        }
    }

正在投掷集合添加事件引用不属于集合的项目

is throwing A collection Add event refers to item that does not belong to collection

这似乎是 BCL 中的错误?

this appears to be a bug in BCL ?

我可以在调用 OnCollectionChanged 之前逐步查看新项目添加到 this.Items

I can step through and see prior to calling OnCollectionChanged that new items are added to this.Items

刚刚有了一个惊人的发现.这些方法都不适合我(flush、addrange),因为只有当这个集合绑定到我的 Listview 时才会触发错误!

just made a staggering discovery. None of these approaches worked for me (flush, addrange), because the error appears to be triggered ONLY if this collection is bound to my Listview!!

TestObservableCollection<Trade> testCollection = new TestObservableCollection<Trade>();
List<Trade> testTrades = new List<Trade>();

for (int i = 0; i < 200000; i++) 
    testTrades.Add(t);

testCollection.AddRange(testTrades); // no problems here.. 
_trades.AddRange(testTrades); // this one is bound to ListView .. BOOOM!!!

总而言之,ObservableCollection 确实支持添加增量列表,但 ListView 不支持.Andyp 想出了一个解决方法,让它与下面的 CollectionView 一起工作,但是由于调用了 .Refresh(),这与仅仅调用 OnCollectionChanged( .Reset) 没有什么不同.

In conclusion, ObservableCollection does support adding incremental lists, but a ListView doesn't. Andyp figured out a workaround to make it work with CollectionView below, but since .Refresh() is called, that is no different than just calling OnCollectionChanged( .Reset )..

推荐答案

您可以像这样为 ObservableCollection 实现 AddRange(),如下所示 这里:

you can implement AddRange() for the ObservableCollection like this as shown here:

public class RangeObservableCollection<T> : ObservableCollection<T>
{
    private bool _SuppressNotification;

    public override event NotifyCollectionChangedEventHandler CollectionChanged;

    protected virtual void OnCollectionChangedMultiItem(
        NotifyCollectionChangedEventArgs e)
    {
        NotifyCollectionChangedEventHandler handlers = this.CollectionChanged;
        if (handlers != null)
        {
            foreach (NotifyCollectionChangedEventHandler handler in 
                handlers.GetInvocationList())
            {
                if (handler.Target is CollectionView)
                    ((CollectionView)handler.Target).Refresh();
                else
                    handler(this, e);
            }
        }
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (!_SuppressNotification)
        {
            base.OnCollectionChanged(e);
            if (CollectionChanged != null)
                CollectionChanged.Invoke(this, e);
        }
    }

    public void AddRange(IEnumerable<T> list)
    {
        if (list == null)
            throw new ArgumentNullException("list");

        _SuppressNotification = true;

        foreach (T item in list)
        {
            Add(item);
        }
        _SuppressNotification = false;

        OnCollectionChangedMultiItem(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, list));
    }
}

更新:绑定到 ListBox 后,我也看到了 InvalidOperationException(与您看到的消息相同).根据这个文章 那是因为 CollectionView 不支持范围操作.幸运的是,这篇文章还提供了一个解决方案(虽然感觉有点hack-ish").

UPDATE: After binding to ListBox I was seeing an InvalidOperationException too (same message you were seeing). According to this article that's because CollectionView doesn't support range actions. Luckily the article also supplies a solution (although it feels a little "hack-ish").

更新 2:添加了一个修复程序,在 OnCollectionChanged() 的重写实现中引发重写的 CollectionChanged 事件.

UPDATE 2: Added a fix that raises the overridden CollectionChanged event in the overridden implementation of OnCollectionChanged().

这篇关于ObservableCollection :使用多个新项目调用 OnCollectionChanged的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆