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

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

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

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

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


Связанный вопрос:
https://stackoverflow.com/questions/670577/observablecollection-doesnt-support-addrange-method-so-i-get-notified-for-each

Гишу, осторожно, если вы привяжете к списку, большинство реализаций здесь взорвутся.

Sam Saffron 12.05.2009 08:55
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
35
1
20 000
10

Ответы 10

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

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

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

Кажется, что интерфейс 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);
    }
}

Фрагмент кода нуждается в некоторых исправлениях ... в IEnumerable нет ToList (), а AddRange должен принимать ICollection <T>, чтобы быть согласованным ... Поскольку мне пришлось пройти через эту временную неудачу к моим грандиозным планам удовлетворения моих еженедельных target, разместив мой образец кода .. немного короче.

Gishu 14.09.2008 22:56

Гишу, метод ToList () - это метод расширения LINQ, доступный в IEnumerable.

Brad Wilson 14.09.2008 23:06

Понятно ... Вам нужно установить параметры проекта для использования .NET 3.5 и добавить ссылку на сборку LINQ и директиву using для ее получения.

Gishu 28.09.2008 16:19

Я пытаюсь сделать что-то почти идентичное ... даже изменил его, чтобы использовать ваш метод AddRange для тестирования, но все равно получаю "Элемент не существует в коллекции" tiny.cc/iim24

Sonic Soul 21.07.2010 20:52

Опубликованный код не работает, если вы используете AddRange с более чем одним элементом. Событие CollectionChanged не может обрабатываться вручную с более чем одним элементом в измененном списке - вы получаете исключение Range actions are not supported

Rachel 16.09.2011 23:30

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

Что ж, идея такая же, как у 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);
        }

    }
}

Я пробовал этот подход раньше. К сожалению, это не сработает для привязок WPF, потому что уведомления для некоторых элементов не поддерживаются. См. эта ошибка в MS Connect

Thomas Levesque 30.09.2010 19:49

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

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

вы можете добавить добавление для каждого элемента, но ваш пользовательский интерфейс будет зависать

Sam Saffron 12.05.2009 08:56

На самом деле, нет - пользовательский интерфейс WPF обрабатывается партиями, как пост-сообщение. Эта функция завершится до того, как пользовательский интерфейс будет проверен на предмет обновления.

cunningdave 10.06.2011 20:23

То же исключение произошло здесь, кто-нибудь поможет нам решить эту проблему

Hemalatha M.R. 12.06.2020 14:57

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

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

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

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

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

BindingList<T>

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

Очень хороший момент по поводу BindingList<T>, но, к сожалению, он реализует IBindingList<T> вместо IObservable<T> ... Последний необходим для приложений WPF, использующих mvvm.

RonnBlack 02.06.2016 00:16

Другое решение, похожее на шаблон 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
    }
}

Другие вопросы по теме