При очистке ObservableCollection в e.OldItems нет элементов

У меня есть кое-что, что действительно застало 9X_observablecollection меня врасплох.

У меня есть ObservableCollection 9X_wpf T, заполненная элементами. У меня также 9X_wpf есть обработчик событий, прикрепленный к 9X_wpf событию CollectionChanged.

Когда вы очищаете коллекцию, это 9X_observablecollection вызывает событие CollectionChanged с параметром 9X_observablecollection e.Action, которому присвоено значение NotifyCollectionChangedAction.Reset. Хорошо, это 9X_observablecollection нормально. Но странно то, что ни в e.OldItems, ни 9X_observablecollection в e.NewItems ничего нет. Я ожидаю, что e.OldItems будет заполнен всеми элементами, которые были удалены из коллекции.

Кто-нибудь еще 9X_observablecollection это видел? И если да, то как они это решили?

Немного 9X_observablecollection предыстории: я использую событие CollectionChanged 9X_observablecollection для присоединения к другому событию и отсоединения 9X_wpf от него, и поэтому, если я не получу никаких 9X_observablecollection элементов в e.OldItems ... я не смогу отсоединиться 9X_wpf от этого события.


УТОЧНЕНИЕ: Я знаю, что в документации 9X_observablecollection прямо не говорится, что он должен вести себя 9X_observablecollection подобным образом. Но для каждого другого 9X_observablecollection действия он уведомляет меня о том, что он 9X_wpf сделал. Итак, я предполагаю, что он скажет 9X_wpf мне ... также и в случае Clear / Reset.


Ниже 9X_wpf приведен пример кода, если вы хотите воспроизвести 9X_observablecollection его самостоятельно. Прежде всего, xaml:

      

Далее 9X_wpf код:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Collections.ObjectModel; namespace ObservableCollection { /// 
/// Interaction logic for Window1.xaml ///
 public partial class Window1 : Window { public Window1() { InitializeComponent(); _integerObservableCollection.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_integerObservableCollection_CollectionChanged); } private void _integerObservableCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { switch (e.Action) { case System.Collections.Specialized.NotifyCollectionChangedAction.Add: break; case System.Collections.Specialized.NotifyCollectionChangedAction.Move: break; case System.Collections.Specialized.NotifyCollectionChangedAction.Remove: break; case System.Collections.Specialized.NotifyCollectionChangedAction.Replace: break; case System.Collections.Specialized.NotifyCollectionChangedAction.Reset: break; default: break; } } private void addButton_Click(object sender, RoutedEventArgs e) { _integerObservableCollection.Add(25); } private void moveButton_Click(object sender, RoutedEventArgs e) { _integerObservableCollection.Move(0, 19); } private void removeButton_Click(object sender, RoutedEventArgs e) { _integerObservableCollection.RemoveAt(0); } private void replaceButton_Click(object sender, RoutedEventArgs e) { _integerObservableCollection[0] = 50; } private void resetButton_Click(object sender, RoutedEventArgs e) { _integerObservableCollection.Clear(); } private ObservableCollection _integerObservableCollection = new ObservableCollection { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; } } 

98
0
15
Общее количество ответов: 15

Ответ #1

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

Он не претендует на включение старых элементов, потому 9X_observablecollection что Reset не означает, что список был очищен

Это 9X_wpf означает, что произошла какая-то драматическая 9X_observablecollection вещь, и стоимость работы над добавлением 9X_observablecollection / удалением, скорее всего, превысит стоимость 9X_wpf простого повторного сканирования списка 9X_observablecollection с нуля ... так что вам следует поступить 9X_wpf так.

MSDN предлагает пример повторной сортировки 9X_wpf всей коллекции как кандидата на сброс.

Повторюсь. Сброс не означает очистку, это 9X_wpf означает, что ваши предположения относительно списка теперь неверны. Относитесь к нему как к совершенно новому списку. Clear является одним из 9X_wpf примеров этого, но могут быть и другие.

Некоторые 9X_wpf примеры:
У меня был такой список, в котором 9X_wpf было много элементов, и он был привязан 9X_wpf к WPF ListView для отображения на экране.
Если 9X_wpf вы очистите список и вызовете событие .Reset, производительность 9X_observablecollection будет практически мгновенной, но если вы 9X_wpf вместо этого вызовете много отдельных событий 9X_observablecollection .Remove, производительность будет ужасной, поскольку 9X_observablecollection WPF удаляет элементы один за другим. Я также 9X_wpf использовал .Reset в своем собственном коде, чтобы 9X_wpf указать, что список был повторно отсортирован, вместо 9X_observablecollection того, чтобы выполнять тысячи отдельных операций 9X_observablecollection Move. Как и в случае с Clear, при возникновении 9X_observablecollection множества отдельных событий производительность 9X_observablecollection сильно падает.

