关于c#:哪个.Net集合可一次添加多个对象并得到通知?

关于c#:哪个.Net集合可一次添加多个对象并得到通知?

Which .Net collection for adding multiple objects at once and getting notified?

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

  • 它有一个只需要一项的添加方法。没有AddRange或等效项。
  • Notification事件参数具有NewItems属性,该属性是一个IList(对象的..不是T)

我这里需要将一批对象添加到集合中,并且侦听器还将批处理作为通知的一部分。我是否缺少ObservableCollection的东西?还有另一个符合我要求的课程吗?

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

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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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);
    }
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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);
        }

    }
}

如果您使用上述任何一种发送添加范围命令并将observablecolletion绑定到listview的实现,都会收到此讨厌的错误。

1
2
3
4
5
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)

我使用的实现使用Reset事件,该事件在WPF框架周围更加均匀地实现:

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

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


我已经多次看到这种问题,我想知道为什么连微软都在其他地方已经推广了更好的collection的地方推广ObservableCollection。

BindingList< T >

这允许您关闭通知并执行批量操作,然后打开通知。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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
    }
}

如果您想从某种集合中继承,最好从System.Collections.ObjectModel.Collection继承,因为它提供了用于重写的虚拟方法。如果走那条路线,您将不得不遮蔽List之外的方法。

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


从List < T >继承并重写Add()和AddRange()方法引发事件吗?


要快速添加,可以使用:

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

使用C#和VB中的AddRange,RemoveRange和Replace range方法查看Observable集合。

在VB中:INotifyCollectionChanging实现。


推荐阅读