【问题标题】:Show a form while BackgroundWorker is running在 BackgroundWorker 运行时显示表单
【发布时间】:2015-04-01 03:20:30
【问题描述】:

我想在BackgroundWorker 的工作没有完成时显示一个“加载表单”(一个带有一些文本消息的表单加上一个样式设置为选取框的进度条)。当BackgroundWorker 完成后,加载表单必须自动关闭。虽然我确实使用了BackgroundWorker,但主线程应该等到它完成。我可以使用AutoResetEvent 做到这一点,但我注意到由于它确实阻塞了主线程,因此表单加载的进度条也被冻结了。

我的问题是:如何在后台运行进程并等待它完成时显示该表单而不冻结它?我希望它很清楚。

这是我当前的代码:

    BackgroundWorker bw = new BackgroundWorker();
    AutoResetEvent resetEvent = new AutoResetEvent(false);
    //a windows form with a progressBar and a label
    loadingOperation loadingForm = new loadingOperation(statusMsg);
    //that form has a progressBar that's freezed. I want to make 
    // it not freezed.
    loadingForm.Show();

    bw.DoWork += (sender, e) =>
    {
        try
        {
            if (!e.Cancel)
            {
               //do something
            }
        }
        finally
        {
            resetEvent.Set();
        }
    };

    bw.RunWorkerAsync();
    resetEvent.WaitOne();
    loadingForm.Close();
    MessageBox.Show("we are done!");

【问题讨论】:

  • Backgroundworker 不会停止主线程。如果你想做某事,你可以使用事件 progresschanged、runworkercompleted 等。只需使用调度程序对象来调用主线程的任何内容。

标签: c# multithreading winforms backgroundworker


【解决方案1】:

将您的 BackgroundWorkerRunWorkerCompleted 连接到将关闭表单的回调,如下所示:

private void backgroundWorker1_RunWorkerCompleted(
    object sender, RunWorkerCompletedEventArgs e)
{
    loadingForm.Close();  
    MessageBox.Show("we are done!");
}

您可以删除resetEvent.WaitOne();

当然,您需要将loadingForm 设为一个字段

告诉我更多

在后台操作完成、取消或引发异常时发生

【讨论】:

  • 我真的需要等待 BackgroundWorker 完成才能继续运行语句。比如查看编辑后的代码,MessageBox.Show()会在DoWork完成之前被调用,不是吗?
  • @Jack 请查看修改后的答案
  • 我以前做过。让我尝试更好地解释。假设BackgroundWorkerfoo() 函数内部被调用,我在hehe() 函数内部有以下语句:foo(); baa()。函数baa() 将在DoWork 完成之前被调用。我知道我可以将baa() 移动到DoWork 事件内部。但在这种情况下,我不能。 foo() 必须仅在 backgroundWorker 完成后返回。这就是我使用AutoResetEvent 的原因
  • @Jack 听起来像是一个新问题?
  • @Jack 为什么BackgroundWorker 需要foo() 而不是hehe()
【解决方案2】:

使登录表单对象成为实例变量。

//use RunWorkerCompleted event to get notified about work completion where you close the form.
bw.RunWorkerCompleted += bw_RunWorkerCompleted;

事件处理代码:

private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    this.loadingForm.close();    
}

参考:https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.runworkercompleted(v=vs.110).aspx

【讨论】:

  • 我以前做过。问题是:我真的需要等待 BackgroundWorker 完成才能继续运行语句。例如,查看编辑后的代码,在 DoWork 完成之前会调用 MessageBox.Show(),不是吗?
  • 在工作人员完成后您想做的任何事情都应该从 bw_RunWorkerComplete 处理程序方法中调用,该方法仅在 DoWork 完成后调用。
【解决方案3】:

Cek 这个脚本,Loading is Form with PictureBox - image gif

private delegate void showProgressCallBack(int value);

private void btnStart5_Click(object sender, EventArgs e)
    {
        BackgroundWorker bw = new BackgroundWorker();
        Loading f = new Loading();
        f.Show();

        bw.DoWork += (s, ea) =>
        {
            try
            {
                test1();
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message); 
            }
        };
        bw.RunWorkerCompleted += (s, ea) =>
        {
            f.Close();
        };

        bw.RunWorkerAsync();
    }

private void showProgress(int value)
    {
        if (progressBar1.InvokeRequired)
        {
            showProgressCallBack showProgressDelegate =  new showProgressCallBack(showProgress);
            this.Invoke(showProgressDelegate, new object[] {value});
        }
        else
        {
            progressBar1.Value = value;
        }
    }

private void test()
    {
        showProgress(20);
        Thread.Sleep(3000);
        showProgress(80);
        Thread.Sleep(2000);
        showProgress(100);
    }

【讨论】:

    猜你喜欢
    • 2012-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-26
    • 2012-02-05
    • 1970-01-01
    相关资源
    最近更新 更多