47
5

  • Что ж, если «Reset» указывает на дорогостоящую операцию, весьма вероятно, что те же рассуж ...

Ответ #2

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

У нас была та же проблема. Действие Reset 9X_wpf в CollectionChanged не включает OldItems. У 9X_wpf нас был обходной путь: вместо этого мы использовали 9X_observablecollection следующий метод расширения:

public static void RemoveAll(this IList list) { while (list.Count > 0) { list.RemoveAt(list.Count - 1); } } 

В итоге мы перестали 9X_wpf поддерживать функцию Clear() и выбросили 9X_wpf NotSupportedException в событии CollectionChanged 9X_observablecollection для действий Reset. RemoveAll вызовет действие 9X_wpf Remove в событии CollectionChanged с правильными 9X_wpf OldItems.

24
3

  • Проблема, Орион, с вашим предложением ... это случай использования, который вызвал этот вопрос. Что происходит, когда в списке есть элементы, от которых я хочу отделить событие? Я не могу просто выгрузить данные из списка ... это ...

Ответ #3

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

Хорошо, я знаю, что это очень старый вопрос, но 9X_observablecollection я нашел хорошее решение проблемы и подумал, что 9X_observablecollection поделюсь. Это решение черпает вдохновение 9X_wpf из многих замечательных ответов здесь, но 9X_observablecollection имеет следующие преимущества:

  • Нет необходимости создавать новый класс и переопределять методы из ObservableCollection
  • Не влияет на работу NotifyCollectionChanged (поэтому не нужно вмешиваться в Reset).
  • Не использует отражение.

Вот код:

 public static void Clear(this ObservableCollection collection, Action> unhookAction) { unhookAction.Invoke(collection); collection.Clear(); } 

Этот 9X_wpf метод расширения просто принимает Action, который 9X_wpf будет вызываться перед очисткой коллекции.

15
0

Ответ #4

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

Другой вариант - заменить событие Reset 9X_observablecollection одним событием Remove, которое содержит 9X_wpf все очищенные элементы в своем свойстве 9X_observablecollection OldItems следующим образом:

public class ObservableCollectionNoReset : ObservableCollection { protected override void ClearItems() { List removed = new List(this); base.ClearItems(); base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed)); } protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (e.Action != NotifyCollectionChangedAction.Reset) base.OnCollectionChanged(e); } // Constructors omitted ... } 

Преимущества:

  1. Нет 9X_wpf необходимости подписываться на дополнительное 9X_observablecollection событие (в соответствии с принятым ответом)

  2. Не 9X_observablecollection генерирует событие для каждого удаленного 9X_observablecollection объекта (некоторые другие предлагаемые решения 9X_observablecollection приводят к множеству удаленных событий).

  3. Подписчику 9X_observablecollection нужно только проверять NewItems и OldItems 9X_wpf на любом событии, чтобы добавлять / удалять 9X_observablecollection обработчики событий по мере необходимости.

Недостатки:

  1. Нет 9X_observablecollection события сброса

  2. Небольшие (?) накладные расходы 9X_observablecollection на создание копии списка.

  3. ???

ИЗМЕНИТЬ 23 9X_observablecollection февраля 2012 г.

К сожалению, при привязке 9X_observablecollection к элементам управления на основе списка 9X_wpf WPF очистка коллекции ObservableCollectionNoReset 9X_observablecollection с несколькими элементами приведет к исключению 9X_observablecollection «Действия диапазона не поддерживаются». Для 9X_wpf использования с элементами управления с 9X_wpf этим ограничением я изменил класс ObservableCollectionNoReset 9X_observablecollection на:

public class ObservableCollectionNoReset : ObservableCollection { // Some CollectionChanged listeners don't support range actions. public Boolean RangeActionsSupported { get; set; } protected override void ClearItems() { if (RangeActionsSupported) { List removed = new List(this); base.ClearItems(); base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed)); } else { while (Count > 0 ) base.RemoveAt(Count - 1); } } protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (e.Action != NotifyCollectionChangedAction.Reset) base.OnCollectionChanged(e); } public ObservableCollectionNoReset(Boolean rangeActionsSupported = false) { RangeActionsSupported = rangeActionsSupported; } // Additional constructors omitted. } 

Это не так эффективно, когда RangeActionsSupported 9X_observablecollection имеет значение false (по умолчанию), потому 9X_observablecollection что для каждого объекта в коллекции создается 9X_observablecollection одно уведомление об удалении

13
2

