Why does SubItems.Clear() also delete the Name attribute?
I am using a WinForms ListView in details mode (.NET 4.0, running on Windows 7) and I have a function that needs to clear the subitems in a particular item. Unfortunately when I do that it also clear's the name:
item.Name = "TESTNAME";
item.SubItems.Clear();
MessageBox.Show(item.Name); //shows nothing
In the debugger I've tracked it down to this, and I've looked at the documentation on MSDN and it's unhelpful,
Clear: Remov开发者_如何学JAVAes all subitems and the parent ListViewItem from the collection.
Except the ListViewItem is still very there because later in the function I'm able to add SubItems to it again!
Surely I don't have to:
while(item.SubItems.Count > 0)
{
item.RemoveAt(0);
}
Do I?
Unfortunately ListView
is a strange beast, and one of the strange corners of it is that its items are just a collection of values to be shown, one for each column.
The Name
property just automates putting something into the first column, and unfortunately this "something" lives in the SubItems
collection.
This means that if you inspect the SubItems
collection, you'll notice that it has one element already, and after setting the name of the item, you'll see the text of that item is equal to that name.
This is the code for the ListViewItem.Name
property:
public string Name {
get {
if (SubItemCount == 0) {
return string.Empty;
}
else {
return subItems[0].Name;
}
}
set {
SubItems[0].Name = value;
}
}
And the ListViewSubItem.Name
property looks like this:
public string Name {
get {
return (name == null) ? "": name;
}
set {
name = value;
if (owner != null) {
owner.UpdateSubItems(-1);
}
}
}
So, clearing the SubItems
collection has the consequence of clearing the properties of that first item, as you've discovered, in addition to removing every other item from the collection.
Actually, what happens is that the collection is cleared, but any attempt to look at the SubItems
collection while it is empty will create a new collection with one item, with default property values. In the above example code, reading the SubItems
collection will automagically assign a collection with one item to the internal field, if the collection isn't already there.
So yes, this is how it "works".
In fact, to remove every subitem except the first, your loop would have to be:
while (item.SubItems.Count > 1)
item.SubItems.RemoveAt(1);
From MSDN:
Note
The first subitem in the ListViewItem.ListViewSubItemCollection is always the item that owns the subitems. When performing operations on subitems in the collection, be sure to reference index position 1 instead of 0 to make changes to the first subitem.
Thus, clearing the sub items collection, clears the values for the parent as well.
Please note 1:
The ListViewItem.Text
(not the Name
) is the ListViewItem.SubItems[0]
, but:
the ListViewItem.SubItems.Clear()
clears also the ListViewItem.Name
!
So, if you use SubItems.Clear
, you then have to restore both Name
and Text
(if you need them).
Please note 2:
If you use *Key
methods (eg. ListView.Items.ContainsKey()
or ListView.Items.RemoveByKey()
) to access the items (instead of *Index
ones), take care of the ListViewItem.Name
, which is the key
you need to pass to these methods...
What a smart logic...
For the case anyone is forced or wants to use ListView
I have discovered another problem described in question 23007388.
As it might take very long time to determine all this stuff, I have posted this answer even this thread is a little bit old.
精彩评论