c# – 事件没有按顺序发生

我在C#中创建一个WinForms应用程序.当我点击一个按钮时,会发生一定数量的事件:

  • Click Button
  • Show label1
  • Show label2
  • Call function to parse a string the user entered before (this can take awhile depending on the string)
  • Show listBox1 and progressBar1
  • backgroundWorker1.RunWorkerAsync
  • backgroundWorker1_DoWork() does something x number of times and reports progress each time
  • backgroundWorker1_ProgressChanged() updates progressBar1 and adds an item to listBox1
  • backgroundWorker1_RunWorkCompleted() shows a message box saying “DONE”

但这不是实际发生的事情.当我浏览代码并查看表单时,它有几个问题.

> label1和label2直到解析完成后才真正出现.
> progressBar1有时会在调用ProgressChanged时更新.其他时候它将等到“DONE”打印完毕并立即更新.
>每次调用progressChange()时,listBox1上的垂直滚动条变小,以便我可以判断正在添加项目,但是在打印“DONE”之后才会显示Items的文本.

我是使用backgroundWorker的新手,所以我可能无法理解它应该如何运作.但显示标签的延迟我根本就不明白.当我浏览代码时,没有错误,并且行似乎以正确的顺序执行.

有没有人对可能导致这些问题的原因有所了解?我将不胜感激任何帮助或建议.我宁愿不发布我的代码,只是因为有很多,但如果有人需要它来更好地理解,只需lmk.

编辑:这是代码.

private void button1_Click(object sender, EventArgs e){
    label1.Show();
    label2.Show();
    String errMsg = parseString();
    if (errMsg == ""){
        listBox1.Items.Clear();
        listBox1.Show();

        progressBar1.Maximum = 100;
        progressBar1.Step = 1;
        progressBar1.Value = 0;
        progressBar1.Show();

        backgroundWorker1.DoWork += backgroundWorker1_DoWork;
        backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
        backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
        backgroundWorker1.WorkerReportsProgress = true;
        backgroundWorker1.WorkerSupportsCancellation = true;

        if (backgroundWorker1.IsBusy != true)
        {
            backgroundWorker1.RunWorkerAsync();
        }
    }
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        backgroundWorker1.ReportProgress(1, "Updating Devices");
        for (int i = 0; i < 100; i++)
        {
            //todo: do stuff

            //update progress
            backgroundWorker1.ReportProgress(i, "Device:" + i);
        }
    }

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
        listBox1.Items.Add(e.UserState);
    }

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        MessageBox.Show("DONE");
    }

最佳答案 感谢@HansPassant和@mwwills的评论.他们带领我走上正轨,使这个解决方案成为可能.

最后我决定做两个后台工作者来解决label1和label2的问题,直到解析完成后才出现.我使用第一个进行解析,第二个使用“do stuff”部分.在代码中,您将看到我必须使用Invoke来编辑标签,因为该部分现在存在于不同的线程上.

我也意识到在调用ProgressChanged之前“做东西”不是立竿见影的.我一直在开发并且尚未实现该代码,但我知道这些操作至少需要3秒才能完成(部分原因是涉及ping).所以现在我已经在该循环中调用Sleep(3000)来模拟它的实际行为.这解决了由吃掉所有内存引起的奇怪的progressbar1和listbox1行为.

以下是代码的结果:

private void button1_Click(object sender, EventArgs e)
    {
        if (backgroundWorker1.IsBusy != true)
        {
            backgroundWorker1.RunWorkerAsync();
        }
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        String errMsg = parseString();
        if (errMsg == "")
        {
            if (listBox1.InvokeRequired)
            {
                listBox1.Invoke(new MethodInvoker(delegate
                {
                    listBox1.Items.Clear();
                    listBox1.Show();
                }));
            }

            if (progressBar1.InvokeRequired)
            {
                progressBar1.Invoke(new MethodInvoker(delegate
                {
                    progressBar1.Maximum = 100;
                    progressBar1.Step = 1;
                    progressBar1.Value = 0;
                    progressBar1.Show();
                }));
            }

            if (backgroundWorker2.IsBusy != true)
            {
                backgroundWorker2.RunWorkerAsync();
            }
        }
        else
        {
            MessageBox.Show(errMsg);
        }
    }

    private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
    {
        backgroundWorker2.ReportProgress(1, "Updating Devices");
        for (int i = 0; i < 100; i++)
        {
            System.Threading.Thread.Sleep(3000);
            //do stuff

            backgroundWorker2.ReportProgress(i, "Device:" + i);
        }
    }

    private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        if (progressBar1.InvokeRequired)
        {
            progressBar1.Invoke(new MethodInvoker(delegate
            {
                progressBar1.Value = e.ProgressPercentage;
            }));
        }
        if (listBox1.InvokeRequired)
        {
            listBox1.Invoke(new MethodInvoker(delegate
            {
                listBox1.Items.Add(e.UserState);
            }));
        }
    }

    private void backgroundWorker2_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        MessageBox.Show("DONE");
    }
点赞