活动未按顺序进行

时间:2018-09-19 12:27:26

标签: c# winforms backgroundworker

我正在用C#创建WinForms应用程序。当我单击按钮时,一定的事件流应该蒸腾起来:

  
      
  • 点击按钮
  •   
  • 显示标签1
  •   
  • 显示标签2
  •   
  • 调用函数以解析用户之前输入的字符串(这可能需要一段时间,具体取决于字符串)
  •   
  • 显示listBox1和progressBar1
  •   
  • backgroundWorker1.RunWorkerAsync
  •   
  • backgroundWorker1_DoWork()做x次,每次报告进度
  •   
  • backgroundWorker1_ProgressChanged()更新progressBar1并将一项添加到listBox1
  •   
  • backgroundWorker1_RunWorkCompleted()显示一个消息框,显示“完成”
  •   

但这不是实际发生的情况。当我遍历代码并查看表单时,它有几个问题。

  1. label1和label2直到解析完成后才真正出现。
  2. progressBar1有时仅在调用ProgressChanged时更新。其他时候,它将等到打印“ DONE”并立即全部更新。
  3. 每次调用progressChange()时listBox1上的垂直滚动条会变小,因此我可以确定正在添加项目,但是直到打印“ DONE”后,项目的文本才会出现。

我是不熟悉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");
    }

1 个答案:

答案 0 :(得分:1)

感谢@HansPassant和@mjwills的评论。他们带领我走上了正确的道路,并使这一解决方案成为可能。

最后,我决定做两个后台工作程序来解决label1和label2直到解析完成后才出现的问题。我使用第一个执行解析,第二个使用“执行任务”部分。在代码中,您将看到我必须使用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");
    }