WPF从主线程停止BackgroundWorker[英] WPF Stop BackgroundWorker from main thread

本文是小编为大家收集整理的关于WPF从主线程停止BackgroundWorker的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

本文来自:IT宝库(https://www.itbaoku.cn)

我有一个背景工作者在后台执行工作.该工作是在命令提示符中运行的一些.EXE应用程序,并等待输出以显示.有时,.EXE应用程序是堆栈或需要大量时间.我想在一分钟后停止工作,以防它仍在运行. 问题是我有一个在主线程中运行1分钟的进度栏.当进度栏已满(1分钟后)从主线程(UI))时,我想停止工人.这是我的代码:

    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
    }

我该怎么做?

推荐答案

如果您使用的是.net 4.5,则可以使用Task类和关联的CancellationTokeSource和CancellationToken类.请注意,任务支持通过IProgress接口进行报告进展. Stephen Cleary有一个很好的示例.

如果您正在进行的工作不提供异步接口,则可以使用Task.Run执行它并传递CancellationToken以监视取消.当您进行工作时,您需要监视取消令牌.一种方法是调用 throwCancellationRequested 如果在CancellationTokenSource上调用Cancel,它将抛出OperationCancelledException. CancellationTokenSource在一定时间后也支持取消,这将适合您的情况.

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
}

其他推荐答案

您需要做两件事,以取消您的BackgroundWorker.首先,您将需要检查 BackgroundWorker.CancellationPending BackgroundWorker.CancellationPending BackgroundWorker.CancellationPending 在您的DoWork处理程序方法中:

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方法而不是.

其他推荐答案

您需要做的是让您的DoWork委托检查e.Cancel(在DoWorkEventArgs中)属性将设置设置为true.如果DoWork正在阻止,就像等待StandardOutput一样,那就不可能了.

另一种方法是通过Process.WaitForExit an int说明应该等待多长时间:

process.WaitForExit(60000);

本文地址:https://www.itbaoku.cn/post/2584242.html

问题描述

i have a BackgroundWorker that execute work in the background. the work is run some .exe application in command prompt and wait for output for display. sometimes the .exe app is stack or takes a lot of time. i want to stop the worker after one minute in case it is still running. the issue is that i have a progress bar that runs in the main thread for 1 minute. i want to stop the worker when the progress bar is full (after 1 minute) from the main thread (UI). here is my code:

    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
    }

how can i do it?

推荐答案

If you are using .net 4.5, you can use the Task class and the associated CancellationTokeSource and CancellationToken classes. Note that tasks support reporting progress through the IProgress interface. Stephen Cleary has a good example on this.

If the work you were doing does not provide an asynchronous interface you can use Task.Run to execute it and pass a CancellationToken to monitor for cancellation. As you are doing the work you need to monitor the token for cancellation. One way to do this is to call ThrowIfCancellationRequested which will throw a OperationCancelledException if Cancel has been called on the CancellationTokenSource. CancellationTokenSource also supports cancellation after a certain time, which will be handy for your scenario.

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
}

其他推荐答案

You will need to do two things to enable work cancellation of your BackgroundWorker. First, you will need to check for the BackgroundWorker.CancellationPending property in your DoWork handler method:

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

Then, when you want to cancel the work, you should call this on your BackgroundWorker:

backgroundWorker.CancelAsync();

However, as you are not using the BackgroundWorker as it was meant to be used, I don't think that this will work for you. If you are waiting for the third party application to start, then you won't be able to set the e.Cancel property to true.

To be honest, I can't quite understand why you would use a BackgroundWorker just to start a process anyway. The Process.Start method takes no time to complete as it doesn't wait for any response. In my opinion, you'd be better off monitoring the Process.Exited event and calling the Process.Kill method instead.

其他推荐答案

What you need to do is have your DoWork delegate check for e.Cancel (in DoWorkEventArgs) property bring set to true. If DoWork is blocking, like waiting for StandardOutput, then that simply wont be possible.

Another approach would be to pass Process.WaitForExit an int stating how long it should wait for output:

process.WaitForExit(60000);