问题
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!
}
回答1:
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.
回答2:
@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();
}
}
来源:https://stackoverflow.com/questions/12044421/c-sharp-background-worker-to-update-status-label