2017-08-21 226 views
2

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

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

+0

是的,我已经有我的代码需要进入背景工作的几个任务,所以我想在我的例子中有一个设置。 for-loop类似于要完成的任务。 – 10a

+0

好的我明白了,那么'testcancel'实际上是一种简单地触发线程并让它在后台运行的方法,而这实际上都是要做的。由于线程运行时间较长,因此您不应该尝试处理这种方法中的表单处理!这将是线程方法的工作。也是'MessageBox.Show(“All done”);'line属于'DoWork'事件,因为实际上只有线程本身知道作业何时完成,而不是启动线程的方法 –

回答

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例外。如果后台进程仍在运行并尝试更新进度条,并且您已经处理该表单。你应该删除这行,并把它留给垃圾收集器。

+0

删除循环?但是工人内部什么都没有留下来? – 10a

+0

他在说'while(worker.IsBusy)'循环。 – Fildor

+0

是的,我刚刚看到它,现在它正在工作。 – 10a

4

此代码是你的问题:

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

您的GUI线程是在循环,直到你的工人完成。 您需要使EventHandler内的工作者实例可以访问,并从那里调用worker.CancelAsync()。


这个之外,我个人会提高代码的2个步骤:

  1. 移动整个的BackgroundWorker到MetingProgress类,使它的构造采取委托实际工作落实。

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

+0

我正在尝试扩展我的代码一步一步,并了解它是如何工作的,所以我可能会最终得到一些建议。 – 10a

+2

过渡到TAP真的需要一些时间来包装你的头。慢慢来,但绝对值得一试。一步一步做,是你可以做的最好的学习。祝你好运! – Fildor