开发者

BackgroundWorker not firing RunWorkerCompleted

开发者 https://www.devze.com 2023-04-10 12:19 出处:网络
The first time I run my backgroundworker it runs correctly - updates a datatable in the background and then RunWorkerCompleted sets the datatable as a datagridview datasource.

The first time I run my backgroundworker it runs correctly - updates a datatable in the background and then RunWorkerCompleted sets the datatable as a datagridview datasource.

If I then run it again, the datagridview clears and doesn't update. I can't work out why.

I've verified that the datatable contains rows when my code hits dgvReadWrites.DataSource.

    private void btnGenerateStats_Click(object sender, EventArgs e)
    {
        dtJobReadWrite.Columns.Clear();
        dtJobReadWrite.Rows.Clear();
        dgvReadWrites.DataSource = dtJobReadWrite;

        List<Tuple<string, string>>jobs = new List<Tuple<string, string>>();

        foreach (ListViewItem job in lstJobs.SelectedItems)
        {
            jobs.Add(new Tuple<string, string>(job.Text, job.SubItems[2].Text));
        }
        BackgroundWorker bgw = new BackgroundWorker();
        bgw.WorkerReportsProgress = true;
        bgw.WorkerSupportsCancellation = true;
        bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
        bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
        pbarGenStats.Style = ProgressBarStyle.Marquee;
        pbarGenStats.MarqueeAnimationSpeed = 30;
        pbarGenStats.Visible = true;
        bgw.RunWorkerAsync(jobs);
    }


    private void bgw_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker bgw = sender as BackgroundWorker;
        List<Tuple<string, string>> jobs = (List<Tuple<string, string>>)e.Argument;
        GetReadWriteStats(jobs);
    }

    private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        BackgroundWorker bgw = sender as BackgroundWorker;
        bgw.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
        bgw.DoWork -= new DoWorkEventHandler(bgw_DoWo开发者_开发问答rk);
        pbarGenStats.MarqueeAnimationSpeed = 0;
        pbarGenStats.Value = 0;
        pbarGenStats.Visible = false;
        dgvReadWrites.DataSource = dtJobReadWrite;
        dgvReadWrites.Visible = true;
        dgvReadWrites.Refresh();
    } 


private void btnGenerateStats_Click(object sender, EventArgs e)
{
    //...
    dgvReadWrites.DataSource = dtJobReadWrite;
    // etc...
}

That's a problem, you are updating dtJobReadWrite in the BGW. That causes the bound grid to get updated by the worker thread. Illegal, controls are not thread-safe and may only be updated from the thread that created them. This is normally checked, producing an InvalidOperationException while debugging but this check doesn't work for bound controls.

What goes wrong next is all over the place, you are lucky that you got a highly repeatable deadlock. The more common misbehavior is occasional painting artifacts and a deadlock only when you are not close. Fix:

    dgvReadWrites.DataSource = null;

and rebinding the grid in the RunWorkerCompleted event handler, like you already do.


Because you unscubscribe from those events

bgw.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
bgw.DoWork -= new DoWorkEventHandler(bgw_DoWork);

Remove those lines


Why are you creating a new BackgroundWorker every time you want to run it? I would like to see what happens with this code if you use one instance of BackgroundWorker (GetReadWriteWorker or something along those lines), subscribe to the events only once, and then run that worker Async on btnGenerateStats_Click.

0

精彩评论

暂无评论...
验证码 换一张
取 消