我正在开发 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;
,而不会等待先前的完成调用(但已经等待它!)
这是怎么回事?
答案 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);
}
}