  • @Alain Коллекция ObservableCollection не накладывает этого ограничения. Я подозреваю, что это элемент управления WPF, к которому вы привязали коллекцию. У меня была такая же проблема, и я так и не успел опубликов ...

Ответ #5

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

Я нашел решение, которое позволяет пользователю 9X_wpf как извлечь выгоду из эффективности добавления 9X_observablecollection или удаления множества элементов за раз 9X_observablecollection при запуске только одного события, так и 9X_observablecollection удовлетворить потребности UIElements в получении 9X_wpf аргументов события Action.Reset, в то время 9X_observablecollection как все другим пользователям нужен список 9X_wpf добавленных и удаленных элементов.

Это решение 9X_wpf включает переопределение события CollectionChanged. Когда 9X_wpf мы запускаем это событие, мы действительно 9X_observablecollection можем посмотреть на цель каждого зарегистрированного 9X_wpf обработчика и определить их тип. Поскольку 9X_observablecollection только классы ICollectionView требуют аргументов 9X_wpf NotifyCollectionChangedAction.Reset, когда изменяется более одного элемента, мы 9X_wpf можем выделить их и предоставить всем остальным 9X_wpf правильные аргументы событий, которые содержат 9X_wpf полный список элементов, удаленных или добавленных. Ниже 9X_observablecollection представлена ​​реализация.

public class BaseObservableCollection : ObservableCollection { //Flag used to prevent OnCollectionChanged from firing during a bulk operation like Add(IEnumerable) and Clear() private bool _SuppressCollectionChanged = false; /// Overridden so that we may manually call registered handlers and differentiate between those that do and don't require Action.Reset args. public override event NotifyCollectionChangedEventHandler CollectionChanged; public BaseObservableCollection() : base(){} public BaseObservableCollection(IEnumerable data) : base(data){} #region Event Handlers protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if( !_SuppressCollectionChanged ) { base.OnCollectionChanged(e); if( CollectionChanged != null ) CollectionChanged.Invoke(this, e); } } //CollectionViews raise an error when they are passed a NotifyCollectionChangedEventArgs that indicates more than //one element has been added or removed. They prefer to receive a "Action=Reset" notification, but this is not suitable //for applications in code, so we actually check the type we're notifying on and pass a customized event args. protected virtual void OnCollectionChangedMultiItem(NotifyCollectionChangedEventArgs e) { NotifyCollectionChangedEventHandler handlers = this.CollectionChanged; if( handlers != null ) foreach( NotifyCollectionChangedEventHandler handler in handlers.GetInvocationList() ) handler(this, !(handler.Target is ICollectionView) ? e : new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } #endregion #region Extended Collection Methods protected override void ClearItems() { if( this.Count == 0 ) return; List removed = new List(this); _SuppressCollectionChanged = true; base.ClearItems(); _SuppressCollectionChanged = false; OnCollectionChangedMultiItem(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed)); } public void Add(IEnumerable toAdd) { if( this == toAdd ) throw new Exception("Invalid operation. This would result in iterating over a collection as it is being modified."); _SuppressCollectionChanged = true; foreach( T item in toAdd ) Add(item); _SuppressCollectionChanged = false; OnCollectionChangedMultiItem(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List(toAdd))); } public void Remove(IEnumerable toRemove) { if( this == toRemove ) throw new Exception("Invalid operation. This would result in iterating over a collection as it is being modified."); _SuppressCollectionChanged = true; foreach( T item in toRemove ) Remove(item); _SuppressCollectionChanged = false; OnCollectionChangedMultiItem(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new List(toRemove))); } #endregion } 

9
0

Ответ #6

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

Хорошо, хотя я все еще хочу, чтобы ObservableCollection 9X_observablecollection вела себя так, как я хотел ... приведенный 9X_observablecollection ниже код - это то, что я в итоге сделал. По 9X_observablecollection сути, я создал новую коллекцию T под названием 9X_wpf TrulyObservableCollection и переопределил 9X_observablecollection метод ClearItems, который затем использовал 9X_wpf для создания события очистки.

В коде, который 9X_wpf использует эту TrulyObservableCollection, я 9X_observablecollection использую это событие Clearing для циклического 9X_observablecollection перебора элементов , которые все еще находятся в коллекции на тот момент, чтобы выполнить отсоединение 9X_wpf для события, которое я хотел отсоединить. с.

Надеюсь, этот 9X_wpf подход поможет и кому-то другому.

public class TrulyObservableCollection : ObservableCollection { public event EventHandler Clearing; protected virtual void OnClearing(EventArgs e) { if (Clearing != null) Clearing(this, e); } protected override void ClearItems() { OnClearing(EventArgs.Empty); base.ClearItems(); } } 

8
5

