Рассматривал класс System.Collections.ObjectModel ObservableCollection<T>. Это странно, потому что
Мне здесь нужно добавить пакет объектов в коллекцию, и слушатель также получит пакет как часть уведомления. Мне что-то не хватает с ObservableCollection? Есть ли другой класс, который соответствует моей спецификации?
Обновление: не хочу выкатывать свои собственные, насколько это возможно. Мне пришлось бы добавить / удалить / изменить и т. д. Много всего.
Связанный вопрос:
https://stackoverflow.com/questions/670577/observablecollection-doesnt-support-addrange-method-so-i-get-notified-for-each





Наследовать от 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, разместив мой образец кода .. немного короче.
Гишу, метод ToList () - это метод расширения LINQ, доступный в IEnumerable.
Понятно ... Вам нужно установить параметры проекта для использования .NET 3.5 и добавить ссылку на сборку LINQ и директиву using для ее получения.
Я пытаюсь сделать что-то почти идентичное ... даже изменил его, чтобы использовать ваш метод AddRange для тестирования, но все равно получаю "Элемент не существует в коллекции" tiny.cc/iim24
Опубликованный код не работает, если вы используете AddRange с более чем одним элементом. Событие CollectionChanged не может обрабатываться вручную с более чем одним элементом в измененном списке - вы получаете исключение Range actions are not supported
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
Если вы используете любую из вышеперечисленных реализаций, которые отправляют команду добавления диапазона и связывают наблюдаемую коллекцию со списком, вы получите эту неприятную ошибку.
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));
}
вы можете добавить добавление для каждого элемента, но ваш пользовательский интерфейс будет зависать
На самом деле, нет - пользовательский интерфейс WPF обрабатывается партиями, как пост-сообщение. Эта функция завершится до того, как пользовательский интерфейс будет проверен на предмет обновления.
То же исключение произошло здесь, кто-нибудь поможет нам решить эту проблему
Взгляните на Наблюдаемая коллекция с методами диапазона 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.
Другое решение, похожее на шаблон 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
}
}
Гишу, осторожно, если вы привяжете к списку, большинство реализаций здесь взорвутся.