为什么SubItems.Clear()也删除Name属性?
我在详细模式(.NET 4.0,在Windows 7上运行)中使用WinForms ListView,我有一个需要清除特定项目中的子项的函数。 不幸的是,当我这样做时,它也清楚了这个名字:
item.Name = "TESTNAME"; item.SubItems.Clear(); MessageBox.Show(item.Name); //shows nothing
在调试器中我跟踪了它,我查看了MSDN上的文档并且它没有用,
清除:从集合中删除所有子项和父ListViewItem。
除了ListViewItem仍然非常存在,因为稍后在函数中我能够再次添加SubItems!
当然,我不必:
while(item.SubItems.Count > 0) { item.RemoveAt(0); }
我呢?
不幸的是, ListView
是一个奇怪的野兽,其中一个奇怪的角落是它的项目只是要显示的值的集合,每列一个。
Name
属性只是自动将某些东西放入第一列,不幸的是这个“东西”存在于SubItems
集合中。
这意味着如果检查SubItems
集合,您会注意到它已经有一个元素,并且在设置了项目的名称后,您将看到该项目的文本等于该名称。
这是ListViewItem.Name
属性的代码:
public string Name { get { if (SubItemCount == 0) { return string.Empty; } else { return subItems[0].Name; } } set { SubItems[0].Name = value; } }
ListViewSubItem.Name
属性如下所示:
public string Name { get { return (name == null) ? "": name; } set { name = value; if (owner != null) { owner.UpdateSubItems(-1); } } }
因此,除了从集合中删除所有其他项目之外,清除SubItems
集合的结果是清除第一个项目的属性,如您所发现的那样。
实际上,会发生的情况是清除了集合,但是在SubItems
集合为空时查看SubItems
集合的任何尝试都会创建一个带有一个项目的新集合,其默认属性值。 在上面的示例代码中,如果集合尚未存在,则读取SubItems
集合将自动将具有一个项目的集合分配给内部字段。
所以是的,这就是它的“工作原理”。
事实上,要删除除第一个以外的每个子项,您的循环必须是:
while (item.SubItems.Count > 1) item.SubItems.RemoveAt(1);
来自MSDN :
注意
ListViewItem.ListViewSubItemCollection中的第一个子项始终是拥有子项的项。 对集合中的子项执行操作时,请务必引用索引位置1而不是0来更改第一个子项。
因此,清除子项集合也会清除父项的值。
请注意1:
ListViewItem.Text
(不是Name
)是ListViewItem.SubItems[0]
, 但是:
ListViewItem.SubItems.Clear()
也清除了ListViewItem.Name
!
因此,如果使用SubItems.Clear
,则必须同时还原Name
和Text
(如果需要)。
请注意2:
如果你使用*Key
方法(例如ListView.Items.ContainsKey()
或ListView.Items.RemoveByKey()
)来访问项目(而不是*Index
的),请注意ListViewItem.Name
,这是你的key
需要传递给这些方法……
多么聪明的逻辑……
对于任何人被迫或想要使用ListView
我发现了问题23007388中描述的另一个问题。
由于确定所有这些内容可能需要很长时间,所以我发布了这个答案,即使这个post有点旧。