36

正在考虑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

4

10 回答 10

20

似乎该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);
    }
}
于 2008-09-11T16:43:52.413 回答
6

好吧,这个想法与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);
        }

    }
}
于 2008-09-14T19:03:47.557 回答
4

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

于 2008-09-12T03:13:10.293 回答
4

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

不支持异常
   在 System.Windows.Data.ListCollectionView.ValidateCollectionChangedEventArgs(NotifyCollectionChangedEventArgs e)
   在 System.Windows.Data.ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs 参数)
   在 System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(对象发送者,NotifyCollectionChangedEventArgs e)
   在 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));
    }
于 2009-05-12T04:54:58.787 回答
3

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

BindingList<T>

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

于 2010-09-30T09:58:37.800 回答
2

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

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

于 2008-09-11T16:21:44.680 回答
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
    }
}
于 2012-01-12T15:30:13.313 回答
1

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

于 2008-09-11T16:19:10.490 回答
0

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

在 VB 中:INotifyCollectionChanging 实现。

于 2009-07-14T03:25:12.300 回答
0

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

((List<Person>)this.Items).AddRange(NewItems);
于 2009-11-24T14:30:21.900 回答