【问题标题】:INotifyCollectionChanged: Added item does not appear at given index '0'INotifyCollectionChanged:添加的项目未出现在给定索引“0”处
【发布时间】:2011-08-18 12:55:45
【问题描述】:

我正在制作一个可观察的课程。 Add 方法工作正常。但后来我尝试调用 Remove() 方法时出现此错误:

“添加的项目没有出现在给定的索引'0'”

但我将 NotifyCollectionChangedAction 枚举设置为 Remove,如下所示。

    public class ObservableOrderResponseQueue : INotifyCollectionChanged, IEnumerable<OrderResponse>
{
    public event NotifyCollectionChangedEventHandler CollectionChanged;
    private List<OrderResponse> _list = new List<OrderResponse>();


    public void Add(OrderResponse orderResponse)
    {
        this._list.Add(orderResponse);
        if (CollectionChanged != null)
        {
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, orderResponse, 0));
        }
    }

    public void RemoveAt(int index)
    {
        OrderResponse order = this._list[index];
        this._list.RemoveAt(index);
        if (CollectionChanged != null)
        {
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, order, index));
        }
    }

    public void Remove(OrderResponse orderResponse)
    {
        var item = _list.Where(o => o.OrderDetail.TrayCode == orderResponse.OrderDetail.TrayCode).FirstOrDefault();
        int index = _list.IndexOf(item);

        this._list.RemoveAt(index);
        if (CollectionChanged != null)
        {
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index));
        }
    }

【问题讨论】:

  • 哪一行引发了异常?
  • 你应该创建一个方法来一次添加或删除一组对象。
  • 我也遇到了这个错误。最后将其归结为我正在添加的对象上的覆盖 Equals 和 public static bool operator == 中的一个错误。花了几个小时来调试这个,所以希望可以节省其他人一些时间。
  • 如果此集合数据绑定到 UI 元素,请检查该集合是否正在非 UI 线程上更新(在您的情况下,是在调用 Remove 时)。

标签: c# wpf


【解决方案1】:

您确定错误与Remove 方法有关吗?错误消息和您的源代码表明它在 Add 方法中。尝试在NotifyCollectionChangedEventArgs的构造函数中使用正确的索引_list.Count - 1

CollectionChanged(this, new NotifyCollectionChangedEventArgs(
                                              NotifyCollectionChangedAction.Add, 
                                              orderResponse, _list.Count - 1)
                 );

【讨论】:

  • 是的,我确定我正在调用 Remove 方法。这就是为什么我不明白。为什么会出现这个错误。
  • @Tan:您是否按照我要求的方式更改了您的Add 方法?如果没有,请这样做,只是为了确定!
  • 调用List&lt;T&gt;.Add将新元素添加到列表的end,即新元素是列表的最后一个,即它有索引list.Count - 1 . NotifyCollectionChangedEventArgs 的构造函数要求你传入新添加对象的索引,因此你传入list.Count - 1
  • 我可以确认这个完全令人困惑的异常是在 Remove (!) 回调中引发的,并通过将正确的索引传递给 Add 回调来修复。令人困惑的是,根本没有在 Add 上传递任何索引(记录为 valid thing to do!)也会导致这个令人困惑的异常消息。
  • 我在实现“排序”的 ObservableCollection 类后遇到了这个问题。当您将一个元素添加到列表中时,它不一定会添加到列表的末尾。但是,当为“添加”操作引发集合更改事件时,WPF 期望将元素添加到列表的末尾。我设法解决这个问题的方法是首先将元素添加到列表的末尾,然后将其移动到正确的索引。
【解决方案2】:

如果我猜的话,我会说这条线......

var item = _list.Where(
    o => o.OrderDetail.TrayCode == orderResponse.OrderDetail.TrayCode)
    .FirstOrDefault();

...因为它调用FirstOrDefault(),可能会返回null。设置断点,看看实际发生了什么。

为此,为什么还要进行该查询?既然您要传入要删除的对象,为什么不简单地这样做:

int index = _list.IndexOf(item);
if (index >= 0)
    this._list.RemoveAt(index);
//then pass item to your eventargs since it was the object removed.

更好,因为List&lt;T&gt; 有自己的Remove(T object) 方法:

this._list.Remove(item);
//this may throw an exception or not if the item is not in that collection,
// which is behavior you should probably retain

旁注

您如何引发CollectionChanged 事件也可能存在竞争条件。在检查null 和提升它之间,订阅者可以从事件中删除它的委托。这是避免这种情况的简单方法:

// initialize it with an empty lamda so it is never null
public event NotifyCollectionChangedEventHandler CollectionChanged = (o,e) => {};

现在你可以直接提高它而无需检查它是否为空:

public void Add(OrderResponse orderResponse)
{
    this._list.Add(orderResponse);
    CollectionChanged(this,
        new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add,
            orderResponse, this._list.Count - 1));
}

这并不能使其完全线程安全,但它是一种确保引发事件不会引发空引用异常的简单方法。

【讨论】:

    【解决方案3】:

    我追踪了 Reflector 的问题,并发现此异常的原因可能是指Equals 没有为列表中实际相等的对象返回 true;或者operator ==

    【讨论】:

      【解决方案4】:

      当我尝试使用 Remove 参数创建一个新的NotifyCollectionChangedEventArgs 时收到此异常删除。

      有一次,我将传递给 NotifyCollectionChangedEventArgs 的项目更改为我从内部列表中删除的实际项目,异常

      “添加的项目没有出现在给定的索引处..”

      走了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-04-05
        • 2013-02-15
        • 1970-01-01
        • 2016-02-16
        • 2014-06-10
        • 2013-06-15
        • 1970-01-01
        相关资源
        最近更新 更多