使用BackgroundWorker进行表单冻结

时间:2017-08-21 06:54:56

标签: c# winforms progress-bar backgroundworker

我正在使用WinForm,从中我需要的所有进程都会被引导。现在,我尝试将BackgroundWorkerProgressBar和取消按钮集成到我的代码中。我希望它在我的代码本地,而不是在一个单独的方法。要对此进行测试,将创建一个带有进度条(尚未激活)的新表单和一个用于停止for循环的按钮。但是,代码无法正常工作(甚至还没有包含进度条)。表格立即冻结(见图),因此我无法测试取消按钮。但是,执行for循环并显示"Done: " + l.ToString()。我该如何解决这个问题?

void stopMeasurement(object sender, EventArgs e) 
{
    stopMeas = true;    
}

public void testcancel() // Test method which is triggered manually
{
    int l = 0;

    MetingProgress metingProgress = new MetingProgress();
    metingProgress.btnCancelmeting.Click += new EventHandler(stopMeasurement);

    BackgroundWorker worker = new BackgroundWorker();
    worker.WorkerSupportsCancellation = true;
    worker.DoWork += (sender, args) =>
    {                       
        for (int k = 0; k < 10; k++)
        {
            Thread.Sleep(1000);
            l++;

            if (worker.CancellationPending)
                break;
        }

        MessageBox.Show("Done: " + l.ToString());

    };
    worker.RunWorkerAsync(); 

    while (worker.IsBusy) 
    {
        if (stopMeas)
            worker.CancelAsync();
    }

    metingProgress.Dispose();
    MessageBox.Show("All done");

}

enter image description here

2 个答案:

答案 0 :(得分:4)

此代码是您的问题:

while (worker.IsBusy) 
{
    if (stopMeas)
        worker.CancelAsync();
}

您的GUI-Thread处于该循环中,直到您的工作完成。 您需要从EventHandler中访问您的worker实例,并从那里调用worker.CancelAsync()。

除此之外,我个人会分两步改进代码:

  1. 将整个BackgroundWorker移动到MetingProgress类中,并使其构造函数为实际工作实现提供委托。

  2. 使用TAP(任务异步模式),即async / await Task with Progress和CancellationToken。

答案 1 :(得分:4)

  

表单立即冻结

这是因为您在主线程上仍然运行 while循环!因此表单不会响应。这叫做buisy等待。您将无法调用CancelAsync方法。

一种解决方案可能是删除while循环并将取消调用放入按钮事件代码中:

void stopMeasurement(object sender, EventArgs e)
{
    stopMeas = true;
    worker.CancelAsync();

}

你基本上做的是:你创建了第二个取消令牌。因此,另一种可能性是仅使用stopMeas来取消后台操作:

worker.DoWork += (sender, args) =>
{                       
    for (int k = 0; k < 10; k++)
    {
        Thread.Sleep(1000);
        l++;

        if (stopMeas)
            break;
    }

    string mes = stopMeas ? "Done: " + l.ToString() : "Task aborted!";
    MessageBox.Show(mes);

};
编辑:也是这一行:

metingProgress.Dispose();

可能会导致ObjectDisposed异常。如果后台进程仍在运行并尝试更新进度条,则您已经处理了该表单。您应该删除此行并将其留给垃圾收集器。