УдалитьAll для ObservableCollections?
Я ищу способ Linq (например, метод RemoveAll для List), который может удалить выбранные элементы из моего ObservableCollection.
Я слишком новичок в создании метода расширения для себя. Есть ли способ удалить элементы из ObservableCollection, передавая выражение Lambda?
Ответы
Ответ 1
Я не знаю, как удалить только выбранные элементы. Но создание метода расширения прямолинейно:
public static class ExtensionMethods
{
public static int Remove<T>(
this ObservableCollection<T> coll, Func<T, bool> condition)
{
var itemsToRemove = coll.Where(condition).ToList();
foreach (var itemToRemove in itemsToRemove)
{
coll.Remove(itemToRemove);
}
return itemsToRemove.Count;
}
}
Это удаляет все элементы из ObservableCollection
, которые соответствуют условию. Вы можете так называть:
var c = new ObservableCollection<SelectableItem>();
c.Remove(x => x.IsSelected);
Ответ 2
Итерация назад должна быть более эффективной, чем создание временной коллекции, как в примере Даниэля Хильгарта.
public static class ObservableCollectionExtensions
{
public static void RemoveAll<T>(this ObservableCollection<T> collection,
Func<T, bool> condition)
{
for (int i = collection.Count - 1; i >= 0; i--)
{
if (condition(collection[i]))
{
collection.RemoveAt(i);
}
}
}
}
Ответ 3
Как насчет этой реализации для одного слоя?
observableCollection.Where(l => l.type == invalid).ToList().All(i => observableCollection.Remove(i))
- Изменить -
Извините, да, вам нужен ToList() в середине, чтобы заставить первую половину оценить, поскольку LINQ по умолчанию выполняет ленивую оценку.
Ответ 4
Каждое предлагаемое здесь решение, которое использует процедуру для удаления элемента один за другим, имеет одну ошибку. Представьте, что у вас много предметов в наблюдаемой коллекции, скажем 10.000 предметов. Затем вы хотите удалить элементы, которые удовлетворяют некоторому условию.
Если вы используете решение из Daniel Hilgarth
и вызываете: c.Remove(x => x.IsSelected);
, и, например, 3000 элементов будут удалены, предлагаемое решение сообщит об удалении каждого элемента. Это связано с тем, что внутренняя реализация Remove(item)
уведомляет об этом изменении. И это будет вызвано для каждого из 3000 элементов в процессе удаления.
Итак, вместо этого я создал потомка ObservableCollection и добавил новый метод RemoveAll(predicate)
[Serializable]
public class ObservableCollectionExt<T> : ObservableCollection<T>
{
public void RemoveAll(Predicate<T> predicate)
{
CheckReentrancy();
List<T> itemsToRemove = Items.Where(x => predicate(x)).ToList();
itemsToRemove.ForEach(item => Items.Remove(item));
OnPropertyChanged(new PropertyChangedEventArgs("Count"));
OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
Интересная строка itemsToRemove.ForEach(item => Items.Remove(item));
. Вызов напрямую Items.Remove(item)
не будет уведомлять об удалении элемента.
Вместо удаления необходимых элементов изменения сообщаются сразу же по вызовам:
OnPropertyChanged(new PropertyChangedEventArgs("Count"));
OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
Ответ 5
Невозможно передать выражение ObservableCollection, чтобы удалить соответствующие элементы, так же, как и общий список. ObservableCollection добавляет и удаляет по одному элементу за раз.
Вам нужно будет создать свою собственную реализацию INotifyCollectionChanged, или, как вы заметите, создайте метод расширения.
Ответ 6
Это моя версия решения метода расширения, которое является лишь небольшим изменением принятого ответа, но имеет то преимущество, что возвращенный счет основан на подтвержденном удалении элемента из коллекции:
public static class ObservableCollectionExtensionMethods
{
/// <summary>
/// Extends ObservableCollection adding a RemoveAll method to remove elements based on a boolean condition function
/// </summary>
/// <typeparam name="T">The type contained by the collection</typeparam>
/// <param name="observableCollection">The ObservableCollection</param>
/// <param name="condition">A function that evaluates to true for elements that should be removed</param>
/// <returns>The number of elements removed</returns>
public static int RemoveAll<T>(this ObservableCollection<T> observableCollection, Func<T, bool> condition)
{
// Find all elements satisfying the condition, i.e. that will be removed
var toRemove = observableCollection
.Where(condition)
.ToList();
// Remove the elements from the original collection, using the Count method to iterate through the list,
// incrementing the count whenever there a successful removal
return toRemove.Count(observableCollection.Remove);
}
}