При очистке 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