Clarification for Await/Async and Task

Recently I've started working with multithreading and have been trying to better understand await/async and Task. I've typed up the following scenario:

private void button1_Click(object sender, EventArgs e)
{
    var list = GenerateList();
    progressBar1.Maximum = list.Count ();

    CreateStuff (list));
    MessageBox.Show ("Complete!");
}

async void CreateStuff (List<int> list)
{
    //additional Parameters here used for DoWork()
    await Task.Run (()=>Parallel.ForEach(list, item =>
    {
        DoWork();
        Invoke(new Action(() => progressBar1.PerformStep()));
    }));
    //do something that relies on list
}

I'm trying to make the message box appear after the completion of the CreateDocs method. I was told by a peer that it was possible to keep using await async in the CreateStuff() method and still wait until the method is compelte before I show the message box. I've been researching await async and Task for a while and can't seem to figure out how to do this.

To me, it seems much easier to make the button1_Click() use await async, then await the CreateStuff() method.

My question is this: Is it possible to keep using await async in the CreateStuff method and still wait for the completion of the CreateStuff() method in button1_Click() before displaying the message box?

I'm assuming that it has to do with returning the Task, but I can't quite figure out how to progress about it.

Any help is appreciated. Thanks!

Jon Skeet
people
quotationmark

My question is this: Is it possible to keep using await async in the CreateStuff method and still wait for the completion of the CreateStuff() method in button1_Click() before displaying the message box?

Absolutely - but you need to change the return type of CreateStuff first. Currently you're returning void, which is almost never a good idea - it's really only there for event handlers. All you need to do is change it to return Task, and you can await it:

async Task CreateStuff (List<int> list)

Then in your click handler (which needs to be async too), await the result of calling it:

await CreateStuff (list);

It's not at all clear that the implementation of CreateStuff is really ideal, mind you. You don't need an async method for that - you could just have:

Task CreateStuff(List<int> list)
{
    return Task.Run(() => Parallel.ForEach(list, item =>
    {
        DoWork();
        Invoke(new Action(() => progressBar1.PerformStep()));
    }));
}

There's not a lot of point having an async method which exists just to create a task and await it, when you can just return the task and let the calling code await that instead. (They do behave slightly differently in a few ways, but not in any way which is important in this particular case, I suspect.)

people

See more on this question at Stackoverflow