Удалить все для ObservableCollections? - PullRequest
66 голосов
/ 25 февраля 2011

Я ищу способ Linq (например, метод RemoveAll для List), который может удалить выбранные элементы из моей коллекции ObservableCollection.

Я слишком новичок, чтобы создавать метод расширения для себя. Есть ли способ удалить элементы из ObservableCollection, передавая лямбда-выражение?

Ответы [ 7 ]

89 голосов
/ 25 февраля 2011

Я не знаю, как удалить только выбранные элементы.Но создать метод расширения просто:

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);
39 голосов
/ 07 марта 2013

Повторение в обратном направлении должно быть более эффективным, чем создание временной коллекции, как в примере Даниэля Хилгарта.

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);
            }
        }
    }
}
13 голосов
/ 13 ноября 2015

Как насчет этой реализации для однострочника?

observableCollection.Where(l => l.type == invalid).ToList().All(i => observableCollection.Remove(i))

- Правка -

Извините, да, вам нужен ToList () в середине, чтобы вызвать первыйполовина для оценки, поскольку LINQ по умолчанию выполняет отложенную оценку.

9 голосов
/ 23 октября 2014

Каждое из предложенных здесь решений, в котором используется процедура удаления элемента одно за другим, имеет одну ошибку.Представьте, что у вас есть много предметов в наблюдаемой коллекции, скажем, 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));
1 голос
/ 03 января 2019
ObservableCollection<AppVariable<G>> _appVariables = new new ObservableCollection<AppVariable<G>>();

var temp = AppRepository.AppVariables.Where(i => i.IsChecked == true).OrderByDescending(k=>k.Index);

foreach (var i in temp)
{
     AppRepository.AppVariables.RemoveAt(i.Index);
}
1 голос
/ 24 февраля 2017

Это моя версия решения с помощью метода расширения, которая лишь незначительно отличается от принятого ответа, но имеет то преимущество, что возвращаемое количество основано на подтвержденном удалении элемента из коллекции:

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's a successful removal
        return toRemove.Count(observableCollection.Remove);
    }
}
1 голос
/ 25 февраля 2011

Невозможно передать выражение в ObservableCollection для удаления совпадающих элементов так же, как и в общем списке. ObservableCollection добавляет и удаляет один элемент за раз.

Вам потребуется создать собственную реализацию INotifyCollectionChanged, чтобы сделать это или, как вы упомянули, создать метод расширения.

...