首先,这是我的代码布局:
public partial class GUI : Form
{
public GUI()
{
InitializeComponent();
}
private void GoButton_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BigMethod bigMeth = new BigMethod();
bigMeth.begin();
}
public void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
progressBar.Refresh();
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Done");
}
}
public class BigMethod()
// If it matters, BigMethod() is in a separate .cs file in the same namespace
{
public void begin()
{
for (; time <= 3600; time += T_STEP) // Running for 1 hour
{
//**********************************************
// DO FOR EACH TIMESTEP
//**********************************************
// Stuff
//**********************************************
// Report back
//**********************************************
gui.backgroundWorker1.ReportProgress((int)(time / RUNTIME * 100));
//gui.progressBar.Value = (int)(time / RUNTIME * 100);
Thread.Sleep(100);
timeCounter += T_STEP;
} // End Loop
}
}
所以我在一个单独的类中有一个名为BigMethod()的方法,它包含一个非常大的数学密集型循环,大约需要15秒才能完成。现在我有一个异步运行包含巨型BigMethod()的BackgroundWorker的按钮。据我所知,这种方法非常有效,该方法完全符合预期,不会“崩溃”GUI。
问题是,progressBar没有刷新。 (每次BigMethod()内部的循环完成时,它会重新计算进度并报告回backgroundWorker)。属性progressBar.Value正在更新,Debug.WriteLine(progressBar.Value)显示它应该是什么,0-100平滑增加,但实际progressBar不移动也不会在完成时跳转到100。
如果我剪切BigMethod并将其放在_DoWork中,一切正常,但这不是一个选项,因为它会严重破坏代码布局。
我该怎么做才能解决这个问题?我已经尝试过progressBar.Refresh()和progressBar.Update(),但他们没有做任何事情。
正如你可能会说的那样,我对线程很陌生,所以我可能会在这里看到一些明显的东西,但我却看不到它。如何从类外的某个地方更新progressBar?
答案 0 :(得分:-1)
backgroundWorker
与GUI线程位于不同的线程上。您必须通过查看InvokeRequired
(http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx)来检查您是否在GUI线程上。如果不是,请通过调用Invoke()
(http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx)调用GUI线程上的函数。
这段代码应该可以解决问题。
public void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (this.InvokeRequired)
{
this.Invoke(new Action<object, ProgressChangedEventArgs>(backgroundWork1_ProgressChanged), sender, e);
return;
}
this.progressBar.Value = e.ProgressPercentage;
}