views:

206

answers:

1

I've seen code like the following in the Silverlight toolkit and can't understand how it is safe to do:

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

If you remove an item from say index 5 doesn't that change the current index of every item in the _items collection after index 5 to be one less than before? So then how is it safe to continually remove items using their "old" indexes like this code does?

I'd really like to understand why this works.

Any ideas?

+4  A: 

This code looks like it is removing a contiguous set of items from a particular starting index. If you read the remove call carefully:

_items.RemoveAt( e.OldStartingIndex );

you will notice that it is iteratively removing items from a constant index. This means it is collapsing the list by removing items in a contiguous range. This may very well be correct - assuming that is the intent of the code.

The loop executes as many times as e.OldItems.Count indicates. So (presumably) it is told how many items to remove starting from a given index.

As a general practice, you have to be careful about how you remove items from collections for a couple reasons:

  1. Item indexes do indeed change as you remove items. So care must be taken to avoid errors resulting from item index positions shifting.
  2. Mutating a list while iterating over it (as in a foreach loop or with an explicit IEnumerator) results in exceptions. You cannot mutate a list (either add or delete) while iterating - it invalidates the iterator.
LBushkin
The only way it would make sense to me is if it were guaranteed that e.OldItems was ordered by descending index. But I see no mention of that in any MSDN documentation so it makes me nervous.
Without knowing the intent and preconditions that above code expects, you can't really say whether it's correct or not. However, it does look like it "could be" correct, if the intent was to delete a range of contiguous, ascending items in a list.
LBushkin
Well assume we are talking about ObservableCollection<t> which is part of .Net. It implements the INotifyCollectionChanged interface. I guess what I'm asking is, does it guarantee that NotifyCollectionChangedEventArgs will give you indexes in the correct order to allow the above code to always work?Also wouldn't you have to delete the items in descending order in order to not be effected by the index shift?
@unknown: I can't see much point to the existance of the OldStartingIndex property in the event args if code handling the event could not rely on the contigous nature of the affected items. I agree that it would be better that this were stated explicitly for anyone intending to create some other implementation of INotifyCollectionChanged.
AnthonyWJones