C# 哪个 .Net 集合用于一次添加多个对象并获得通知?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/57020/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 10:12:50  来源:igfitidea点击:

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

提问by Gishu

Was considering the System.Collections.ObjectModel ObservableCollection<T>class. This one is strange because

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

  • it has an Add Method which takes oneitem only. No AddRange or equivalent.
  • the Notification event arguments has a NewItems property, which is a IList(of objects.. not T)
  • 它有一个 Add 方法,它只需要一个项目。没有 AddRange 或等效项。
  • 通知事件参数有一个 NewItems 属性,它是一个IList(对象......不是 T)

My need here is to add a batch of objects to a collection and the listener also gets the batch as part of the notification. Am I missing something with ObservableCollection ? Is there another class that meets my spec?

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

Update: Don't want to roll my own as far as feasible. I'd have to build in add/remove/change etc.. a whole lot of stuff.

更新:不想尽可能地推出我自己的。我必须在添加/删除/更改等中构建很多东西。



Related Q:
https://stackoverflow.com/questions/670577/observablecollection-doesnt-support-addrange-method-so-i-get-notified-for-each

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

回答by Joel Coehoorn

Inherit from List<T> and override the Add() and AddRange() methods to raise an event?

从 List<T> 继承并覆盖 Add() 和 AddRange() 方法以引发事件?

回答by David Mohundro

If you're wanting to inherit from a collection of some sort, you're probably better off inheriting from System.Collections.ObjectModel.Collection because it provides virtual methods for override. You'll have to shadow methods off of List if you go that route.

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

I'm not aware of any built-in collections that provide this functionality, though I'd welcome being corrected :)

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

回答by fryguybob

It seems that the INotifyCollectionChangedinterface allows for updating when multiple items were added, so I'm not sure why ObservableCollection<T>doesn't have an AddRange. You could make an extension method for AddRange, but that would cause an event for every item that is added. If that isn't acceptable you should be able to inherit from ObservableCollection<T>as follows:

似乎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);
    }
}

回答by Ryan Lundy

Not only is System.Collections.ObjectModel.Collection<T>a good bet, but in the help docs there's an exampleof how to override its various protected methods in order to get notification. (Scroll down to Example 2.)

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

回答by Gishu

Well the idea is same as that of fryguybob - kinda weird that ObservableCollection is kinda half-done. The event args for this thing do not even use Generics.. making me use an IList (that's so.. yesterday :) Tested Snippet follows...

嗯,这个想法与 fryguybob 的想法相同——有点奇怪的是 ObservableCollection 有点完成了。这件事的事件参数甚至不使用泛型......让我使用 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);
        }

    }
}

回答by Sam Saffron

If you use any of the above implementations that send an add range command and bind the observablecolletion to a listview you will get this nasty error.

如果您使用上述任何一种发送添加范围命令并将 observablecolletion 绑定到列表视图的实现,您将收到这个令人讨厌的错误。

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)

The implementation I have gone with uses the Reset event that is more evenly implemented around the WPF framework:

我使用的实现使用了更均匀地围绕 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));
    }

回答by Shimmy Weitzhandler

Take a look at Observable collection with AddRange, RemoveRange and Replace range methodsin both C# and VB.

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

In VB: INotifyCollectionChanging implementation.

在 VB 中:INotifyCollectionChanging 实现。

回答by Boris

For fast adding you could use:

为了快速添加,您可以使用:

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

回答by Akash Kava

I have seen this kind of question many times, and I wonder why even Microsoft is promoting ObservableCollection everywhere where else there is a better collection already available thats..

我已经多次看到这种问题,我想知道为什么即使是微软也在到处推广 ObservableCollection,而其他地方已经有更好的集合可用了。

BindingList<T>

BindingList<T>

Which allows you to turn off notifications and do bulk operations and then turn on the notifications.

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

回答by Mo0gles

Another solution that is similar to the CollectionView pattern:

另一种类似于 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
    }
}