【问题标题】:C# Win Form - Main thread not responding when using background workerC# Win Form - 使用后台工作者时主线程没有响应
【发布时间】:2017-05-14 06:38:44
【问题描述】:

我有一个 datagridview,它通过 DataSource 由 DataTable 填充,我正在使用 backgroundworker 格式化单元格(背景颜色和单元格的前景色)在 datagridview 中。

BackgroundWorker bw = new BackgroundWorker();
private void Frm_Find_Load(object sender, EventArgs e)
{
    bw.WorkerSupportsCancellation = true;
    bw.DoWork += new DoWorkEventHandler(bw_DoWork);
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    CheckForValidValues();
}

public bool CheckForValidValues()
{
    dgv.Invoke((MethodInvoker)delegate()
    {
        for (int i = 0; i < Dt.Rows.Count; i++)
        {
            if (Dt.Rows[0]["Name"].ToString() == Value)
            {
                  dgv.Rows[i].Cells["Name"].Style.BackColor = Color.FromArgb(255, 192, 192);
            }
            else
            {
                   dgv.Rows[i].Cells["Name"].Style.BackColor = Color.White;
            }
            progressBar1.Invoke((MethodInvoker)(() => progressBar1.Value++));
        }
    });

    this.Invoke((MethodInvoker)delegate()
    {
        BtnShow.Enabled = true;
        dgv.Enabled = true;
    });
}

private void btnSave_Click(object sender, EventArgs e)
{
    if (bw.IsBusy == false)
    {
          progressBar1.Visible = true;
          progressBar1.Value = 0;

          BtnShow.Enabled = false;
          dgv.Enabled = false;

          progressBar1.Maximum = dgv.Rows.Count;

          bw.RunWorkerAsync();
    }
}

当整个过程停止时,DataGridView 仍然是Enabled=false,因此用户无法更改 datagridview 中的任何值。

datagridview 中通常有 15,000 行并且要格式化的行很多,这需要时间,这就是为什么我使用 backgroundworker 并且它工作非常好但是当用户尝试按下启用 false datagridview 几次,主线程变得无响应并且进度条冻结。

谁能指导我如何处理它?

【问题讨论】:

  • 你为什么使用 C# 3.0?升级使用async/await
  • @AluanHaddad 我知道我使用的是 Visual Studio (2008) 的过时版本,但由于某种原因我必须坚持使用它,你能告诉我一个解决方法吗

标签: multithreading winforms datagridview c#-3.0 backgroundworker


【解决方案1】:

您正在使用Invoke 运行整个代码。这意味着您正在切换到 UI 线程并且代码正在 UI 线程中运行。由于代码是一个耗时的 for 循环,因此它阻塞了 UI 线程。

不要使用BackgroundWorker来格式化单元格,最好使用CellFormatting事件:

private void dgv_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    //If this is header cell or new row, do nothing
    if (e.RowIndex < 0 || e.ColumnIndex < 0 || e.RowIndex == dgv.NewRowIndex)
        return;

    //If formatting your desired column, perform validation
    if (e.ColumnIndex == dgv.Columns["Name"].Index)
    {
        // Perform validation and change cell back color here.
    }
}

【讨论】:

  • 能否请您为其添加一个代码 sn-p,因为我不知道在这种情况下如何使用它
  • 抱歉,但我无法理解“CellFormatting”将如何被调用,以及它在 UI 线程中如何无法像后台工作人员那样工作。
  • 我没有说 CellFormatting 将在不同的线程上运行。我刚刚告诉你为什么 UI 在你的方法中被阻止。我还向您展示了一种更好的格式化单元格的方法。测试一下,你就会发现不同。
  • 对不起,我现在还没有使用过这个事件,但是它是如何工作的,因为我正在设置一个不会触发 CellFormatting 事件的数据源
  • 事件属于DataGridView。像处理任何其他事件一样处理它。我已经发布了该活动的 MSDN 页面链接。
【解决方案2】:

也许尝试在按钮被点击时禁用它直到工作完成?

假设您的按钮名称是 Button1,

当用户点击启用假数据网格视图时,使用 Button.enabled=false,然后当工作完成时使用 Button.enabled=true

希望有帮助!

【讨论】:

  • 按钮在被点击的那一刻被启用=false,直到整个工作完成(抱歉忘记在上面的代码中添加它)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-05
  • 1970-01-01
  • 2017-12-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多