ListView 控件在通过文本框搜索后多次显示一个值

ListView control showing one value multiple times after search through textbox

我目前正在开发 WinForms 应用程序,其中在表单上有一个用于搜索的文本框和一个 ListView 控件,其中将根据用户的输入从数据库中填充数据。

下面是在文本框控件

上实现TextChanged事件的代码
        private void tbSearchGlassOnShell_TextChanged(object sender, EventArgs e)
        {
            Form1 form = new Form1();
            string cmdString = string.Empty;

            try
            {
                string connString = string.Format("Server={0};Username={1};Database={2};Port={3};Password={4};",
                    form.Tbhostname, form.Tbusername, form.Tbdatabase, form.Tbport, form.Tbpassword);
                MySqlConnection conn = new MySqlConnection(connString);
                conn.Open();
                cmdString = "SELECT shell_glass.shell_glass_id,shell.shell_name,glass.glass_name," +
                    "shell_glass.shell_glass_quantity,shell_glass.shell_glass_ordernumber," +
                    "shell_glass.shell_glass_datetime,shell_glass.user_id FROM shell_glass " +
                    "JOIN shell using (shell_id) JOIN glass using (glass_id)" +
                    "WHERE LOWER(glass.glass_name) LIKE '%" + tbSearchGlassOnShell.Text.ToLower() + "%'";
                MySqlCommand command = new MySqlCommand(cmdString, conn);
                MySqlDataReader reader = command.ExecuteReader();
                while(reader.Read())
                {
                    ListViewItem item = new ListViewItem(reader["shell_glass_id"].ToString());
                    item.SubItems.Add(reader["shell_name"].ToString());
                    item.SubItems.Add(reader["glass_name"].ToString());
                    item.SubItems.Add(reader["shell_glass_quantity"].ToString());
                    item.SubItems.Add(reader["shell_glass_ordernumber"].ToString());
                    item.SubItems.Add(reader["shell_glass_datetime"].ToString());
                    item.SubItems.Add(reader["user_id"].ToString());
                    lvSearchGlassOnShell.Items.Add(item);
                }
                reader.Close();
            }
            catch (MySqlException ex)
            {
                form.TbSetupLog.AppendText("MySqlExepction: " + ex.Message + Environment.NewLine);
            }
            catch (Exception ex)
            {
                form.TbSetupLog.AppendText("Exception: " + ex.Message + Environment.NewLine);
            }
        }

出于某种原因,ListView 控件在用户输入后多次显示相同的值,如下图所示

问题:如何实现用户输入后只有一个值不重复?

TextBox 中键入的每个字符都会调用 TextChanged 事件,因此在您键入第一个字母时执行搜索,然后在您键入第二个字母时执行另一个搜索,依此类推。您永远不会清除 ListView 项目集合,因此每次搜索都会在列表视图中添加另一个条目。

要解决您眼前的问题,只需致电

lvSearchGlassOnShell.Items.Clear();

在进入 reader 循环之前。

但是上面的代码还有其他问题。严重的是 the Sql Injection 成为可能,因为您连接字符串以构建 sql 命令。
相反,您需要以这种方式使用参数

try
{
    lvSearchGlassOnShell.Items.Clear();
    string connString = string.Format("Server={0};Username={1};Database={2};Port={3};Password={4};",
        form.Tbhostname, form.Tbusername, form.Tbdatabase, form.Tbport, form.Tbpassword);
    string cmdString = @"SELECT shell_glass.shell_glass_id, 
                     shell.shell_name,glass.glass_name,
                     shell_glass.shell_glass_quantity, 
                     shell_glass.shell_glass_ordernumber,
                     shell_glass.shell_glass_datetime,
                     shell_glass.user_id 
                 FROM shell_glass 
                 JOIN shell using (shell_id) 
                 JOIN glass using (glass_id)
                 WHERE LOWER(glass.glass_name) LIKE @name";

    using(MySqlConnection conn = new MySqlConnection(connString))
    using(MySqlCommand command = new MySqlCommand(cmdString, conn))
    {
        conn.Open();
        command.Parameters.Add("@name", MySqlDbType.Text).Value = tbSearchGlassOnShell.Text;
        MySqlDataReader reader = command.ExecuteReader();
        ....
   }
}
catch(Exception ex)
   ....

这里我删除了输入文本的连接,并放置了一个参数占位符以避免 SqlInjection 问题。还要注意如何将连接作为一次性对象包含在 using 语句中以正确清理该对象使用的资源