0

I know there are several posts about this before:

Post 1, Post 2

I have not got any of this to work.

In my Winform application, the queries to the database are only accessible through async methods. I need the list myObjectsList to be populated with the result before I call the method:

DisplayInTheDatagridview(myObjectsList).

Now this method is always called with an empty list. If I set a breakpoint in my code and wait the result will be finished, so the database has the actual data I want to retrieve. This is what I have tried so far:

public void ShowRowsInDatagridview(List<MyObjects> listRowsToQueryDB)
{
    List<MyObjects> myObjectsList = new List<MyObjects>();

    var task = client.GetListFromDBAsync(listRowsToQueryDB);
    task.Wait();

    var result = task.Result;
    myObjectsList = (List<MyObjects>)result;

    DisplayInTheDatagridview(myObjectsList);
}

public void ShowRowsInDatagridview(List<MyObjects> listRowsToQueryDB)
{
    List<MyObjects> myObjectsList = new List<MyObjects>();

    var result = client.GetListFromDBAsync(listRowsToQueryDB).GetAwaiter().GetResult();
    myObjectsList = (List<MyObjects>)result;

    DisplayInTheDatagridview(myObjectsList);
}

public void ShowRowsInDatagridview(List<MyObjects> listRowsToQueryDB)
{
    List<MyObjects> myObjectsList = new List<MyObjects>();

    var result = Task.Run(async () => await client.GetListFromDBAsync(listRowsToQueryDB)).Result;
    myObjectsList = (List<MyObjects>)result;

    DisplayInTheDatagridview(myObjectsList);
}
Borisonekenobi
  • 469
  • 4
  • 15
  • Why isn't the `ShowRowsInDatagridview` method also `async`, so it can internally `await` other `async` operations? – David Jul 19 '23 at 14:04
  • 2
    You _need_ to go async _all the way_. – Fildor Jul 19 '23 at 14:05
  • 2
    If you have an EventHandler that starts off this operation, than make that async: `async void OnButtonClick(EventArgs e) { await ShowRowsInDataGridAsync( ... ) ;}` – Fildor Jul 19 '23 at 14:07
  • 3
    All options are wrong. The correct one is to change the signature to `async Task` and use `var myObjectList=await client.GetListFromDBAsync(listRowsToQueryDB);` If `GetListFromDBAsync` returns an `object` it should probably be modified to be generic so you don't have to cast by hand – Panagiotis Kanavos Jul 19 '23 at 14:07
  • @Clemens JonasH wrote a good answer and I have to import some Excel files that contained non-visible characters in a numeric field – Panagiotis Kanavos Jul 19 '23 at 14:27
  • "var result = task.Result;" NO !!! (See Fildor's comment "You NEED to go async ALL THE WAY". – granadaCoder Jul 19 '23 at 19:48

1 Answers1

4

The typical solution is to use await

public async Task ShowRowsInDatagridview(List<MyObjects> listRowsToQueryDB)
{
    var result = await client.GetListFromDBAsync(listRowsToQueryDB);
    var myObjectsList = (List<MyObjects>)result;

    DisplayInTheDatagridview(myObjectsList);
}

This achieves the objective of running DisplayInTheDatagridview after the database call has completed, while letting the UI thread be free to do other stuff while the db call completes. This assumes your database is actually async, and are not just faking it.

Make sure to await ShowRowsInDatagridview from whenever it is called, and make sure that method also returns a task. If you reach an event handler where you cannot return a task you should make the method async void, but make sure to catch and handle any exceptions that occur while calling the database.

If you want to block the UI while the db call is in progress you can do things like disable buttons until the call completes, or show a modal dialog to prevent the UI from being used.

Clemens
  • 123,504
  • 12
  • 155
  • 268
JonasH
  • 28,608
  • 2
  • 10
  • 23
  • Thank you for the answer. I would like the methods in Winform to not be changed to async. Now it looks like I will have to make many methods async because they again call on a async method. For example the methods that call on ShowRowsInDatagridview and then the methods that call on those methods. Is there a way for a sync method to call an async method and wait til the result is finished? – Tech develop Jul 19 '23 at 14:18
  • It worked now without awaiting ShowRowsInDatagridview but just with the code you wrote. Is this still safe or could I end up getting the same problem again? I would like to change as few methods in Winform as possible to async. – Tech develop Jul 19 '23 at 14:25
  • 2
    @Techdevelop: *"Now it looks like I will have to make many methods async because they again call on a async method."* - Didn't those methods **already** have to change in order to **add** the call to an `async` operation? That's when the method itself should have been changed to `async`. It sounds like the "make many changes" task was already approved and expected, but that the correct changes weren't actually made. The "sync over async" pattern is the wrong approach to the problem of not having properly used `async` in the first place. – David Jul 19 '23 at 14:25
  • The method that call ShowRowsInDatagridview and the method those calls are inn are still sync methods. I only changed ShowRowsInDatagridview to async and I don't have any await on the actual ShowRowsInDatagridview method. – Tech develop Jul 19 '23 at 14:30
  • 1
    @Techdevelop `.Wait()` should do just that, but it is really not recommended since it will block the UI thread, and that will impact user experience. Note that if your results are empty, it is possible that your db query is incorrect, and your problems are unrelated to sync/async. – JonasH Jul 19 '23 at 14:34