Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# background worker to update status label

This should be a fairly simple thing; however, I've been unable to figure this out.

/// This section is located in the InitializeComponent() method
/// form's class, i.e. partial class frmMain { .... }
this.bgw = new System.ComponentModel.BackgroundWorker();
this.bgw.WorkerReportsProgress = true;
this.bgw.DoWork += new System.ComponentModel.DoWorkEventHandler(this.bgw_DoWork);
this.bgw.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.bgw_ProgressChanged);

/// This code is located in public partial class frmMain : Form { .... }
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i = 1; i <= 100; i++)
    {
        Thread.Sleep(100); // Wait 100 milliseconds
        //Console.WriteLine(i);
        bgw.ReportProgress(i);
    }
}
private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // Update status label
    lblStatus.Text = e.ProgressPercentage.ToString();
}
// New code added to question after edit
public frmMain()
{
    InitializeComponent();
    bgw.RunWorkerAsync();
    // some more stuff...
}

The background worker is running correctly; however, it is not correctly updating its progress. If I uncomment the commented line in the DoWork event, I able able to see the status updated correctly; however, the ProgressChanged event does not get triggered until after the task (heavy database computational stuff) in the main thread is finished.

This is using .NET Framework 4 and is a Windows Forms Application.

Edit

See the comments in the above code for where the code is located.

Some more details

The code that is being executed involves executing multiple queries on a database. I am not at liberty to disclose that code. As far as how that code is being executed, I actually do not know, as I was handed a .dll by another developer and was told to only use that when accessing the database....

Edit

The code in the "some more stuff" section was moved to be as follows

private void frmMain_Load(object sender, EventArgs e)
{
   // some more stuff... aka run queries!
}
like image 743
James Mnatzaganian Avatar asked Aug 20 '12 20:08

James Mnatzaganian


2 Answers

Your BackgroundWorker code is just fine. The problem is that you have code elsewhere (in this case, in your constructor or FormLoad) that is blocking the UI thread (by performing a synchronous database request). You need to do something to ensure that this code is run in a non-UI thread. This could mean using this existing BackgroundWorker to perform those other long running tasks; it could also be done by using Task.Factory.StartNew or some other threading mechanism to have it run in a non-UI thread.

Once the UI thread is not being blocked you will see the updates made in your `ProgressChanged event handler reflected in the UI.

like image 99
Servy Avatar answered Oct 19 '22 06:10

Servy


@Servy is of course correct.

I just wanted to chime in with this code that reproduces the problem:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        bgw.RunWorkerAsync();

        Task.Factory.StartNew(SomeMoreStuff);
    }

    private void SomeMoreStuff()
    {
        for (int i = 0; i < 5; i++)
        {
            Thread.Sleep(50);
            this.Invoke((Action)HogTheUIThread);
        }
    }

    private void HogTheUIThread()
    {
        Thread.Sleep(1000);
    }

    private void bgw_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 1; i <= 100; i++)
        {
            Thread.Sleep(100); // Wait 100 milliseconds
            //Console.WriteLine(i);
            bgw.ReportProgress(i);
        }
    }

    private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        // Update status label
        lblStatus.Text = e.ProgressPercentage.ToString();
    }
}
like image 2
Christoffer Lette Avatar answered Oct 19 '22 06:10

Christoffer Lette