Windows Forms ListView使用FindItemWithText查找数值时匹配异常问题
解决ListView的FindItemWithText误判重复ID问题
问题场景
有一个名为lst_Employees的ListView,搭配两个联动ComboBox:cmb_EmployeeID和cmb_EmployeeName。选择员工姓名后,ID会同步显示,点击按钮可将员工信息添加到ListView中。使用FindItemWithText判断员工是否已存在时出现误判:先添加ID为14的员工,再添加ID为1的员工会被提示重复;同理先加20-29的ID,再加2也会误判——原因是FindItemWithText仅做前缀匹配,不校验完整内容。
原问题代码
private void btn_EmployeeAdd_Click(object sender, EventArgs e) { if (cmb_EmployeeName.SelectedIndex > 0) { ListViewItem foundItem = null; if (lst_Employees.Items.Count > 0) { foundItem = lst_Employees.FindItemWithText(cmb_EmployeeID.Text, false, 0); if (foundItem != null) { MessageBox.Show("Employee has already in the list", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } if (foundItem == null) { string name = cmb_EmployeeName.Text.Substring(0, cmb_EmployeeName.Text.IndexOf(" - [")); ListViewItem lvi = new ListViewItem(); lvi.Text = cmb_EmployeeID.Text; lvi.SubItems.Add(name); lst_Employees.Items.Add(lvi); cmb_EmployeeName.SelectedIndex = 0; } } else { MessageBox.Show("Please select an employee."); } }
解决方案
方法1:遍历ListViewItems做精确字符串匹配
直接遍历列表项,对比每个项的ID文本与目标ID完全一致,避免前缀匹配问题:
private void btn_EmployeeAdd_Click(object sender, EventArgs e) { if (cmb_EmployeeName.SelectedIndex > 0) { bool isExists = false; string targetId = cmb_EmployeeID.Text; // 精确匹配每个项的ID文本 foreach (ListViewItem item in lst_Employees.Items) { if (item.Text.Equals(targetId, StringComparison.Ordinal)) { isExists = true; break; } } if (isExists) { MessageBox.Show("Employee has already in the list", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } // 添加新员工逻辑 string name = cmb_EmployeeName.Text.Substring(0, cmb_EmployeeName.Text.IndexOf(" - [")); ListViewItem lvi = new ListViewItem(); lvi.Text = targetId; lvi.SubItems.Add(name); lst_Employees.Items.Add(lvi); cmb_EmployeeName.SelectedIndex = 0; } else { MessageBox.Show("Please select an employee."); } }
方法2:用LINQ简化精确匹配判断
如果项目支持LINQ,可以用更简洁的代码实现:
private void btn_EmployeeAdd_Click(object sender, EventArgs e) { if (cmb_EmployeeName.SelectedIndex > 0) { string targetId = cmb_EmployeeID.Text; bool isExists = lst_Employees.Items.Cast<ListViewItem>().Any(item => item.Text == targetId); if (isExists) { MessageBox.Show("Employee has already in the list", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } // 添加新员工逻辑 string name = cmb_EmployeeName.Text.Substring(0, cmb_EmployeeName.Text.IndexOf(" - [")); ListViewItem lvi = new ListViewItem(); lvi.Text = targetId; lvi.SubItems.Add(name); lst_Employees.Items.Add(lvi); cmb_EmployeeName.SelectedIndex = 0; } else { MessageBox.Show("Please select an employee."); } }
方法3:转换为数值类型匹配(推荐)
如果ID是数值类型(如int),将字符串转换为数值后对比,彻底避免字符串格式带来的匹配问题:
private void btn_EmployeeAdd_Click(object sender, EventArgs e) { if (cmb_EmployeeName.SelectedIndex > 0) { // 先校验ID格式 if (!int.TryParse(cmb_EmployeeID.Text, out int targetId)) { MessageBox.Show("Invalid Employee ID format.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // 数值精确匹配 bool isExists = lst_Employees.Items.Cast<ListViewItem>().Any(item => int.TryParse(item.Text, out int existingId) && existingId == targetId); if (isExists) { MessageBox.Show("Employee has already in the list", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } // 添加新员工逻辑 string name = cmb_EmployeeName.Text.Substring(0, cmb_EmployeeName.Text.IndexOf(" - [")); ListViewItem lvi = new ListViewItem(); lvi.Text = targetId.ToString(); lvi.SubItems.Add(name); lst_Employees.Items.Add(lvi); cmb_EmployeeName.SelectedIndex = 0; } else { MessageBox.Show("Please select an employee."); } }
说明
FindItemWithText的默认逻辑是前缀匹配,只要项文本以目标字符串开头就会被命中,这是误判的核心原因。上述三种方法都通过精确匹配解决了问题,其中数值类型匹配的方式最可靠,能同时处理ID带前导零等特殊字符串格式的情况。
内容的提问来源于stack exchange,提问作者Cooper
相关产品推荐
相关产品推荐

