哪个.Net集合可以一次添加多个对象并收到通知?

时间:2008-09-11 16:15:53

标签: c# .net-3.5 collections

正在考虑System.Collections.ObjectModel ObservableCollection<T>课程。这个很奇怪,因为

  • 它有一个Add方法,只接受一个项。没有AddRange或等价物。
  • Notification事件参数有一个NewItems属性,它是 IList (对象..而不是T)

我的需要是将一批对象添加到集合中,并且侦听器还将批处理作为通知的一部分。我错过了ObservableCollection的东西吗?还有其他课程符合我的规范吗?

更新:尽量不要自己动手。我必须构建添加/删除/更改等等。很多东西。


相关问题:
https://stackoverflow.com/questions/670577/observablecollection-doesnt-support-addrange-method-so-i-get-notified-for-each

11 个答案:

答案 0 :(得分:19)

似乎INotifyCollectionChanged界面允许在添加多个项目时进行更新,因此我不确定为什么ObservableCollection<T>没有AddRange。您可以为AddRange创建一个扩展方法,但这会导致添加的每个项目都有一个事件。如果这是不可接受的,您应该能够继承ObservableCollection<T>,如下所示:

public class MyObservableCollection<T> : ObservableCollection<T>
{
    // matching constructors ...

    bool isInAddRange = false;

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        // intercept this when it gets called inside the AddRange method.
        if (!isInAddRange) 
            base.OnCollectionChanged(e);
    }


    public void AddRange(IEnumerable<T> items)
    {
         isInAddRange = true;
         foreach (T item in items)
            Add(item);
         isInAddRange = false;

         var e = new NotifyCollectionChangedEventArgs(
             NotifyCollectionChangedAction.Add,
             items.ToList());
         base.OnCollectionChanged(e);
    }
}

答案 1 :(得分:6)

这个想法与fryguybob的想法相同 - 有点奇怪,ObservableCollection有点半完成。这件事的事件args甚至没有使用Generics ..让我使用IList(就是这样......昨天:) 经过测试的代码片段如下......

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;

namespace MyNamespace
{
    public class ObservableCollectionWithBatchUpdates<T> : ObservableCollection<T>
    {
        public void AddRange(ICollection<T> obNewItems)
        {
            IList<T> obAddedItems = new List<T>();
            foreach (T obItem in obNewItems)
            {
                Items.Add(obItem);
                obAddedItems.Add(obItem);
            }
            NotifyCollectionChangedEventArgs obEvtArgs = new NotifyCollectionChangedEventArgs(
               NotifyCollectionChangedAction.Add, 
               obAddedItems as System.Collections.IList);
            base.OnCollectionChanged(obEvtArgs);
        }

    }
}

答案 2 :(得分:4)

System.Collections.ObjectModel.Collection<T>不仅是一个不错的选择,而且在帮助文档中还有an example如何覆盖其各种受保护的方法以获取通知。 (向下滚动到示例2。)

答案 3 :(得分:4)

如果您使用上述任何发送add range命令并将observablecolletion绑定到listview的实现,您将收到这个令人讨厌的错误。

NotSupportedException
   at System.Windows.Data.ListCollectionView.ValidateCollectionChangedEventArgs(NotifyCollectionChangedEventArgs e)
   at System.Windows.Data.ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args)
   at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e)
   at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)

我使用的实现使用了围绕WPF框架更均匀实现的Reset事件:

    public void AddRange(IEnumerable<T> collection)
    {
        foreach (var i in collection) Items.Add(i);
        OnPropertyChanged("Count");
        OnPropertyChanged("Item[]");
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

答案 4 :(得分:3)

我已经多次看过这样的问题了,我想知道为什么即使微软也在其他任何地方推广ObservableCollection已经有了更好的收藏......

  

BindingList<T>

允许您关闭通知并执行批量操作,然后启用通知。

答案 5 :(得分:2)

如果您想要从某种类型的集合继承,那么最好继承System.Collections.ObjectModel.Collection,因为它提供了覆盖的虚方法。如果你走这条路,你将不得不从List中隐藏方法。

我不知道任何提供此功能的内置集合,但我欢迎更正:)

答案 6 :(得分:2)

另一种类似于CollectionView模式的解决方案:

public class DeferableObservableCollection<T> : ObservableCollection<T>
{
    private int deferLevel;

    private class DeferHelper<T> : IDisposable
    {
        private DeferableObservableCollection<T> owningCollection;
        public DeferHelper(DeferableObservableCollection<T> owningCollection)
        {
            this.owningCollection = owningCollection;
        }

        public void Dispose()
        {
            owningCollection.EndDefer();
        }
    }

    private void EndDefer()
    {
        if (--deferLevel <= 0)
        {
            deferLevel = 0;
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }
    }

    public IDisposable DeferNotifications()
    {
        deferLevel++;
        return new DeferHelper<T>(this);
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (deferLevel == 0) // Not in a defer just send events as normally
        {
            base.OnCollectionChanged(e);
        } // Else notify on EndDefer
    }
}

答案 7 :(得分:1)

继承自List&lt; T&gt;并覆盖Add()和AddRange()方法来引发事件?

答案 8 :(得分:0)

在C#和VB中查看Observable collection with AddRange, RemoveRange and Replace range methods

在VB中:INotifyCollectionChanging实现。

答案 9 :(得分:0)

如需快速添加,您可以使用:

((List<Person>)this.Items).AddRange(NewItems);

答案 10 :(得分:-1)

扩展方法人员救援!

    /// <summary>
    /// Adds all given items to the collection
    /// </summary>
    /// <param name="collection">The collection.</param>
    /// <param name="toAdd">Objects to add.</param>
    public static void AddAll<T>(this IList<T> collection, params T[] toAdd)
    {
        foreach (var o in toAdd)
            collection.Add(o);
    }