Search code examples
c#.netwinformslistviewlistviewitem

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: Removes 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?


Solution

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