RemoveAll for ObservableCollections?

问题描述 投票:0回答:8

我正在寻找可以从我的 ObservableCollection 中删除所选项目的 Linq 方式(如 List 的 RemoveAll 方法)。

我太新了,无法为自己创建扩展方法。有什么方法可以通过 Lambda 表达式从 ObservableCollection 中删除项目?

c# observablecollection removeall
8个回答
111
投票

我不知道有什么方法可以只删除选定的项目。但是创建扩展方法很简单:

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

54
投票

向后迭代应该比创建临时集合更有效,如 Daniel Hilgarth 的example.

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

15
投票

单行的这个实现怎么样?

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

-- 编辑 --

抱歉,是的,您需要在中间使用 ToList() 来强制前半部分求值,因为 LINQ 默认情况下会进行惰性求值。


10
投票

这里提出的每一个使用例程逐项删除的解决方案都有一个错误。想象一下,您在可观察集合中有很多项目,比如说 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));

2
投票

这是我的扩展方法解决方案版本,与已接受的答案仅略有不同,但优点是返回的计数基于已确认从集合中删除项目:

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
投票

无法像通用列表那样将表达式传递给 ObservableCollection 以删除匹配项。 ObservableCollection 一次添加和删除一项。

您必须创建自己的 INotifyCollectionChanged 实现才能执行此操作,或者如您提到的创建扩展方法。


1
投票
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);
}

0
投票

有点晚了,但只是把它贴在这里,因为我在遇到同样的问题时找不到在线的另一个解决方案。

https://i.stack.imgur.com/sbVDQ.png

假设您有一个 ID 或各种名称,您可以从中获取要删除的对象,您可以使用 ObservableCollections 中的 .First 方法获取要删除的对象,并调用 .Remove 方法删除所选项目。

或者,您可以将整个第一行放入 Remove 方法中。

© www.soinside.com 2019 - 2024. All rights reserved.