When I read the code inside .NET, more specifically ListBox.cs
and ListView.cs
, they have two different classes for storing their SelectedItems
collections.
ListBox.cs
has a SelectedObjectCollection
, which has the following elements:
private ListBox owner; private bool stateDirty; private int lastVersion; private int count;
ListView.cs
has a SelectedListViewItemCollection
, which only has these members:
private ListView owner; private int lastAccessedIndex = -1;
Therefore, looking at this, I assume that we can conclude that the ListBox
collection is a valid enumerator that tracks any changes and the number of items in the list. ListView
, on the other hand, does not seem to care about this at all and only tracks the current index of the enumerator and just takes a step forward.
So the ListBox
throws an exception, since it tracks changes, the ListView
does not.
ListBox.cs
: ListBox.cs
SelectecObjectCollection
The GetEnumerator method looks like this:
public IEnumerator GetEnumerator() { return InnerArray.GetEnumerator(SelectedObjectMask); }
And ListView.cs
SelectedListViewItemCollection
The GetEnumerator method is as follows:
public IEnumerator GetEnumerator() { if (owner.VirtualMode) { throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode)); } ListViewItem[] items = SelectedItemArray; if (items != null) { return items.GetEnumerator(); } else { return new ListViewItem[0].GetEnumerator(); } }
So, it looks like the ListView
returns an array enumerator, which is constant, and the ListBox
returns the actual enumerator as a filter of its InnerArray elements.
I know that this is not what you asked for; but itβs always useful to add all elements to a temporary list before iterating through it to remove things, since you may never know how enumerated elements are implemented on the backend, and how they may change in the future.