При очистке 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 }; } }
Ответ #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 сильно падает.
- Что ж, если «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.
- Проблема, Орион, с вашим предложением ... это случай использования, который вызвал этот вопрос. Что происходит, когда в списке есть элементы, от которых я хочу отделить событие? Я не могу просто выгрузить данные из списка ... это ...
Ответ #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 будет вызываться перед очисткой коллекции.
Ответ #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 ... }
Преимущества:
-
Нет 9X_wpf необходимости подписываться на дополнительное 9X_observablecollection событие (в соответствии с принятым ответом)
-
Не 9X_observablecollection генерирует событие для каждого удаленного 9X_observablecollection объекта (некоторые другие предлагаемые решения 9X_observablecollection приводят к множеству удаленных событий).
-
Подписчику 9X_observablecollection нужно только проверять NewItems и OldItems 9X_wpf на любом событии, чтобы добавлять / удалять 9X_observablecollection обработчики событий по мере необходимости.
Недостатки:
-
Нет 9X_observablecollection события сброса
-
Небольшие (?) накладные расходы 9X_observablecollection на создание копии списка.
-
???
ИЗМЕНИТЬ 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 одно уведомление об удалении
- @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 }
Ответ #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(); } }
- Лол отличное имя. Согласен, это ...
Ответ #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); } } }
Ответ #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 несложно, но это много печатать.
Ответ #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; } } }
Ответ #10
Ответ на вопрос: При очистке ObservableCollection в e.OldItems нет элементов
Глядя на NotifyCollectionChangedEventArgs, кажется, что OldItems содержит 9X_wpf только элементы, измененные в результате 9X_wpf действия «Заменить», «Удалить» или «Переместить». Это 9X_observablecollection не означает, что он будет содержать что-либо 9X_wpf на Clear. Я подозреваю, что Clear запускает 9X_observablecollection событие, но не регистрирует удаленные элементы 9X_observablecollection и вообще не вызывает код удаления.
- Я тоже это видел, но мне это не нравится. Мне это кажется зияющей дырой ...
Ответ #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); }
- Зачем тебе это делать? Есть и другие вещи, котор ...
Ответ #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.
Ответ #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); } } }
Ответ #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 }); } } } } }
Ответ #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 в коде коллекции.
-
2
-
19
-
5
-
3
-
2
-
4
-
3
-
2
-
5
-
3
-
3
-
3
-
8
-
2
-
3
-
2
-
1
-
1
-
3
-
2
-
3
-
2
-
11
-
6
-
17
-
5
-
3
-
3
-
7
-
7
-
3
-
2
-
3
-
5
-
3
-
2
-
11
-
5
-
8
-
8
-
10
-
30
-
7
-
6
-
6
-
3
-
4
-
3
-
14
-
10