Какая коллекция .Net для добавления нескольких объектов одновременно и получения уведомлений? - PullRequest
34 голосов
/ 11 сентября 2008

Рассматривал класс System.Collections.ObjectModel ObservableCollection<T>. Это странно, потому что

  • у него есть метод Add, который принимает один элемент. Нет AddRange или эквивалент.
  • аргументы события Notification имеют свойство NewItems, которое представляет собой IList (объектов .. не T)

Здесь мне нужно добавить пакет объектов в коллекцию, и слушатель также получит пакет как часть уведомления. Я что-то упустил с ObservableCollection? Есть другой класс, который соответствует моим спецификациям?

Обновление: не хочу, чтобы мои собственные свернули, насколько это возможно. Я должен был бы встроить добавить / удалить / изменить и т.д .. много всего.


Похожие Q:
https://stackoverflow.com/questions/670577/observablecollection-doesnt-support-addrange-method-so-i-get-notified-for-each

Ответы [ 11 ]

19 голосов
/ 11 сентября 2008

Похоже, что интерфейс 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);
    }
}
6 голосов
/ 14 сентября 2008

Ну, идея та же, что и у fryguybob - странно, что ObservableCollection немного наполовину закончен. Аргументы событий для этой вещи даже не используют 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);
        }

    }
}
4 голосов
/ 12 мая 2009

Если вы используете любую из вышеперечисленных реализаций, которые отправляют команду добавления диапазона и связывают наблюдаемую коллекцию со списком, вы получите эту неприятную ошибку.

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:

    public void AddRange(IEnumerable<T> collection)
    {
        foreach (var i in collection) Items.Add(i);
        OnPropertyChanged("Count");
        OnPropertyChanged("Item[]");
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
4 голосов
/ 12 сентября 2008

Не только System.Collections.ObjectModel.Collection<T> хорошая ставка, но в справочных документах есть пример того, как переопределить его различные защищенные методы для получения уведомления. (Прокрутите вниз до примера 2.)

3 голосов
/ 30 сентября 2010

Я видел подобные вопросы много раз, и мне интересно, почему даже Microsoft продвигает ObservableCollection везде, где еще есть лучшая коллекция, которая уже доступна вот и все.

BindingList<T>

Что позволяет отключать уведомления и выполнять массовые операции, а затем включать уведомления.

2 голосов
/ 12 января 2012

Другое решение, похожее на шаблон 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
    }
}
2 голосов
/ 11 сентября 2008

Если вы хотите наследовать от какой-либо коллекции, вам, вероятно, лучше наследовать от System.Collections.ObjectModel.Collection, поскольку она предоставляет виртуальные методы для переопределения. Если вы пойдете по этому пути, вам придется скрывать методы от List.

Мне не известны какие-либо встроенные коллекции, которые предоставляют эту функциональность, хотя я бы приветствовал исправление:)

1 голос
/ 11 сентября 2008

Наследовать от List и переопределять методы Add () и AddRange (), чтобы вызвать событие?

0 голосов
/ 24 ноября 2009

Для быстрого добавления вы можете использовать:

((List<Person>)this.Items).AddRange(NewItems);
0 голосов
/ 14 июля 2009

Посмотрите на Наблюдаемая коллекция с помощью методов диапазона AddRange, RemoveRange и Replace в C # и VB.

В VB: реализация INotifyCollectionChanging.

...