3

首先这是我的代码布局:

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?

4

1 回答 1

-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;
}
于 2013-08-02T23:46:34.663 回答