Today I will show how to do async programming with VB.NET. Async allows you to run certain code in a different thread; the benefit is that you can run multiple code blocks at once.
Let me explain. All your code is run in a thread you might have multiple threads if set it up that way. When you create a new app all the code such as forms and other UI-related code. Now, this is fine for most projects but let’s say you are loading data from a super slow API and you don’t want your app to freeze while this is happening then you can run the loading in a separate thread so that the main thread is not frozen. One thing to keep in mind is that you cannot reference objects across threads without first invoking it first.
Let’s get started with some samples. First, we will make a sample to just sleep the thread to act as the super slow API. Create a WinForms project for vb.net obviously. On the main form add the following controls:
Apply the following properties to the form:
When you’re done the form should be like this:
Next in the code behind add the following code:
Private Sub btnSync_Click(sender As Object, e As EventArgs) Handles btnSync.Click APICall() End Sub Private Sub btnAsync_Click(sender As Object, e As EventArgs) Handles btnAsync.Click Task.Run(AddressOf APICall) End Sub Private Sub APICall() Threading.Thread.Sleep(10000) MsgBox("Done") End Sub
Note that Task.Run() will accept a lambda expression as well. When you run the app and press the sync button it does work and the form freezes. Now if you press the async button you can move the form around.
In this example, we will reference a variable created in a different thread. In this case, it is a control. We will start with the same UI as the other. Remove the sync button. Then add a label with the name lblState. Put the label below the button. Then add this code:
Private Sub btnAsync_Click(sender As Object, e As EventArgs) Handles btnAsync.Click Task.Run(Sub() Invoke(Sub() lblStatus.Text = New Random().Next(100).ToString)) End Sub
As you can see when we reference the label we need to call the forms to invoke method and pass a lambda expression to execute on the form’s thread. If you do not use the invoker it will throw a runtime exception. I would not recommend using invoke unless you have to.
In this example, we will return a value from an async method. Since we are executing the code in a separate thread when calling it, it will not wait for the code to finish executing; it just keeps going. So in order to get the value, we have to wait for it to finish executing. We will do the same thing as in the other example but we will use a function instead of invoking the control. Add this code:
Private Async Sub btnAsync_Click(sender As Object, e As EventArgs) Handles btnAsync.Click lblStatus.Text = Await GetNumber() End Sub Private Function GetNumber() As Task(Of Integer) Return New Task(Of Integer)(Function() New Random().Next(100)).Run(Function() New Random().Next(100)) End Function
As you can see we display a random number in the label without using the Invoke method.
Async methods can be really handy when you are wanting to run along or big process with disabling the other parts of your app. But you have to be careful with cross-thread calls to variables and methods as this will cause runtime errors.