Reputation: 387
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
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
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
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