Windows Forms (WinForms) 有一个复杂的组件事件模型(DataGridView 是一个组件)。一些事件继承自Control(如FontChanged、ForeColorChanged等),但所有特定于组件的事件都存储在单个EventHandlerList对象中,该对象继承自Component(顺便说一句,事件来自控制也存储在那里,请参阅答案末尾的更新)。有一个受保护的Events 属性:
protected EventHandlerList Events
{
get
{
if (this.events == null)
this.events = new EventHandlerList(this);
return this.events;
}
}
下面是为DataGridView 事件添加事件处理程序的方式:
public event DataGridViewCellEventHandler CellValueChanged
{
add { Events.AddHandler(EVENT_DATAGRIDVIEWCELLVALUECHANGED, value); }
remove { Events.RemoveHandler(EVENT_DATAGRIDVIEWCELLVALUECHANGED, value); }
}
如您所见,委托(值)通过一些键值传递给EventHandlerList。所有事件处理程序都按键存储在那里。您可以将EventHandlerList 视为以对象为键、委托为值的字典。所以,这里是如何通过反射获取组件的事件。第一步是获取这些密钥。正如您已经注意到的,它们被命名为EVENT_XXX:
private static readonly object EVENT_DATAGRIDVIEWCELLVALUECHANGED;
private static readonly object EVENT_DATAGRIDVIEWCELLMOUSEUP;
// etc.
所以我们开始吧:
var keys = typeof(DataGridView) // You can use `GetType()` of component object.
.GetFields(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Where(f => f.Name.StartsWith("EVENT_"));
接下来,我们需要我们的EventHandlerList:
var events = typeof(DataGridView) // or GetType()
.GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic);
// Could be null, check that
EventHandlerList handlers = events.GetValue(grid) as EventHandlerList;
最后一步,获取附加了处理程序的键列表:
var result = keys.Where(f => handlers[f.GetValue(null)] != null)
.ToList();
这会给你钥匙。如果您需要委托,则只需在处理程序列表中查找它们即可。
更新:从Control 继承的事件也存储在EventHandlerList 中,但由于某些未知原因,它们的键具有不同的名称,例如EventForeColor。您可以使用与上述相同的方法来获取这些密钥并检查是否附加了处理程序。