user3719173
user3719173

Reputation: 387

WPF Stop BackgroundWorker from main thread

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?

Upvotes: 0

Views: 4131

Answers (3)

NeddySpaghetti
NeddySpaghetti

Reputation: 13495

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
}

Upvotes: 1

Sheridan
Sheridan

Reputation: 69985

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.

Upvotes: 1

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149628

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);

Upvotes: 0

Related Questions