2

I have a simple Form with buton and one event button1_Click:

public Form1 : Form
{
    public Form1()
    {
        ...
        this.button1.Click += new System.EventHandler(this.button1_Click);
    }

    private async Task button1_Click(object sender, EventArgs e) // line A
    {
    }
}

In line A I would like to try use async Task return type rather than void and I encounter error message from compiler. How I can make this code run?

Piotr Wojcik
  • 95
  • 1
  • 17
  • 6
    You can use `asyns void` in an event handler. [Async/Await - Best Practices in Asynchronous Programming](https://msdn.microsoft.com/en-us/magazine/jj991977.aspx?f=255&MSPPError=-2147217396). – Jimi Nov 09 '18 at 10:53

4 Answers4

2

That event handler is a delegate with void return type, which means you can't add methods with Task result to it.

However you can also mark void methods with async so you should just replace the Task with void.

Péter Csajtai
  • 878
  • 6
  • 9
  • async void is a bad practice. In multi-thread programming it has a flow. Please read the circumstances of async with void – Hassaan Nov 09 '18 at 11:03
  • 2
    You don't have a chance to use anything else with void event handlers and in wpf and winforms you only have those. It can be dangerous if you don't know what are you doing and how it should be used, but it's true for anything else too. – Péter Csajtai Nov 09 '18 at 11:20
1

I think bellow proposition is nice and functional. However it's break sometimes forms in the DevExpress Design mode. So I put my solution to futher discussion:

public Form1 : Form
{
    public Form1()
    {
        ...
        this.button1.Click += 
             new System.EventHandler(
                 async (sender, events) => await this.button1_Click(sender, events)
             );
    }

    private async Task button1_Click(object sender, EventArgs e) // line A
    {
    }
}
Piotr Wojcik
  • 95
  • 1
  • 17
0

How I can make this code run?

It cannot be done because the async Task signature is not implemented for UI event handlers in .net. (make sure to read this post: Why do event handlers always have a return type of void?)

The general consensus is that, in general, a return value of an event handler has not a well defined purpose. Although IMO it would make sense to be able to fire off all the handlers async, but then again, that would be exactly the case if you wouldn't await the logic inside it.

Of course you could overcome the problem by putting the event logic in another class. Most of the time this is actual a good idea anyhow.

Note: do not use it like this, it's just to explain it

public Form1 : Form
{
    public Form1()
    {
        ...
        this.button1.Click += new System.EventHandler(this.button1_Click);
    }

    private async void button1_Click(object sender, EventArgs e) // line A
    {
        await YourLogic(e.foo); //optional configure await.
    }

    private async Task YourLogic(your parameters)
    {
        // do stuff
    }
}

See also:

Why do event handlers always have a return type of void?

async/await - when to return a Task vs void?

https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

How do I await events in C#?


How to make form events to use benefits from async?

So, basically it already does, but check out this post: How to 'await' raising an EventHandler event

Community
  • 1
  • 1
Stefan
  • 17,448
  • 11
  • 60
  • 79
  • 1
    Does await make this asonchrynous call synchronous? Async make promise that YourLogic would be finished but soon as you call that method you simply wait until YourLogic finish. – Piotr Wojcik Nov 09 '18 at 12:18
  • 1
    That's a bit of a trick question. In short: what `await` does, is that it executes the code async (so your ui remains responsive) but resumes from that point afterward. It is like having your function split up into 2 parts. – Stefan Nov 09 '18 at 12:44
0

We can check this code:

 public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        this.button1.Click += (s, e) => Button1_Click(s, e);
        //this.button1.Click += Button1_Click1;
        MessageBox.Show("The End!");
    }
    private async Task Button1_Click(object sender, EventArgs e)
    {
        await Task.Delay(5000);
        MessageBox.Show("With Sync");
    }

    private void Button1_Click1(object sender, EventArgs e)
    {
        MessageBox.Show("Without async");
    }
}
ideepak04
  • 36
  • 4
  • 1
    This is just obscuring the fact that the event handler is void returning by making it an anonymous method. You still have the void event handier. This is in fact *far* worse, as it behaves the same but could very easily mislead the reader into thinking this *isn't* a fire and forget operation when it in fact is. – Servy Nov 09 '18 at 14:21