Страницы

Поиск по вопросам

четверг, 12 декабря 2019 г.

Потеря обработчиков событий после использования LINQ

#c_sharp #события #linq #observablecollection


Есть ObservableCollection mystrings, которой я на старте приложения присваиваю
значения, и делаю обработчик события mystrings.CollectionChanged += mystrings_OnChange;

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

mystrings = new ObservableCollection(mystrings.Where(x => x ...));


То после этого у меня mystrings новый обьект, который "потерял" обработчики событий.
Как правильнее с этим бороться?
    


Ответы

Ответ 1



Проблема ObservableCollection в том, что она не работает с диапазонами данных одновременно (добавить диапазон, удалить диапазон, заменить диапазон). Предложение добавить диапазоны в API ObservableCollection ещё не реализовано и не будет даже в .NET Core 3.x, так как команда WPF и так очень загружена из-за того, что данное предложение может поломать WPF, который не умеет работать с изменением диапазона данных, а не одного элемента данных. Поэтому вижу три возможности: Пересоздать коллекцию, заново добавить обработчик события CollectionChanged. Вы так и сделали в своём вопросе. Получить коллекцию элементов, которые нужно оставить, очистить ObservableCollection с помощью метода Clear, в цикле добавить в ObservableCollection нужные элементы через Add. Возможно, надо будет отключить обработчик CollectionChanged до Clear и цикла добавления, а затем подключить его заново после цикла. Получить коллекцию элементов для удаления, в цикле удалить из ObservableCollection ненужные элементы через Remove. Возможно, надо будет отключить обработчик CollectionChanged до цикла удаления, а затем подключить его заново после цикла.

Ответ 2



Возможно поможет моя библиотека ObservableComputations. Ваш код с использованием этой библиотеки будет выглядеть так: ObservableCollection filteredMystrings = mystrings.Filtering(x => x ...)); Чтобы этот код работал нужно чтобы mystrings был ObservableCollection.

Ответ 3



скопировать в коллекцию ту выборку которую ты сделал не забудь посмотреть что будет с длинной мой вариант: oc.ClearItems(); foreach(l in enumerable){ oc.InsertItem(l); } специально посмотрел в Microsoft.Docs. оба метода вызывают событие CollectionChanged

Ответ 4



Реализация третьего варианта ответа @Vadim Ovchinnikov, но без создания временной коллекции. //Использованы части кода из ответа @KuzCode public static void Main(string[] args) { var collection = new ObservableCollection(); NotifyCollectionChangedEventHandler handler = (obj, e) => { if (obj is ObservableCollection coll) { Console.Write("items now: "); foreach (var item in coll) Console.Write(item + " "); Console.WriteLine(); } }; collection.CollectionChanged += handler; for (int i = 0; i < 10; i++) collection.Add(i); collection.RemoveNotMatched(t => t >= 5); collection.RemoveNotMatched(t => t >= 7, handler); Console.ReadKey(); } public static void RemoveNotMatched(this ObservableCollection coll , Func predicate) { for (int i = coll.Count()-1; i >= 0; i--) { var item = coll[i]; if (!predicate(item)) coll.Remove(item); } } public static void RemoveNotMatched(this ObservableCollection coll , Func predicate , NotifyCollectionChangedEventHandler handler) { coll.CollectionChanged -= handler; RemoveNotMatched(coll, predicate); coll.CollectionChanged += handler; handler(coll, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } Вывод items now: 0 items now: 0 1 items now: 0 1 2 items now: 0 1 2 3 items now: 0 1 2 3 4 items now: 0 1 2 3 4 5 items now: 0 1 2 3 4 5 6 items now: 0 1 2 3 4 5 6 7 items now: 0 1 2 3 4 5 6 7 8 items now: 0 1 2 3 4 5 6 7 8 9 items now: 0 1 2 3 5 6 7 8 9 items now: 0 1 2 5 6 7 8 9 items now: 0 1 5 6 7 8 9 items now: 0 5 6 7 8 9 items now: 5 6 7 8 9 items now: 7 8 9

Ответ 5



Я предлагаю, возможно, не самый быстрый по производительности способ, но он абсолютно практичен. Просто создайте функцию-расширение для коллекции CopyFrom(), которая принимает List, и добавьте все объекты из списка в вашу коллекцию. Вот пример кода: using System; using System.Collections.ObjectModel; using System.Collections.Generic; using System.Linq; namespace Rextester { public static class Program { public static void Main(string[] args) { var collection = new ObservableCollection(); collection.CollectionChanged += (obj, e) => // добавляем событие { Console.Write("items now: "); foreach (var item in collection) Console.Write(item + " "); Console.WriteLine(); }; for (int i = 0; i < 10; i++) collection.Add(i); // добавляем элементы collection.CopyFrom(collection.Where((item) => item >= 5).ToList()); //делаем выборку } public static void CopyFrom(this ObservableCollection coll, List list) { coll.Clear(); list.ForEach((item) => coll.Add(item)); } } } И пример вывода: items now: 0 items now: 0 1 items now: 0 1 2 items now: 0 1 2 3 items now: 0 1 2 3 4 items now: 0 1 2 3 4 5 items now: 0 1 2 3 4 5 6 items now: 0 1 2 3 4 5 6 7 items now: 0 1 2 3 4 5 6 7 8 items now: 0 1 2 3 4 5 6 7 8 9 items now: items now: 5 items now: 5 6 items now: 5 6 7 items now: 5 6 7 8 items now: 5 6 7 8 9

Комментариев нет:

Отправить комментарий