7

I'm making a observable class. The Add methods works fine. But then I'm trying to call the Remove() method I get this error:

"Added item does not appear at given index '0'"

but I'm setting the NotifyCollectionChangedAction enum to Remove as the code below.

    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));
        }
    }
Cœur
  • 37,241
  • 25
  • 195
  • 267
Tan
  • 2,148
  • 3
  • 33
  • 54
  • which line raises the exception? – Marino Šimić May 04 '11 at 13:10
  • You should make a method to add or remove a set of objects all at once. – MrFox Feb 18 '13 at 15:54
  • 1
    I was getting this error as well. Finally tracked it down to a bug in my override Equals and public static bool operator == on the object I was adding. Took hours to debug this so hopefully might save others some time. – FreddyFlares May 25 '14 at 00:55
  • If this collection is data-bound to a UI element, check whether the collection is being updated (in your case, when `Remove` was called) on a non-UI thread. – hillin May 31 '19 at 10:41

4 Answers4

9

Are you sure the error is with the Remove method? The error message and your source code indicate it is in the Add method. Try using the correct index _list.Count - 1 in the constructor of NotifyCollectionChangedEventArgs:

CollectionChanged(this, new NotifyCollectionChangedEventArgs(
                                              NotifyCollectionChangedAction.Add, 
                                              orderResponse, _list.Count - 1)
                 );
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • 1
    Yes iam sure iam calling the Remove method. Thats why i dont get it. Why does this error appear. – Tan May 04 '11 at 13:19
  • @Tan: Did you change your `Add` method the way I asked you to do? If not, please do it, just to be sure! – Daniel Hilgarth May 04 '11 at 13:31
  • Sorry! I thought i should change the Remove method. But it was the add method. Now everything works great. Thanks for the help. – Tan May 04 '11 at 13:45
  • Now it works fine but i dont get it why do i have to use _list.Count - 1. why minus 1 in add function ? – Tan May 04 '11 at 13:48
  • 1
    Calling `List.Add` adds the new element to the **end** of the list, i.e. the new element is the last one in the list, i.e. it has the index `list.Count - 1`. The constructor of `NotifyCollectionChangedEventArgs` requires you to pass in the index of the newly added object, hence you pass `list.Count - 1`. – Daniel Hilgarth May 04 '11 at 13:50
  • You can verify it by calling `_list.IndexOf(orderResponse)`. You will see, it will return `_list.Count - 1`. – Daniel Hilgarth May 04 '11 at 13:50
  • 8
    I can confirm that this thoroughly confusing exception is raised on the `Remove` (!) callback, and is fixed by passing the correct index to the `Add` callback. Confusingly, not passing any index at all on `Add` (documented as a [valid thing to do!](http://msdn.microsoft.com/en-us/library/ms653207.aspx)) also leads to this confusing exception message. – Roman Starkov Jan 22 '12 at 23:17
  • 3
    I faced this issue after implementing a "sorted" ObservableCollection class. When you add an element to the list, it will not necessarily be added to the end of the list. However, when raising the collection-change event for the "Add" action, WPF expects that the element is added to the end of the list. The way I managed to get around this was to first add the element to the end of the list and then move it to its correct index. – bgh Dec 13 '18 at 11:33
2

If I were to guess, I'd say that this line...

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

...because it calls FirstOrDefault(), may be returning null. Set a breakpoint and see what's actually going on.

To that end, why even do that query? Since you're passing in the object to be removed, why not simply do this:

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

Even better, since List<T> has its own Remove(T object) method:

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

Sidenotes

There is also a possible race condition in how you raise the CollectionChanged event. In between checking for null and raising it a subscriber could remove its delegate from the event. Here's an easy way to avoid that:

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

Now you can just raise it and never need to check if it is null:

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

This doesn't make it completely thread-safe, but it's an easy way of making sure raising the event won't throw a null reference exception.

Community
  • 1
  • 1
Joel B Fant
  • 24,406
  • 4
  • 66
  • 67
1

I received this exception when I attempted to create a new NotifyCollectionChangedEventArgs with the Remove parameter when passing an item that I used to look up in my internal list and not the actual item that was getting removed.

Once, I changed the item I passed into the NotifyCollectionChangedEventArgs to the actual item I was removing from my internal list the exception

"Added item does not appear at given index.."

went away.

juagicre
  • 1,065
  • 30
  • 42
Jim
  • 13
  • 4
0

I tracked down the issue with Reflector and figured out the cause of this exception might refer to Equals not returning true for actually equal objects in your list; or maybe operator ==.

Javid
  • 2,755
  • 2
  • 33
  • 60