调用ListView.Items.Clear()丢失分组关联的问题咨询
问题成因
ListViewItem属于引用类型,你在过滤逻辑中直接将masterChannelList中存储的项实例添加到了channellistView.Items集合中,此时masterChannelList里的项和channellistView里的项指向同一个内存对象。- 当调用
channellistView.Items.Clear()时,WinForm的ListView控件会自动清空所有被移除项的Group属性,解除项和当前控件分组的绑定,这个操作会直接修改你存在masterChannelList里的同实例对象的属性,导致下次取数据时Group已经是null值。 - 初始化阶段你给
masterChannelList存储克隆项的逻辑是正常的,但第一次过滤开始后你直接把master里的实例绑定到控件上,就会触发这个问题。
解决方法
方案1:每次过滤添加项时克隆实例,不修改master原始数据
过滤时不要直接添加master里的原始项,每次添加前先克隆一份再指定分组,这样控件的Clear操作只会影响克隆出来的临时项,不会改动master里的原始数据:
channellistView.BeginUpdate(); channellistView.Items.Clear(); string filterText = searchmetroTextBox.Text.ToLower().Trim(); foreach (ListViewItem sourceItem in masterChannelList.Where(lvi => lvi.Text.ToLower().StartsWith(filterText))) { // 克隆master中的原始项,不会修改原始实例属性 ListViewItem newItem = sourceItem.Clone() as ListViewItem; // 手动绑定分组,通过原始项的分组名查找控件中的对应分组即可 newItem.Group = channellistView.Groups[sourceItem.Group.Name]; channellistView.Items.Add(newItem); } channellistView.EndUpdate();
方案2:改用隐藏不匹配项的方式实现过滤
不需要清空Items集合,仅遍历所有项设置Visible属性即可,不会触发分组清空的逻辑,性能也更优:
channellistView.BeginUpdate(); string filterText = searchmetroTextBox.Text.ToLower().Trim(); foreach (ListViewItem item in channellistView.Items) { item.Visible = item.Text.ToLower().StartsWith(filterText); } channellistView.EndUpdate();
如果你的场景不需要动态增删全量列表项,只是做过滤展示,更推荐这个方案。
方案3:每次Clear后重新给master项赋值Group
如果不想修改过滤的添加逻辑,也可以在清空控件项之后,先遍历master列表重新绑定分组关联:
channellistView.BeginUpdate(); channellistView.Items.Clear(); // 先恢复所有master项的分组关联 foreach (ListViewItem item in masterChannelList) { item.Group = channellistView.Groups[item.Group.Name]; } string filterText = searchmetroTextBox.Text.ToLower().Trim(); foreach (ListViewItem item in masterChannelList.Where(lvi => lvi.Text.ToLower().StartsWith(filterText))) { channellistView.Items.Add(item); } channellistView.EndUpdate();
内容的提问来源于stack exchange,提问作者rrirower
相关产品推荐
相关产品推荐

