从ObservableCollection中删除空项

时间:2012-09-12 16:26:14

标签: c# .net

我在使用以下代码时遇到了一些问题:

AllAgents.CollectionChanged += (sender, e) =>
            {
                if (e.Action != NotifyCollectionChangedAction.Remove) return;

                foreach (var s in AllSnapshots)
                {
                    foreach (var stat in s.Stats.Where(stat => stat.Model.Agent == null))
                        s.Stats.Remove(stat);
                }
            };

这当然会抛出“Collection已被修改;枚举操作可能无法执行”。对我来说完全有意义的例外。问题是,从ObservableCollection中删除Model.Agent属性为null的所有项目的最佳方法是什么?我也对其他解决方案持开放态度,实质上,当从AllAgents集合中删除代理时,我需要从我的AllSnapshots.Stats集合中删除任何引用该代理的条目。

4 个答案:

答案 0 :(得分:3)

从这样的集合中删除项目的最佳方法是使用标准的for循环结构并向后迭代集合。由于您不再依赖枚举器来迭代集合,因此您可以安全地修改它而不会干扰循环。

反向迭代可防止在循环过程中删除干扰索引,否则会导致某些元素最终无法被删除。

ObservableCollection<Stat> o = new ObservableCollection<Stat>();
for (int i = o.Count - 1; i >= 0; i--) {
    if (o[i] == null) 
        o.RemoveAt(i);                
}

答案 1 :(得分:1)

问题是你正在迭代和删除并尝试再次迭代。 ObservableCollection不支持此功能,因为它不会跟踪哪些元素已被删除。

将您的foreach替换为不依赖于未修改的Collection的标准编号,并且全部。

这个解决方案延迟了Sam我的回复是不使用额外的内存来创建另一个列表(如果你的元素数量足够大,这可能相当昂贵)。

答案 2 :(得分:0)

我可能会做的是生成一个要删除的统计信息列表,然后在单独的foreach循环中将它们全部删除

foreach (var s in AllSnapshots)
{
    list<object> stats = new list<object> 
   //if this doesn't work i'll leave it up to you to look up how to list a generic type

    foreach (var stat in s.Stats.Where(stat => stat.Model.Agent == null))
        stats.add(stat);

    foreach(var stat in stats)
        s.Stats.Remove(stat);
}

答案 3 :(得分:0)

如果每张快照的统计数据都相当低,我可能会这样做:

foreach(var s in AllSnapShots)
{
    s.Stats = new ObservableCollection<Stats>(s.Where(stat =>stat.Model.Agent != null));
}

因此,将使用 null的元素构建新集合。但是,如果统计数据列表相当大,您也可以这样做:

List<WhateverYourCollectionWasOf> statsToDelete;

foreach(var s in AllSnapShots)
{
    statsToDelete.AddRange(s.Stats.Where(stat => stat.Model.Agent == null));

    foreach (var stat in statsToDelete)
    {
         s.Stats.Remove(stat);
    }
}

或者,如果你想成为未来的证据,你可以写一个扩展方法来做这类事情:

public static class ExtensionMethods
{
    public static ObservableCollection<T> RemoveAll<T>(
        this ObservableCollection<T> collection, Func<T, bool> predicate)
    {
        List<T> collectionAsList = collection.ToList();
        List<T> itemsToRemove = collection.Where(predicate);            
        collectionAsList.RemoveAll(i => itemsToRemove.Contains(i));
        collection = new ObservableCollection<T>(collectionAsList);
        return collection;
    }
}

然后会这样调用:

foreach(var s in AllSnapShots)
{
    s.Stats.RemoveAll(stat => stat.Model.Agent == null);
}
相关问题