在我的Windows Forms应用程序中,我使用PerformClick
调用一个async
事件处理程序时遇到了问题。看起来事件处理程序没有await
,而是立即返回。我创建了这个简单的应用程序来展示这个问题(它只是一个带有3个按钮的表单,容易自行测试):
string message = "Not Started";
private async void button1_Click(object sender, EventArgs e)
{
await MyMethodAsync();
}
private void button2_Click(object sender, EventArgs e)
{
button1.PerformClick();
MessageBox.Show(message);
}
private void button3_Click(object sender, EventArgs e)
{
MessageBox.Show(message);
}
private async Task MyMethodAsync()
{
message = "Started";
await Task.Delay(2000);
message = "Finished";
}
这里有个有趣的问题,当我点击
Button2
时,你认为message
会显示什么?令人惊讶的是,它显示"Started"而不是"Finished",这与你预期的不同。换句话说,它并没有等待
await MyMethod()
,而只是启动了任务,然后继续执行。
编辑:
在这个简单的代码中,我可以通过直接从Button2事件处理程序调用await Method()
来使它起作用,像这样:private async void button2_Click(object sender, EventArgs e)
{
await MyMethodAsync();
MessageBox.Show(message);
}
现在,它等待2秒并显示“完成”。
这是怎么回事?为什么使用PerformClick
时它不起作用?
结论:
好的,现在我明白了,结论如下:
如果事件处理程序是
async
,则永远不要调用PerformClick
。它不会await
!永远不要直接调用
async
事件处理程序。它不会await
!
剩下的是缺乏关于此的文档:
Button.PerformClick
应该在文档页面上有一个警告:
Button.PerformClick "调用PerformClick将不会等待异步事件处理程序。"
- 调用
async void
方法(或事件处理程序)应该给出编译器警告:“您正在调用一个async void方法,它将不会被等待!”
await MyMethodAsync();
时,系统会检查MyMethodAsync
是否已返回。由于Task.Delay(2000);
的存在,它尚未返回,因此继续回到button2_Click
并打印“Started”。当然,message = "Started";
已经执行过了。 - γηράσκω δ' αεί πολλά διδασκόμε