  • Лол отличное имя. Согласен, это ...

Ответ #7

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

Я подошел к этому несколько иначе, так как 9X_wpf хотел зарегистрироваться на одно событие 9X_wpf и обрабатывать все добавления и удаления 9X_observablecollection в обработчике событий. Я начал с переопределения 9X_wpf события изменения коллекции и перенаправления 9X_observablecollection действий сброса на действия по удалению 9X_wpf со списком элементов. Все пошло не так, поскольку 9X_observablecollection я использовал наблюдаемую коллекцию в качестве 9X_observablecollection источника элементов для представления коллекции 9X_observablecollection и получил сообщение «Действия диапазона 9X_observablecollection не поддерживаются».

Наконец-то я создал новое 9X_wpf событие под названием CollectionChangedRange, которое 9X_observablecollection действует так, как я ожидал от встроенной 9X_wpf версии.

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

/// 
/// An observable collection with support for addrange and clear ///
 /// [Serializable] [TypeConverter(typeof(ExpandableObjectConverter))] public class ObservableCollectionRange : ObservableCollection { private bool _addingRange; [field: NonSerialized] public event NotifyCollectionChangedEventHandler CollectionChangedRange; protected virtual void OnCollectionChangedRange(NotifyCollectionChangedEventArgs e) { if ((CollectionChangedRange == null) || _addingRange) return; using (BlockReentrancy()) { CollectionChangedRange(this, e); } } public void AddRange(IEnumerable collection) { CheckReentrancy(); var newItems = new List(); if ((collection == null) || (Items == null)) return; using (var enumerator = collection.GetEnumerator()) { while (enumerator.MoveNext()) { _addingRange = true; Add(enumerator.Current); _addingRange = false; newItems.Add(enumerator.Current); } } OnCollectionChangedRange(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newItems)); } protected override void ClearItems() { CheckReentrancy(); var oldItems = new List(this); base.ClearItems(); OnCollectionChangedRange(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, oldItems)); } protected override void InsertItem(int index, T item) { CheckReentrancy(); base.InsertItem(index, item); OnCollectionChangedRange(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index)); } protected override void MoveItem(int oldIndex, int newIndex) { CheckReentrancy(); var item = base[oldIndex]; base.MoveItem(oldIndex, newIndex); OnCollectionChangedRange(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, item, newIndex, oldIndex)); } protected override void RemoveItem(int index) { CheckReentrancy(); var item = base[index]; base.RemoveItem(index); OnCollectionChangedRange(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); } protected override void SetItem(int index, T item) { CheckReentrancy(); var oldItem = base[index]; base.SetItem(index, item); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, oldItem, item, index)); } } /// 
/// A read only observable collection with support for addrange and clear ///
 /// [Serializable] [TypeConverter(typeof(ExpandableObjectConverter))] public class ReadOnlyObservableCollectionRange : ReadOnlyObservableCollection { [field: NonSerialized] public event NotifyCollectionChangedEventHandler CollectionChangedRange; public ReadOnlyObservableCollectionRange(ObservableCollectionRange list) : base(list) { list.CollectionChangedRange += HandleCollectionChangedRange; } private void HandleCollectionChangedRange(object sender, NotifyCollectionChangedEventArgs e) { OnCollectionChangedRange(e); } protected virtual void OnCollectionChangedRange(NotifyCollectionChangedEventArgs args) { if (CollectionChangedRange != null) { CollectionChangedRange(this, args); } } } 

4
0

Ответ #8

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

Вот как работает ObservableCollection, вы 9X_wpf можете обойти это, сохранив свой собственный 9X_observablecollection список за пределами ObservableCollection 9X_observablecollection (добавление в список, когда действие - Добавить, удалить, когда 9X_observablecollection действие - Удалить и т. д.), тогда вы можете 9X_observablecollection получить все удаленные элементы ( или добавленные 9X_wpf элементы) при действии Reset путем сравнения 9X_observablecollection вашего списка с ObservableCollection.

Другой 9X_observablecollection вариант - создать свой собственный класс, реализующий 9X_wpf IList и INotifyCollectionChanged, затем 9X_observablecollection вы можете присоединять и отсоединять события 9X_observablecollection из этого класса (или устанавливать OldItems 9X_wpf на Clear, если хотите) - это действительно 9X_wpf несложно, но это много печатать.

3
0

Ответ #9

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

Для сценария присоединения и отсоединения 9X_wpf обработчиков событий к элементам ObservableCollection 9X_wpf также существует «клиентское» решение. В 9X_observablecollection коде обработки событий вы можете проверить, находится 9X_wpf ли отправитель в ObservableCollection, используя 9X_wpf метод Contains. Pro: вы можете работать 9X_wpf с любой существующей ObservableCollection. Минусы: метод 9X_observablecollection Contains работает с O (n), где n - количество 9X_wpf элементов в ObservableCollection. Итак, это 9X_wpf решение для небольших ObservableCollections.

Еще 9X_observablecollection одно «клиентское» решение - использовать 9X_observablecollection обработчик событий посередине. Просто зарегистрируйте 9X_observablecollection все события в обработчике событий посередине. Этот 9X_wpf обработчик событий, в свою очередь, уведомляет 9X_observablecollection реальный обработчик событий посредством 9X_observablecollection обратного вызова или события. Если происходит 9X_observablecollection действие Reset, удалите обратный вызов или 9X_observablecollection событие, создайте новый обработчик событий 9X_observablecollection посередине и забудьте о старом. Этот подход 9X_wpf также работает для больших ObservableCollections. Я 9X_observablecollection использовал это для события PropertyChanged 9X_observablecollection (см. Код ниже).

