WPF从主线程停止BackgroundWorker

时间:2014-06-09 10:50:00

标签: c# wpf multithreading

我有一个BackgroundWorker,可以在后台执行工作。工作是在命令提示符下运行一些.exe应用程序并等待输出显示。有时.exe应用程序是堆栈或需要很多时间。我想在一分钟后停止工人,以防它仍在运行。 问题是我有一个在主线程中运行1分钟的进度条。我想在主线程(UI)中进度条已满(1分钟后)时停止工作。这是我的代码:

    private void btnTest_Click(object sender, RoutedEventArgs e)
    {

        wTest = new BackgroundWorker();
        wTest .DoWork += new DoWorkEventHandler(wTest _DoWork);
        wTest .RunWorkerCompleted += wTest _RunWorkerCompleted;
        wTest .WorkerReportsProgress = true;
        wTest .WorkerSupportsCancellation = true;
        wTest .RunWorkerAsync();

        while (pbTest.Value < 91)
        {               
            if (!wTest.CancellationPending)
            {
                pbTest.Value = (pbTest.Value + 100/60);
                Thread.Sleep(1000);
            }
            Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background,
                                       new ThreadStart(delegate { }));
        }
    }

    void wTest_DoWork(object sender, DoWorkEventArgs e)
    {
        //call .exe application and wait for output
    }

我该怎么做?

3 个答案:

答案 0 :(得分:1)

如果您使用的是.net 4.5,则可以使用Task类以及相关的CancellationTokeSourceCancellationToken类。请注意,任务支持通过IProgress界面报告进度。 Stephen Cleary对此有一个很好的example

如果您正在进行的工作不提供异步接口,您可以使用Task.Run执行它并传递CancellationToken以监控取消。当您正在进行工作时,您需要监视令牌以进行取消。一种方法是拨打ThrowIfCancellationRequested,如果在OperationCancelledException上调用了Cancel,则会CancellationTokenSourceCancellationTokenSource还支持在一定时间后取消,这对您的方案非常方便。

private CancellationTokenSource cts;

private void btnTest_Click(object sender, RoutedEventArgs e)
{
    if(cts == null)
    {
        cts = new CancellationTokenSource(new TimeSpan(0, 0, 60)); // cancel after 60 seconds
    }

    await Task.Run( () => Work(), cts.Token);

    cts = null;
}

void Work(CancellationToken token)
{
   // do work
  token.ThrowIfCancellationRequested();
  // do work
}

答案 1 :(得分:1)

您需要做两件事才能取消BackgroundWorker的工作。首先,您需要检查DoWork处理程序方法中的BackgroundWorker.CancellationPending property

private void wTest_DoWork(object sender, DoWorkEventArgs e)
{
    //call .exe application and wait for output
    if (worker.CancellationPending)
    {   
        e.Cancel = true;
    }
}

然后,当您想要取消工作时,您应该在BackgroundWorker

上拨打此电话
backgroundWorker.CancelAsync();

但是,由于您使用BackgroundWorker因为它本来要使用,我不认为这对您有用。如果您正在等待第三方应用程序启动,则您将无法将e.Cancel属性设置为true

说实话,我不太明白为什么你只使用BackgroundWorker开始一个过程。 Process.Start方法没有时间完成,因为它不等待任何响应。在我看来,您最好不要监控Process.Exited event并改为调用Process.Kill method

答案 2 :(得分:0)

您需要做的是DoWork代理检查e.CancelDoWorkEventArgs)属性设置为true。如果DoWork正在阻止,例如等待StandardOutput,那么根本就不可能。

另一种方法是传递Process.WaitForExitint说明它应该等待输出的时间:

process.WaitForExit(60000);