Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

foreach-ing through a listview and accessing subitems?

Tags:

I'm having difficulty using a foreach statement with a WinForm ListView control. The following two code blocks demonstrates what I'm trying to do. It works with a for loop, but not a foreach.

foreach(var item in listView.Items){
    item. <-Can't access any of the subitems of this item
}

vs

for(int i=0;i<listView.Items.Count;i++){
    listView.Items[i].Subitems[1] <- Here I can access the sub items
}

I'm trying to use a foreach loop so I can more easily remove items from the ListView.

like image 416
sooprise Avatar asked Apr 05 '11 14:04

sooprise


3 Answers

You need to specify the type:

foreach(ListViewItem item in listView.Items){

To answer your comments:

This is because most controls' item collections implement the non-generic ICollection (and IEnumerable), see this MSDN entry for ListViewItemCollection for example. Since it doesn't implement the generic ICollection<T> or IEnumerable<T>, the compiler can't guess the type of the items from looking at the collections themselves, so you have to tell it that they're of type ListViewItem instead of using var.

like image 161
BoltClock Avatar answered Nov 05 '22 08:11

BoltClock


You need to specify the type if the item in the collection explicitly. The var keyword uses type inference in order to determine the type of the variable. In the case of var in a foreach clause, it uses the particular implementation of IEnumerable to determine the type.

  • If the collection only implements IEnumerable (and not a generic IEnumerable<T>), then var will be object
  • If the collection implements one generic IEnumerable<T> (say, IEnumerable<int>), then var will be T (in the example here, var would be int)

In your case, ListViewItemCollection does not implement any generic form of IEnumerable<T>, so var is assumed to be object. However, the compiler will allow you to specify a more specific type for the iterator variable if the enumerable only implements IEnumerable, and it automatically inserts a cast to that particular type.

Note that, because there's a casting operator, the cast will fail at runtime if the object is not of that particular type. For instance, I can do this:

List<object> foo = new List<object>();

foo.Add("bar");
foo.Add(1);

foreach(string bar in foo)
{

}

This is legal, but will fail when the iterator reaches the second item, since it is not a string.

like image 44
Adam Robinson Avatar answered Nov 05 '22 08:11

Adam Robinson


You need to have the type of the item - in this case: ListViewItem.

Also, if you're planning to remove items from the collection and are using a foreach loop, you cannot directly remove from the you're looping through - you'd need to add each item to remove to a new collection and remove all items in that collection from the original after the termination of the loop.

like image 35
T.K. Avatar answered Nov 05 '22 09:11

T.K.