Andarta Andarta - 19 days ago 5
Vb.net Question

Making sure async tasks complete before vb.net application terminates

I'm creating a vb.net desktop application. This application includes some asynchronous functions. When the user closes the application via the red X in the upper-right corner, there is some logic to possibly run one or more of these async functions. The problem is, the program terminates before they are complete. I figured using "Await" in my call would do that, but apparently not.

I found this thread that talks about using ManualResetEvent, but I'm having trouble understanding all of it, especially since the question is in the context of a console app, and the MSDN documentation the answer links to is about specifying threads, not simply using async tasks. As an attempt at using it anyway, I tried adding this to my main form:


Public resetEvent As ManualResetEvent = New ManualResetEvent(False)


And immediately after the call to one of these functions, I added this (quote includes the call):

Await activeCount.SerializeAsync(activeCount)
resetEvent.WaitOne()


And at the end of my async function itself, before returning the Task, added this:

frmMain.resetEvent.Set()


I don't think I'm using that right, though. The program still terminates before it's complete anyway.

Even before that, I figured the best place for such a thing would be in
ApplicationEvents MyApplication_Shutdown
, but I'm not sure how to know if such a function is still running at that point.

So what is the best way to make sure all my async functions complete before the application terminates in this situation?

Thank you!




UPDATE AFTER ACCEPTED ANSWER:

Though F0r3v3r-A-N00b's answer worked, I realized I need to use a dialog in certain cases. I couldn't call that within the background worker because the dialog is on the GUI thread, not the background thread. I tried moving things around so I'd call the dialog first, then make the background worker and all that, but for whatever reason I couldn't get it to work.

Long story short, I got around it by simply making a synchronous version of my functions, and so I could say 'if the user terminated the program and I need to call any of these functions before closing, call the synchronous versions instead'. That works. Thanks!

Answer

Try this. Create a new project. Add 1 label and backgroundworker to your form. Paste this in your form's code area:

Public Class Form1
Dim taskCompleted As Boolean = False
Dim taskIsrunning As Boolean = False

Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    Threading.Thread.Sleep(5000)
End Sub






Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    taskCompleted = True
    taskIsRunning = False
    Label1.Text = "Background task completed."
    Me.Close()
End Sub






Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    If taskIsRunning Then
       e.Cancel = True
       Exit Sub
    End If

    If Not taskCompleted Then
        taskIsRunning = True
        Label1.Text = "Starting background task."
        BackgroundWorker1.RunWorkerAsync()
        Label1.Text = "Background task is running."
        e.Cancel = True
    End If
End Sub
End Class
Comments