 /// 
/// Helper class that allows to "detach" all current Eventhandlers by setting /// DelegateHandler to null. ///
 public class PropertyChangedDelegator { /// 
/// Callback to the real event handling code. ///
 public PropertyChangedEventHandler DelegateHandler; /// 
/// Eventhandler that is registered by the elements. ///
 /// the element that has been changed. /// the event arguments public void PropertyChangedHandler(Object sender, PropertyChangedEventArgs e) { if (DelegateHandler != null) { DelegateHandler(sender, e); } else { INotifyPropertyChanged s = sender as INotifyPropertyChanged; if (s != null) s.PropertyChanged -= PropertyChangedHandler; } } } 

3
0

Ответ #10

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

Глядя на NotifyCollectionChangedEventArgs, кажется, что OldItems содержит 9X_wpf только элементы, измененные в результате 9X_wpf действия «Заменить», «Удалить» или «Переместить». Это 9X_observablecollection не означает, что он будет содержать что-либо 9X_wpf на Clear. Я подозреваю, что Clear запускает 9X_observablecollection событие, но не регистрирует удаленные элементы 9X_observablecollection и вообще не вызывает код удаления.

2
1

  • Я тоже это видел, но мне это не нравится. Мне это кажется зияющей дырой ...

Ответ #11

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

Ну, я решил сам испачкаться.

Microsoft приложила 9X_wpf ОЧЕНЬ много работы, чтобы всегда убедиться, что 9X_wpf NotifyCollectionChangedEventArgs не содержит 9X_observablecollection данных при вызове сброса. Я предполагаю, что 9X_wpf это было решение производительности / памяти. Если 9X_observablecollection вы сбрасываете коллекцию из 100 000 элементов, я 9X_wpf предполагаю, что они не хотели дублировать 9X_wpf все эти элементы.

Но поскольку в моих коллекциях 9X_wpf никогда не бывает более 100 элементов, я 9X_wpf не вижу в этом проблемы.

В любом случае я 9X_wpf создал унаследованный класс следующим методом:

protected override void ClearItems() { CheckReentrancy(); List oldItems = new List(Items); Items.Clear(); OnPropertyChanged(new PropertyChangedEventArgs("Count")); OnPropertyChanged(new PropertyChangedEventArgs("Item[]")); NotifyCollectionChangedEventArgs e = new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction.Reset ); FieldInfo field = e.GetType().GetField ( "_oldItems", BindingFlags.Instance | BindingFlags.NonPublic ); field.SetValue(e, oldItems); OnCollectionChanged(e); } 

2
1

