RemoveAll for ObservableCollections?

Arp*_*wal 68 c# observablecollection removeall

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

我太新了,无法为自己创建扩展方法.有没有办法从ObservableCollection中删除传递Lambda表达式的项目?

Dan*_*rth 92

我不知道只删除所选项目的方法.但是创建扩展方法很简单:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这将删除ObservableCollection符合条件的所有项目.你可以这样称呼它:

var c = new ObservableCollection<SelectableItem>();
c.Remove(x => x.IsSelected);
Run Code Online (Sandbox Code Playgroud)


小智 40

向后迭代应该比在Daniel Hilgarth的例子中创建临时集合更有效.

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 在实际测试的应用程序中,我发现这确实比临时收集更快 - 平均时间为 44 毫秒,峰值为 62 毫秒,而临时收集的平均时间为 55 毫秒,峰值为 93 毫秒 (2认同)

sim*_*005 13

单线程的实现怎么样?

observableCollection.Where(l => l.type == invalid).ToList().All(i => observableCollection.Remove(i))
Run Code Online (Sandbox Code Playgroud)

- 编辑 -

对不起,是的,您需要在中间强制使用ToList()来强制评估上半部分,因为默认情况下LINQ会进行延迟评估.


psu*_*lek 9

这里提出的每个解决方案使用例程逐个删除项目都有一个错误.想象一下,在可观察集合中有很多项目,可以说是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));
    }
}
Run Code Online (Sandbox Code Playgroud)

有趣的是itemsToRemove.ForEach(item => Items.Remove(item));.直接呼叫Items.Remove(item)不会通知有关删除的项目.

取消所需项目后,将通过以下呼叫立即通知更改:

OnPropertyChanged(new PropertyChangedEventArgs("Count"));
OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
Run Code Online (Sandbox Code Playgroud)

  • 在一个真实世界的应用程序中,我发现这实际上比临时收集慢 - 平均时间为67毫秒,峰值时间为152毫秒,而平均时间为55毫秒,峰值为93毫秒.请记住,这仅适用于小型收藏品. (2认同)