awaitng异步事件处理程序不等待方法继续

时间:2018-07-09 10:48:15

标签: c# asynchronous async-await

我正在开发 WinForms应用程序。 我创建了一个自定义控件(继承自 Control 类)。它具有自己的事件处理程序,以允许表单观察某些事件。

public  event EventHandler<TextBoxFilterEventArgs> DataGetFiltered;

在某些特定情况下,我在控件内打电话给已注册的接收方时,出现了我的问题:

this.Enabled=false;
if (DataGetFiltered != null)
   DataGetFiltered(this, new TextBoxFilterEventArgs(itemsFiltered));
this.Enabled=true;

您可以看到我在通话前后将控件设置为禁用/启用。 包含控件的表单正在以异步方式向该事件注册一些方法:

txtFilter.DataGetFiltered += async (s, e) => await txtFilterByDesc_DataGetFiltered(s, e);

private async Task txtFilterByDesc_DataGetFiltered(object sender, TextBoxFilterEventArgs e)
{
     await Task.Run(()=>/*some code*/);
}

会发生什么? 该控件调用已注册的事件处理程序,但它会继续运行this.Enabled=true;,而不会等待先前的完成调用(但已经等待它!) 这是怎么回事?

2 个答案:

答案 0 :(得分:2)

  

会发生什么?

禁用控制后,事件处理代码将运行异步委托。
委托最终调用Task.Run,并将一些工作转移到线程池线程中。 然后,委托返回,并再次启用控制,但是计划任务仍在后台运行。

  

该控件是一个文本框,我希望在处理事件处理程序时将其启用/禁用。我必须将该逻辑移至处理程序本身吗?

简短的回答:是的。

更详细的答案:使用标准的.NET事件处理模式时,必须将此逻辑移至事件处理程序中。事件不知道处理程序的实现。它们可以是同步的,也可以是异步的。因此,您所要做的就是让事件处理程序管理Enabled属性。

从技术上讲,您可以发明某种异步事件处理程序,但实际上不应该。 .NET开发人员知道,事件委托的类型为EventHandler / EventHandler<T>。自定义事件委托类型会破坏众所周知的模式。

答案 1 :(得分:1)

我认为这是因为您的事件处理程序使用await,但是您的调用方法并不等待处理程序!因此,您需要创建自己的返回Task的事件,如下所示:

public delegate Task DataGetFiltered(object sender, TextBoxFilterEventArgs e);
public event DataGetFiltered OnDataGetFiltered;

在被调用的方法中:

if (null != this.OnDataGetFiltered)
{
    var args = new TextBoxFilterEventArgs(itemsFiltered);
    foreach (var handler in this.OnDataGetFiltered.GetInvocationList().Cast<DataGetFiltered>())
    {
        await handler(this, args);
    }
}