RemoveAll for ObservableCollections?

I am looking for Linq way (like RemoveAll method for List) which can remove selected items from my ObservableCollection.

I am too new to create an extension method for myself. Is there any way I remove items from ObservableCollection passing a Lambda expression?

47682 次浏览

我不知道一种只删除选定项的方法。但创建一种扩展方法很简单:

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

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

为此,您必须创建自己的 INotifyCollectionChanged 实现,或者像您提到的那样创建一个扩展方法。

向后迭代应该比创建临时集合(如 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);
}
}
}
}

这里提出的每一种使用例程逐项删除的解决方案都有一个缺陷。假设您有许多可观察到的收藏品,比方说10.000件。然后要删除满足某些条件的项。

如果您使用 丹尼尔 · 希尔加思的解决方案并调用: c.Remove(x => x.IsSelected);,例如有3000个项目要删除,建议的解决方案将通知每个项目删除。这是因为 Remove(item)的内部实现通知了这一变化。这将被称为每3000项在删除过程中。

因此,我创建了 Observer ableCollection 的子代,并添加了新的方法 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));

How about this implementation for a one-liner?

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

——编辑——

对不起,是的,您需要中间的 ToList ()来强制前半部分进行计算,因为 LINQ 默认执行惰性计算。

这是我的扩展方法解决方案版本,它只是接受答案的一个细微变化,但其优点是返回的计数基于从集合中删除项目的 确认:

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