'Best Practice winforms async/await keywords
Testing a bit TPL.
I use this code and it works:
async void button1_Click(object sender, EventArgs e)
{
MyClass2 mc2 = new MyClass2();
label1.Text = "Start";
List<string> list = await mc2.GetInfosAsync("test123");
label1.Text = "";
list.ForEach(x => label1.Text += x + "\n");
}
class MyClass2
{
public Task<List<string>> GetInfosAsync(string txt)
{
return Task.Factory.StartNew<List<string>>(() => GetInfos(txt));
}
public List<string> GetInfos(string txt)
{
//doing long-listbuilding-operation
}
}
But I'm wondering if this is best practice of using async and await keywords, I feel a bit uncomfortable by "manipulating" the signature of button1_click
event.
Solution 1:[1]
Using async on windows form event handler is correct and recommended way to do. If you don't use async await, you may see deadlock (unless you are using ConfigureAwait(false)).
Use async await all the way in your code. Don't use Wait() or Result
One important thing, keep all logic in separate method to make unit testable. It will be difficult to test async void. You cannot change method to async Task
// Will result in compilation error
private async Task button1_Click(object sender, EventArgs e)
// Because of event handler signature
public delegate void EventHandler(object sender, EventArgs e);
One good example to handle this is mentioned in msdn article mentioned below
public async void button1_Click(object sender, EventArgs e)
{
await this.ButtonClickHandlerAsync()
}
// Unit test this
public async Task ButtonClickHandlerAsync()
{
MyClass2 mc2 = new MyClass2();
label1.Text = "Start";
List<string> list = await mc2.GetInfosAsync("test123");
label1.Text = "";
list.ForEach(x => label1.Text += x + "\n");
}
More details- https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
PS: I am assuming your question is about "Is using async on winform button click event handler good practice"? Technically async is not part of method signature (only method name and parameters). In case your question is actually about signature then please ignore this answer.
Solution 2:[2]
I implemented this in a solution for login. You can do it like this.
private async void metroButton1_Click(object sender, EventArgs e)
{
string res= await login();
if (res.Equals("true"))
{
this.Hide();
MainMDIParent mdi = new MainMDIParent();
mdi.Show();
btnLogin.Enabled = true;
}
else
{
MessageBox.Show("Invalid User Credentials", "LOgin", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
txtPassword.Text = "";
txtUsername.Text = "";
btnLogin.Enabled = true;
}
}
Solution 3:[3]
There is another approach to achieve this.
Parallel.foreach("list",(currentelement) =>
{
enter code here
});
Basically this will work as async.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Frank Odoom |
Solution 3 | ggeorge |