ListView添加项报错:无法在多个位置添加/插入同一项
问题描述
向ListView添加项时抛出异常:Cannot add or insert the item '0' in more than one place,预期能正常添加项,实际无法完成添加。
相关代码
Takenshows.cs 类定义
namespace MainLayer { public partial class Takenshows : Form { int c; int f; int d = 0; public List<Show> myShows; private ListViewColumnSorter lvwColumnSorter; Main p;
构造函数
public Takenshows() { InitializeComponent(); lvwColumnSorter = new ListViewColumnSorter(); this.listView1.ListViewItemSorter = lvwColumnSorter; myShows = new List<Show>(); } public Takenshows(IEnumerable<Show> shows) : this() { AddShows(shows); }
添加Show项到ListView的方法
internal void AddShow(Show item) => AddShows(new[] { item }); internal void AddShows(IEnumerable<Show> items) { var lvis = items.Select(x => new ListViewItem(new[] { x.OrdNum.ToString(), x.DTshow.ToString(), x.values.ToString(), x.practiseNumber.ToString() })); listView1.Items.AddRange(lvis.ToArray()); }
清空ListView方法
internal void emptyShows() { listView1.Items.Clear(); }
获取Show项方法
public List<Show> getShows(List<Show> items) { return items; }
异常发生的Takenshows_Load方法
private void Takenshows_Load(object sender, EventArgs e) { // 设置视图模式以显示列 listView1.View = View.Details; listView1.Columns.Add("Order Number", 115, HorizontalAlignment.Left); listView1.Columns.Add("Practise datetime", 140, HorizontalAlignment.Left); listView1.Columns.Add("values", 420, HorizontalAlignment.Left); listView1.Columns.Add("Practise number", 105, HorizontalAlignment.Left); foreach (ListViewItem item in listView1.Items) { int index = listView1.Items.IndexOf(item); item.Tag = index; item.Text = index.ToString(); item.SubItems.Add(listView1.Items[index].SubItems[0].Text); item.SubItems.Add(listView1.Items[index].SubItems[1].Text); item.SubItems.Add(listView1.Items[index].SubItems[2].Text); item.SubItems.Add(listView1.Items[index].SubItems[3].Text); listView1.Items.Add(item); // 此处抛出异常:cannot add the item '0' in more than one place } myShows = listView1.SelectedItems.Cast<ListViewItem>().Select(lvi => (Show)lvi.Tag).ToList(); for (int j = 0; j < listView1.Items.Count; j++) { c = c + 1; listView1.Items[j].SubItems[0].Text = c.ToString(); } f = Int32.Parse(c.ToString()); var frm3 = Application.OpenForms.OfType<Principal>().First(); if (frm3 != null) { frm3.devCont(); frm3.devcontlist(f); frm3.devMed(myShows); } }
ListView选中项变更事件
private void listView1_SelectedIndexChanged(object sender, EventArgs e) { listView1.BeginUpdate(); listView1.EndUpdate(); listView1.Invalidate(); listView1.Update(); }
删除项按钮事件
private void button1_Click(object sender, EventArgs e) { c = 0; if (listView1.SelectedItems != null) { for (int i = 0; i < listView1.Items.Count; i++) { if (listView1.Items[i].Selected) { DialogResult dr = MessageBox.Show("Are you sure you want to remove the selected item?", "WARNING", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); switch (dr) { case DialogResult.Yes: listView1.Items[i].Remove(); i--; for (int j = 0; j < listView1.Items.Count; j++) { c = c + 1; listView1.Items[j].SubItems[0].Text = c.ToString(); } f = Int32.Parse(c.ToString()); myShows = listView1.SelectedItems.Cast<ListViewItem>().Select(lvi => (Show)lvi.Tag).ToList(); var frm2 = Application.OpenForms.OfType<Principal>().First(); if (frm2 != null) { frm2.devCont(); frm2.devcontlist(f); frm2.devMed(myShows); } break; case DialogResult.No: break; } } } } }
ListView列排序事件
private void listView1_ColumnClick(object sender, ColumnClickEventArgs e) { if (e.Column == 0) { if (lvwColumnSorter.SortColumn == 0) { lvwColumnSorter.SortColumn = e.Column; lvwColumnSorter.Order = SortOrder.Ascending; } } this.listView1.Sort(); } } }
Main.cs 添加项按钮事件
private void button2_Click(object sender, EventArgs e) { string values = textBox_F.Text + " " + textBox_PT.Text + " " + textBox_QT.Text + " " + textBox_ST.Text + " " + textBox_FPT.Text; c = c + 1; watchedShow = new Show { OrdNum = c + d, DTShow = DateTime.Now, Values = values, practiseNumber = GetPractiseNumberLN.getInstance().getPractiseNum() }; watchedShows.Add(watchedShow); var frm = Application.OpenForms.OfType<Takenshows>().FirstOrDefault(); if (frm == null) { frm = new Takenshows(watchedShows); frm.Show(); } else { frm.AddShow(watchedShow); frm.Activate(); } }
异常出现在Takenshows_Load方法的listView1.Items.Add(item);行,尝试过将foreach替换为for循环,问题依旧。请问如何解决该异常,实现正常添加ListView项?
解决方案
问题根源
Takenshows_Load里的foreach循环犯了两个核心错误:
- 重复添加已有项:你遍历的是
listView1.Items里的现有项,然后直接调用Add(item)试图把同一个ListViewItem实例再次加入列表。而一个ListViewItem实例只能属于一个ListView,这直接触发了异常。 - 错误的子项操作:循环里给已有项重复添加子项,但这些子项在
AddShows创建ListViewItem时就已经初始化完成了,这种操作不仅多余,还会导致子项重复,逻辑完全混乱。
另外,myShows的赋值逻辑也错了:你试图从选中项转换Tag,但此时根本没有选中项,而且Tag被错误赋值为索引,而非Show对象。
修改步骤
1. 删除错误的foreach循环
直接删掉Takenshows_Load里的整个foreach循环块,因为AddShows已经正确把ListViewItem添加到了ListView中,不需要重复处理。
2. 修正AddShows方法,绑定Show对象到Tag
在创建ListViewItem时,把对应的Show对象绑定到Tag,方便后续获取:
internal void AddShows(IEnumerable<Show> items) { var lvis = items.Select(x => { var lvi = new ListViewItem(new[] { x.OrdNum.ToString(), x.DTshow.ToString(), x.values.ToString(), x.practiseNumber.ToString() }); lvi.Tag = x; // 将Show对象绑定到Tag属性 return lvi; }); listView1.Items.AddRange(lvis.ToArray()); }
3. 修正Takenshows_Load中的myShows赋值
改为从所有项的Tag中获取Show对象:
// 替换原来的myShows赋值行 myShows = listView1.Items.Cast<ListViewItem>().Select(lvi => (Show)lvi.Tag).ToList();
4. 修正序号更新的初始值
确保序号从1开始,初始化c为0:
c = 0; // 初始化c为0 for (int j = 0; j < listView1.Items.Count; j++) { c = c + 1; listView1.Items[j].SubItems[0].Text = c.ToString(); }
5. 修正删除按钮中的myShows更新
删除后应该获取所有项的Show对象,而非仅选中项:
// 替换原来的myShows赋值行 myShows = listView1.Items.Cast<ListViewItem>().Select(lvi => (Show)lvi.Tag).ToList();
修改后的Takenshows_Load方法
private void Takenshows_Load(object sender, EventArgs e) { // 设置视图模式 listView1.View = View.Details; // 添加列 listView1.Columns.Add("Order Number", 115, HorizontalAlignment.Left); listView1.Columns.Add("Practise datetime", 140, HorizontalAlignment.Left); listView1.Columns.Add("values", 420, HorizontalAlignment.Left); listView1.Columns.Add("Practise number", 105, HorizontalAlignment.Left); // 获取所有Show对象 myShows = listView1.Items.Cast<ListViewItem>().Select(lvi => (Show)lvi.Tag).ToList(); // 更新序号 c = 0; for (int j = 0; j < listView1.Items.Count; j++) { c = c + 1; listView1.Items[j].SubItems[0].Text = c.ToString(); } f = c; // 直接使用c的值,无需转字符串再解析 var frm3 = Application.OpenForms.OfType<Principal>().FirstOrDefault(); if (frm3 != null) { frm3.devCont(); frm3.devcontlist(f); frm3.devMed(myShows); } }
额外优化建议
getShows方法只是返回传入的参数,完全没有作用,可以直接删除。listView1_SelectedIndexChanged事件里的BeginUpdate和EndUpdate没有实际操作列表内容,可简化或删除。- 把序号更新逻辑封装成单独方法,避免加载和删除时重复写相同代码。
内容的提问来源于stack exchange,提问作者Francisco J A
相关产品推荐
相关产品推荐

