I am updating my code from a BackgroundWorker to Tasks and am running into an issue. I would like to mimic the functionality that BackgroundWorker has where, when the DoWork()
thread completes, the BackgroundWorker calls the DoWorkCompleted()
function. Here's what I have so far:
Private Sub btn_Start_Click(sender, e) Handles btn_Start.Click
btn_Stop.IsEnabled = True
btn_Start.IsEnabled = False
_cts = New CancellationTokenSource()
Dim theWork As Task = Worker.Start(_cts.Token)
theWork.ContinueWith(AddressOf OnWorkCompleted)
End Sub
Private Sub OnWorkCompleted()
btn_Stop.IsEnabled = False
btn_Start.IsEnabled = True
End Sub
Private Sub btn_Stop_Click(sender, e) Handles btn_Stop.Click
_cts.Cancel()
End Sub
Then in another file, Worker.vb, I have the following:
Private Shared _cts As CancellationToken
Public Shared Function Start(token As CancellationToken) As Task
Try
_cts = token
Return Task.Run(AddressOf Process, token)
Catch ex As TaskCanceledException
MessageBox.Show("Task cancelled")
Return Task.CompletedTask
End Try
End Function
Private Shared Async Sub Process()
Try
Log.Information("0")
Await Task.Delay(1000, _cts)
Log.Information("1")
Await Task.Delay(1000, _cts)
Log.Information("2")
Await Task.Delay(1000, _cts)
Log.Information("3")
Await Task.Delay(1000, _cts)
Log.Information("4")
Await Task.Delay(1000, _cts)
Catch ex As OperationCanceledException
MessageBox.Show("cancelled operation")
End Try
End Sub
Pretty much, what I want to happen with this code is to mimic what will happen with the full code when I migrate it over: after a user clicks start, a long operation runs on a separate thread and the UI is still responsive. If at any point the user clicks Stop, the task will end and the OnWorkCompleted
function will be called. What happens, is the OnWorkCompleted() is called immediately and not when Stop is clicked.
CodePudding user response:
As a general rule, you should avoid Async Sub
:
Private Shared Async Function Process() As Task
Also, use Await
instead of ContinueWith
:
Private Async Sub btn_Start_Click(sender, e) Handles btn_Start.Click
btn_Stop.IsEnabled = True
btn_Start.IsEnabled = False
_cts = New CancellationTokenSource()
Try
Await Worker.Start(_cts.Token)
Finally
OnWorkCompleted()
End Try
End Sub
You may find my blog post series on replacing BackgroundWorker
with Task.Run
helpful.