ijb109
ijb109

Reputation: 972

Backgroundworker is always busy

I'm new to using event handlers and backgroundworkers, so I may be missing something completely obvious here. Still, I've been trying to fix this for two days, so I thought I might as well see what anyone had to say.

I have a backgroundworker called SqlExpressDownloader. It starts running at the beginning of my program, the rest of the work runs, and then it should wait for the operations in the SqlExpressDownloader_DoWork() method to complete before continuing. The only problem is that for some reason whenever I do while(SqlExpressDownloader.IsBusy), it always responds as busy and therefore will wait forever.

The code for the event handler is here:

    private void SqlExpressDownloader_DoWork(object sender, DoWorkEventArgs e)
    {
        string sSource = string.Format("{0}\\{1}", Paths.Settings_Common, "sqlexpr_x64_enu.exe");
        Debug.WriteLine(sSource);
        Debug.WriteLine("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe");
        if (!System.IO.File.Exists(sSource))
        {
            WebClient oWebClient = new WebClient();
            oWebClient.DownloadProgressChanged += DownloadProgressChanged;
            oWebClient.DownloadDataCompleted += DownloadComplete;

            oWebClient.DownloadFileAsync(new System.Uri("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe"), sSource);

            while (oWebClient.IsBusy)
            {
                Thread.Sleep(100);
            }

            e.Result = "";
            DownloadFinished = true;
        }
    }

I have watched the code and have watched it complete this method. I even added a return after the DownloadFinished = true, but it still responds as busy. What I want to know is how to make the backgroundworker respond as not busy.

EDIT The events are all added in the constructor as shown here:

        SqlExpressDownloader = new BackgroundWorker();
        SqlExpressDownloader.DoWork += new DoWorkEventHandler(this.SqlExpressDownloader_DoWork);
        SqlExpressDownloader.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.SqlExpressDownloader_RunWorkerCompleted);

The RunWorkerCompleteEventHandler looks like this:

    private void SqlExpressDownloader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            Debug.WriteLine("The actions are complete.");
        }
        else
        {
            Debug.WriteLine("Error in completed work.");
        }
    }

But, when I debugged it last, it didn't actually trigger.

Upvotes: 5

Views: 2472

Answers (3)

Kickass
Kickass

Reputation: 1134

I had a similar issue. DownloadASync would fire but .IsBusy would always stay on true.

This probably won't be a common problem, just thought I share my resolution.

I used

MessageBox.Show(new Form() { TopMost = true }, "", "")

This was the cause. I also tried:

var t = new Form() { TopMost = true };
MessageBox.Show(t, "", "");
t.Dispose();

This caused the same issue.

My code had multiple threads, I assume one of them must have gotten stuck, or perhaps the MessageBox(the new Form() { TopMost = true; } ) call created a stuck thread.

As soon as I removed that part, eg.

MessageBox.Show("", "");

Everything worked as expected again.

So maybe you are creating another thread somewhere that is causing your issue.

Upvotes: 1

Grant Winney
Grant Winney

Reputation: 66439

Instead of querying SqlExpressDownloader.IsBusy in a loop, try subscribing to the RunWorkerCompleted event of the BackgroundWorker and place your code in there that should only occur after the DoWork event has completed.

You'll also have access to the RunWorkerCompletedEventArgs, which you can check to make sure no error was thrown from the DoWork portion of your BackgroundWorker.

    ...
    ...
    SqlExpressDownloader.RunWorkerCompleted += SqlExpressDownloader_RunWorkerCompleted;
    SqlExpressDownloader.RunWorkerAsync();
}

private void SqlExpressDownloader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error != null)
    {
        // do something in response to the error
    }

    // stuff to do after DoWork has completed
}

I found Joe Albahari's tutorial helpful when I was learning how to use these.

Upvotes: 3

Alex S
Alex S

Reputation: 1221

You can replace your code with more elegant async/await solution like this

private async Task SqlExpressDownloadAsync()
{
    string sSource = string.Format("{0}\\{1}", Paths.Settings_Common, "sqlexpr_x64_enu.exe");
    Debug.WriteLine(sSource);
    Debug.WriteLine("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe");
    if (!System.IO.File.Exists(sSource))
    {
        WebClient oWebClient = new WebClient();
        oWebClient.DownloadProgressChanged += DownloadProgressChanged;
        oWebClient.DownloadDataCompleted += DownloadComplete;
        await oWebClient.DownloadFileTaskAsync(new System.Uri("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe"), sSource);  
    }   
}

Upvotes: 1

Related Questions