Home > Blockchain >  .NET How to define an Async task Callback
.NET How to define an Async task Callback

Time:04-16

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.

  • Related