【问题标题】:Handling ObservableCollection CollectionChanged Event处理 ObservableCollection CollectionChanged 事件
【发布时间】:2011-09-06 00:53:03
【问题描述】:

我在 Silverlight 工具包中看到过类似以下的代码,但不明白这样做的安全性:

private void ItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    // Update the cache
    if (e.Action == NotifyCollectionChangedAction.Remove && e.OldItems != null)
    {
        for (int index = 0; index < e.OldItems.Count; index++)
        {
            _items.RemoveAt(e.OldStartingIndex);
        }
    }
}

如果您从说索引 5 中删除一个项目,这不会将索引 5 之后的 _items 集合中每个项目的当前索引更改为比以前少一个吗?那么,像这段代码那样使用“旧”索引不断删除项目是安全的吗?

我真的很想知道为什么会这样。

有什么想法吗?

【问题讨论】:

    标签: wpf silverlight observablecollection inotifycollectionchanged


    【解决方案1】:

    这段代码看起来像是从特定的起始索引中删除一组连续的项目。如果您仔细阅读删除调用:

    _items.RemoveAt( e.OldStartingIndex );  
    

    您会注意到它正在迭代地从常量索引中删除项目。这意味着它通过删除连续范围内的项目来折叠列表。这很可能是正确的 - 假设这是代码的意图。

    循环执行的次数与e.OldItems.Count 指示的一样多。所以(大概)它被告知从给定索引开始删除多少项目。

    作为一般惯例,您必须小心如何从集合中删除项目,原因如下:

    1. 当您删除项目时,项目索引确实会发生变化。因此必须注意避免因项目索引位置移动而导致的错误。
    2. 在迭代列表时更改列表(如在 foreach 循环中或使用显式 IEnumerator)会导致异常。迭代时不能改变列表(添加或删除) - 它会使迭代器无效。

    【讨论】:

    • 对我来说唯一有意义的方法是保证 e.OldItems 是按降序排列的。但我在任何 MSDN 文档中都没有提到这一点,所以这让我很紧张。
    • 在不知道上面代码所期望的意图和前提条件的情况下,您无法真正说出它是否正确。但是,如果意图是删除列表中一系列连续的、升序的项目,它看起来确实“可能”是正确的。
    • 假设我们正在谈论 ObservableCollection,它是 .Net 的一部分。它实现了 INotifyCollectionChanged 接口。我想我要问的是,它是否保证 NotifyCollectionChangedEventArgs 会以正确的顺序为您提供索引以允许上述代码始终有效?另外,您是否不必按降序删除项目以免受到索引移位的影响?
    • @unknown:如果处理事件的代码不能依赖受影响项目的连续性质,我看不出事件 args 中存在 OldStartingIndex 属性的意义。我同意,最好为任何打算创建 INotifyCollectionChanged 的​​其他实现的人明确说明这一点。
    猜你喜欢
    • 2013-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-06
    • 2016-12-24
    • 1970-01-01
    相关资源
    最近更新 更多