Async loading for winforms
Where am i supposed to place the await keyword to accomplish this? I can't place it in my Load event since this needs to complete for the application to behave "normally".
Why can't you await inside load event handler? You can do that if you mark the method with async
modifier.
private async void Form_Load(object sender, EventArgs e)
{
//Do something
var data = await GetDataFromDatabaseAsync();
//Use data to load the UI
}
This way, you can keep the UI responsive and also execute the time consuming work asynchronously. GetDataFromDatabaseAsync
has to be asynchronous (should not block the calling thread).
If this doesn't answers your question, please be more specific.
H W
Updated on June 20, 2022Comments
-
H W almost 2 years
In (Android) Apps it is quite common to have ListViews loading and being built while the user is interacting with the interface. In Winforms however the tendency seems to be clicking a button and waiting for the result to be fully loaded before the user can continue navigating through the application.
Since the database access that i am currently using is quite slow, i would like to use the database in async methods to enable the user to keep interacting with the interface, while the data is not fully loaded and displayed.
For example i would like to start an asynchronous method in my Form_Load event to keep gathering data. When this method completes, i want to bind the data to some controls - this will (for now) not change the functionality at all. Thus i want the user not to notice any difference (except for the data being shown or not) when handling the application.
Where am i supposed to place the await keyword to accomplish this? I can't place it in my Load event since this needs to complete for the application to behave "normally".
Is it even possible with async methods to have windows forms being fully reactional while not all methods completed, or am i looking at the 'wrong' functionality for my purposes?
Thank you in advance.
Edit: Following Srirams hint, I made the load-event itself an async sub which worked out well. Here is some simple sample code which shows the desired behaviour:
Public Class DelayedLoadingWindow Private Async Sub DelayedLoadingWindow_Load(sender As Object, e As EventArgs) Handles MyBase.Load Dim awaitedResultOne As Task(Of String) = GetDataOneAsync() Label1.Text = Await awaitedResultOne Dim awaitedResultTwo As Task(Of String) = GetDataTwoAsync() Label2.Text = Await GetDataTwoAsync() Dim awaitedResultThree As Task(Of String) = GetDataThreeAsync() Label3.Text = Await GetDataThreeAsync() Me.Text = "DONE" End Sub Public Async Function GetDataOneAsync() As Task(Of String) Await Task.Delay(2000) Return "Async Methods" End Function Public Async Function GetDataTwoAsync() As Task(Of String) Await Task.Delay(2000) Return "are" End Function Public Async Function GetDataThreeAsync() As Task(Of String) Await Task.Delay(2000) Return "running!" End Function End Class
-
Ben Robinson over 9 yearsWhilst this won't block the UI as such, surely the form in question will not load until the event handler completes, which will not be until the
GetDataFromDatabaseAsync()
completes. -
Sriram Sakthivel over 9 years@BenRobinson From what OP said Thus i want the user not to notice any difference (except for the data being shown or not) that's fine I guess. Also what else you can do about it?
-
Steve over 9 yearsDoWork works in a different thread from the UI thread, no message loop there. This will fail in a spectacular way.
-
Stephen Cleary over 9 years@BenRobinson: No, WinForms considers the
Form_Load
event "done" when it hits the firstawait
. This is an entirely appropriate solution; just make sure that the form is initialized to an "empty state" UI before the firstawait
, and then the code after the firstawait
should just be updating the UI to contain the data. -
M.G.E over 9 years@StephenCleary I think if we consider this case as general in OOP, what's happening is that you don't know what's happening after Load handler of form, then it can not wait a handler.
-
Vaibhav J over 9 years@Steve: i just forget to add Application.Run(frm), now i have updated my code, and its now perfectly working, i have checked it with my test project. Thanks for correct me.
-
Stephen Cleary over 9 years@TommyMoore: I'm not sure what you mean. It's an event, and can be handled asynchronously just fine.
-
Steve over 9 yearsNot downvoting you but this is still wrong stackoverflow.com/questions/3892189/…
-
Vaibhav J over 9 years@Steve: what is the problem with the code Steve, i m curious to know, i have test it with my test project and i can send it you if you want. pl. let me know the problem.
-
M.G.E over 9 years@StephenCleary Let's assume that I have a Custom form that it has a custom OnFormLoad and after the Load event runs some jobs then if we handle Load like that we wait the jobs after Load event. It's attractive because it's new feature in c# but not the robust and neat solution like running a Task in a new thread.
-
Sriram Sakthivel over 9 years@TommyMoore What do you mean? Are you sure you know enough about async/await ? What makes
Task
a robust and neat which async/await isn't? -
Sriram Sakthivel over 9 years@Vaibhav Now your
DoWork
event can't do any other work than pumping the message which makes theBackgroundWorker
useless. -
Steve over 9 yearsAnd if you look at the not accepted answer in the link posted you will discover the problems with drag.drop and copy.paste
-
H W over 9 yearsThank you, apparently i was just lacking some very basics of async methods. Stephens hint was very helpful as well!
-
Sriram Sakthivel over 9 years@HW Welcome. StephenCleary's blog is a good place to start learning async/await. Cheers!.
-
erict about 6 yearsI thought doing "async void" is a sin? see Haack's haacked.com/archive/2014/11/11/async-void-methods
-
Sriram Sakthivel about 6 years@erict yes it is with the exception of event handlers. Just because you can't have the event handlers return a Task, its okay to have async void there. But we should handle the exceptions inside the method as no one is waiting for the task.