4

I'm new to c# async await mechanism. I have checked all the previous examples of async, await but none of them is exactly like mine. what I would like to do? I have a foreach loop and I would like to stop it on a certain rule, do some stuff and continue running by clicking on a button. Here is simple code example:

private void RunConvert()  // START 
{
    foreach (PartSettings File in PartsFromXLS)  // RUNING THE FOREACH LOOP ON A LIST
    {
        ProcessSinglePart(PathStep, PathMCX);
    }
}

public static async void ProcessSinglePart(string PartPathToRead, string PartPathToSave)
{
    // DO SOME STUFF BEFORE THE CHECK

    if (PartLength < PartWidth) // SOME CHECK VALUES
    {
         await WhenClicked();  //HERE I WOULD LIKE TO WAIT FOR BUTTON CLICK
    }

    //DO SOME STUFF AFTER THE CHECK
}

private void GeometryOK_Click(object sender, EventArgs e) 
{
    //  I WOULD LIKE TO WAIT FOR THIS CLICK
}
Hossein Golshani
  • 1,847
  • 5
  • 16
  • 27
Primoz Krzic
  • 49
  • 1
  • 2
  • 2
    `await` != "wait for". – dymanoid Oct 08 '18 at 16:10
  • 2
    There's *a lot* wrong here, to be honest. For one thing, async/await has nothing to do with waiting for the user to click a button. So the fundamental nature of what you're asking is based on a misunderstanding on your part. So we can't even really answer what you're asking. Additionally, `async void` is a *very bad idea*. It only exists for backward compatability with WinForms event handlers and really *really* shouldn't be used outside of those. (And even with those should be used very very carefully.) – David Oct 08 '18 at 16:11
  • 1
    @dymanoid On the contrary, that's *exactly* what await does. "Wait for this task to complete" – BradleyDotNET Oct 08 '18 at 16:17
  • @David You need to know about `TaskCompletionSource` but this is totally possible. – BradleyDotNET Oct 08 '18 at 16:31
  • @BradleyDotNET: That's pretty awesome actually, and indeed something I've not encountered before. Though would there be problems if the "task" in this case never completes? (That is, if the button is never pressed?) It still *feels* to me like using the wrong tool for the job. Though I guess I haven't looked into this implementation enough to articulate more than that. Perhaps I'm just very accustomed to signaling a worker thread for something like this. – David Oct 08 '18 at 16:39
  • 1
    @David you can use a `TimeoutAfter` extension to Task (not hard to write) to solve that problem, but yes it is a potential issue. I use this technique a lot in doing asynchronous messaging between processes. The "signaling a worker thread" has the same problem if it is never signaled :D – BradleyDotNET Oct 08 '18 at 16:41

1 Answers1

7

await suspends execution of a method until the argument (which must be a Tasklike, in practice, its just a Task or Task<T>) completes. Your issue is actually one that I've run into a number of times:

How to asynchronously wait for some event to be fired

In your case "some event" is a button click. Luckily, TaskCompletionSource<T> (hereafter, TCS) is pretty much ideal for solving this. First declare a TCS at the class level:

private TaskCompletionSource<bool> clickWaitTask;

There's no non-generic version of a TCS so I usually just use bool. We don't actually care about the data in this case. Then your method looks like this (explanation to follow):

public static async void ProcessSinglePart(string PartPathToRead, string PartPathToSave)
{
    // DO SOME STUFF BEFORE THE CHECK
    clickWaitTask = new TaskCompletionSource<bool>();

    if (PartLength < PartWidth) // SOME CHECK VALUES
    {
         await clickWaitTask.Task;
    }

    //DO SOME STUFF AFTER THE CHECK
}

You create a new TCS so that each time this logic is run, it will wait for the click to occur. Then you await the Task property (which is, in fact, a Task<T>). That task will only complete when TrySetResult is called on the TCS object. Do that in your button click handler (or command handler for WPF):

 clickWaitTask.TrySetResult(true); //Value does not matter

As a commenter noted, you shouldn't use async void unless you are in a event handler, and should have try/catch around the method in that case to avoid some nastiness with unhandled exceptions. I'm also extremely wary of your public static but that's a separate problem.

BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117