You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TextBox TextChanged结合BackgroundWorker填充DataGridView遇并发错误求助

解决BackgroundWorker并发运行报错及实时搜索优化方案

我在窗体中使用TextBox、BackgroundWorker和DataGridView控件,希望通过TextBox的TextChanged事件触发BackgroundWorker查询匹配数据,实时填充DataGridView。但运行后报错:

ErrorSystem.InvalidOperationExceptoin:This Background worker is currently busy and cannot run multiple tasks concurrently.


错误原因

  1. CancelAsync()仅发送取消请求,不会立即终止正在执行的DoWork线程,此时IsBusy仍为true,直接调用RunWorkerAsync()会触发并发冲突。
  2. DoWork方法中直接访问UI控件txtSearchBox.Text,违反WinForms线程安全规则(后台线程禁止直接操作UI)。
  3. 存在SQL注入风险,且数据库连接未正确释放。

解决方案及修正代码

核心修复点

  • 等待后台线程真正完成取消后再启动新任务
  • 通过参数传递查询文本,避免后台线程访问UI控件
  • 在DoWork中响应取消请求,及时终止操作
  • 使用参数化查询避免SQL注入,用using管理数据库连接

1. TextChanged事件处理

private void txtSearchBox_TextChanged(object sender, EventArgs e)
{
    if (backgroundWorker1.IsBusy)
    {
        backgroundWorker1.CancelAsync();
        // 等待线程真正结束,同时保持UI响应
        while (backgroundWorker1.IsBusy)
        {
            Application.DoEvents();
        }
    }
    // 将搜索文本作为参数传入后台线程
    backgroundWorker1.RunWorkerAsync(txtSearchBox.Text.Trim());
}

2. DoWork事件处理

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    string searchText = e.Argument as string;
    
    // 检查取消请求,及时终止
    if (backgroundWorker1.CancellationPending)
    {
        e.Cancel = true;
        return;
    }

    DataSet ds = new DataSet();
    // 使用using自动释放数据库连接和适配器
    using (MySqlConnection con = new MySqlConnection("你的数据库连接字符串"))
    {
        try
        {
            con.Open();
            // 参数化查询,避免SQL注入
            string sql = "SELECT * FROM Games WHERE Name LIKE @SearchText";
            MySqlDataAdapter da = new MySqlDataAdapter(sql, con);
            da.SelectCommand.Parameters.AddWithValue("@SearchText", $"%{searchText}%");
            
            da.Fill(ds, "GameID");
            
            // 填充后再次检查取消状态
            if (backgroundWorker1.CancellationPending)
            {
                e.Cancel = true;
                return;
            }
            // 将查询结果传递给完成事件
            e.Result = ds.Tables["GameID"];
        }
        catch (Exception ex)
        {
            // 将异常信息传递到完成事件处理
            e.Result = ex;
        }
    }
}

3. RunWorkerCompleted事件处理

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // 任务被取消则直接返回
    if (e.Cancelled)
    {
        return;
    }

    // 处理查询异常
    if (e.Result is Exception ex)
    {
        MessageBox.Show($"查询出错:{ex.Message}");
        return;
    }

    // 更新DataGridView数据源
    DataTable dt = e.Result as DataTable;
    if (dt != null)
    {
        SimilarData.DataSource = dt.DefaultView;
    }
}

额外优化建议

  • 添加输入延迟(如300ms),避免用户每输入一个字符就触发查询,减少数据库请求频率
  • 确保BackgroundWorker的WorkerSupportsCancellation属性设置为true(可在设计器或构造函数中配置)

内容的提问来源于stack exchange,提问作者RayMond

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 15:15:46