Search code examples
multithreadingwinformsdatagridviewc#-3.0backgroundworker

C# Win Form - Main thread not responding when using background worker


I have a datagridview which is being populated by a DataTable through DataSource and i am using a backgroundworker for formatting of cells (back color and forecolor of cells) in 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();
    }
}

while the whole process goes down the DataGridView remains Enabled=false so that user cant change any values in datagridview.

There is usually 15,000 rows in the datagridview and that many rows to format, this takes time that is why I use a backgroundworker for it and it works perfectly fine BUT when the user tries to press the enabled false datagridview couple of times, the main thread becomes unresponsive and the progressbar freezes.

Can anyone guide me how to deal with it?


Solution

  • You are running the whole code using Invoke. It means you are switching to UI thread and the code is running in UI thread. Since the code is a time-consuming for loop, then it's blocking UI thread.

    Instead of using a BackgroundWorker, to format cells, it's better to use CellFormatting event:

    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.
        }
    }