2008-09-11 7 views
31

Рассматривал класс System.Collections.ObjectModel ObservableCollection<T>. Это один странно, потому чтоКакая коллекция .Net для одновременного добавления нескольких объектов и получения уведомления?

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

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

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


Связанные Q:
https://stackoverflow.com/questions/670577/observablecollection-doesnt-support-addrange-method-so-i-get-notified-for-each

+4

Gishu, осторожна, если вы свяжете на ListView большинство реализаций здесь взорвется. – 2009-05-12 04:55:38

ответ

1

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

2

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

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

18

Похоже, что интерфейс 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); 
    } 
} 
+0

Фрагмент кода нуждается в некоторых исправлениях .. в IEnumerable и AddRange не должно быть ToList(), поэтому ICollection должен быть последовательным ... Так как мне пришлось пройти через эту временную неудачу в моих грандиозных планах по достижению моей недельной цели , отправляя мой образец кода .. немного короче. – Gishu 2008-09-14 18:56:05

+2

Gishu, метод ToList() - это метод расширения LINQ, доступный для IEnumerable. – 2008-09-14 19:06:34

+0

Получил это ... Вам нужно установить параметры проекта для использования .NET 3.5 и добавить ссылку на сборку LINQ и использовать директиву для ее получения. – Gishu 2008-09-28 12:19:15

-1

метод расширения Человек на помощь!

/// <summary> 
    /// Adds all given items to the collection 
    /// </summary> 
    /// <param name="collection">The collection.</param> 
    /// <param name="toAdd">Objects to add.</param> 
    public static void AddAll<T>(this IList<T> collection, params T[] toAdd) 
    { 
     foreach (var o in toAdd) 
      collection.Add(o); 
    } 
+0

Это очень медленно ... например, попробуйте добавить 3000 предметов к наблюдаемым (попрощайтесь с ui в течение 3 минут) – 2009-05-12 04:40:30

4

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

6

Ну, идея такая же, как у 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

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

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

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

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

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

BindingList<T>

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

1

Другим решением, которое аналогично образцу 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 
    } 
}