  • Зачем тебе это делать? Есть и другие вещи, котор ...

Ответ #12

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

ObservableCollection, а также интерфейс 9X_wpf INotifyCollectionChanged явно написаны с 9X_observablecollection учетом конкретного использования: создание 9X_observablecollection пользовательского интерфейса и его конкретные 9X_observablecollection характеристики производительности.

Если вам 9X_wpf нужны уведомления об изменениях в коллекции, обычно 9X_observablecollection вас интересуют только события «Добавить 9X_observablecollection и удалить».

Я использую следующий интерфейс:

using System; using System.Collections.Generic; /// 
/// Notifies listeners of the following situations: /// /// Elements have been added. /// Elements are about to be removed. /// ///
 /// The type of elements in the collection. interface INotifyCollection { /// 
/// Occurs when elements have been added. ///
 event EventHandler> Added; /// 
/// Occurs when elements are about to be removed. ///
 event EventHandler> Removing; } /// 
/// Provides data for the NotifyCollection event. ///
 /// The type of elements in the collection. public class NotifyCollectionEventArgs : EventArgs { /// 
/// Gets or sets the elements. ///
 /// The elements. public IEnumerable Items { get; set; } } 

Я 9X_observablecollection также написал свою собственную перегрузку 9X_wpf Collection, где:

  • ClearItems вызывает удаление
  • InsertItem вызывает добавление
  • RemoveItem вызывает удаление
  • SetItem вызывает удаление и добавление

Конечно, можно добавить 9X_observablecollection и AddRange.

2
0

Ответ #13

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

Я просто просматривал код построения диаграмм 9X_observablecollection в наборах инструментов Silverlight и WPF 9X_observablecollection и заметил, что они также решили эту проблему 9X_observablecollection (подобным образом) ... и я подумал, что 9X_observablecollection опубликую их решение.

По сути, они также 9X_observablecollection создали производную ObservableCollection 9X_observablecollection и переопределили ClearItems, вызывая Remove 9X_wpf для каждого очищаемого элемента.

Вот код:

/// 
/// An observable collection that cannot be reset. When clear is called /// items are removed individually, giving listeners the chance to detect /// each remove event and perform operations such as unhooking event /// handlers. ///
 /// The type of item in the collection. public class NoResetObservableCollection : ObservableCollection { public NoResetObservableCollection() { } /// 
/// Clears all items in the collection by removing them individually. ///
 protected override void ClearItems() { IList items = new List(this); foreach (T item in items) { Remove(item); } } } 

1
0

Ответ #14

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

Это горячая тема ... потому что, на мой 9X_observablecollection взгляд, Microsoft не выполнила свою работу 9X_observablecollection должным образом ... снова. Не поймите меня 9X_wpf неправильно, мне нравится Microsoft, но 9X_observablecollection они не идеальны!

Я прочитал большинство предыдущих 9X_wpf комментариев. Я согласен со всеми, кто считает, что 9X_observablecollection Microsoft неправильно запрограммировала 9X_wpf Clear().

По крайней мере, на мой взгляд, для 9X_observablecollection этого нужен аргумент, чтобы можно было отделить 9X_wpf объекты от события ... но я также понимаю 9X_observablecollection влияние этого. Затем я придумал это предложенное 9X_observablecollection решение.

Я надеюсь, что это сделает всех 9X_wpf счастливыми или, по крайней мере, почти 9X_wpf всех ...

Эрик

using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Reflection; namespace WpfUtil.Collections { public static class ObservableCollectionExtension { public static void RemoveAllOneByOne(this ObservableCollection obsColl) { foreach (T item in obsColl) { while (obsColl.Count > 0) { obsColl.RemoveAt(0); } } } public static void RemoveAll(this ObservableCollection obsColl) { if (obsColl.Count > 0) { List removedItems = new List(obsColl); obsColl.Clear(); NotifyCollectionChangedEventArgs e = new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction.Remove, removedItems ); var eventInfo = obsColl.GetType().GetField ( "CollectionChanged", BindingFlags.Instance | BindingFlags.NonPublic ); if (eventInfo != null) { var eventMember = eventInfo.GetValue(obsColl); // note: if eventMember is null // nobody registered to the event, you can't call it. if (eventMember != null) eventMember.GetType().GetMethod("Invoke"). Invoke(eventMember, new object[] { obsColl, e }); } } } } } 

1
0

Ответ #15

Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов

Чтобы не усложнять, почему бы вам не переопределить 9X_observablecollection метод ClearItem и не сделать там все, что 9X_wpf вы хотите, т.е. отсоединить элементы от 9X_observablecollection события.

public class PeopleAttributeList : ObservableCollection, { { protected override void ClearItems() { Do what ever you want base.ClearItems(); } rest of the code omitted } 

Простой, понятный и содержащийся 9X_wpf в коде коллекции.

1
0