RemoveAll для ObservableCollections?

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

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

6 ответов


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

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);

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

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);
            }
        }
    }
}

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

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

-- Edit --

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


каждое из предложенных здесь решений, которое использует процедуру для удаления элемента один за другим, имеет одну ошибку. Представьте, что у вас много предметов в наблюдаемой коллекции, скажем, 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));

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

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


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

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);
    }
}