如何检查分配了哪些事件?

Roh*_*hit 3 c# reflection controls winforms

我的代码如下。

Control[] FoundControls = null;
FoundControls = MyFunctionToFilter(TF, c => c.Name != null && c.Name.StartsWith("grid"));
var eventinfo = FoundControls[0].GetType().GetEvents();
Run Code Online (Sandbox Code Playgroud)

但是,eventinfo 为我提供了属于网格的所有控件的列表。而主类中只定义了两个事件:KeyDownValidating 。

如何获取这些指定事件的列表,即 Keydown 和 Validating?

Ser*_*kiy 5

Windows 窗体(WinForms) 有一个复杂的组件事件模型(并且它DataGridView是一个组件)。有些事件继承自Control(例如FontChanged,,ForeColorChanged等),但所有特定于组件事件都存储在单个EventHandlerList对象中,该对象继承自Component(顺便说一句,来自Control的事件也存储在那里,请参阅最后的更新回答)。有一个受保护的Events财产:

protected EventHandlerList Events
{
    get
    {
        if (this.events == null)            
            this.events = new EventHandlerList(this);            
        return this.events;
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是为事件添加事件处理程序的方式DataGridView

public event DataGridViewCellEventHandler CellValueChanged
{
    add { Events.AddHandler(EVENT_DATAGRIDVIEWCELLVALUECHANGED, value); }
    remove { Events.RemoveHandler(EVENT_DATAGRIDVIEWCELLVALUECHANGED, value); }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,委托(值)被传递给EventHandlerList一些键值。所有事件处理程序都通过键存储在那里。您可以将其视为EventHandlerList一个字典,其中对象作为键,委托作为值。因此,以下是如何通过反射获取组件的事件。第一步是获取这些密钥。正如您已经注意到的,它们被命名为EVENT_XXX

private static readonly object EVENT_DATAGRIDVIEWCELLVALUECHANGED;
private static readonly object EVENT_DATAGRIDVIEWCELLMOUSEUP;
// etc.
Run Code Online (Sandbox Code Playgroud)

那么我们开始吧:

var keys = typeof(DataGridView) // You can use `GetType()` of component object.
   .GetFields(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy)
   .Where(f => f.Name.StartsWith("EVENT_"));
Run Code Online (Sandbox Code Playgroud)

接下来,我们需要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;
Run Code Online (Sandbox Code Playgroud)

最后一步,获取带有附加处理程序的键列表:

var result = keys.Where(f => handlers[f.GetValue(null)] != null)
                 .ToList();
Run Code Online (Sandbox Code Playgroud)

这会给你钥匙。如果您需要委托,只需在处理程序列表中查找即可。

更新:继承自的事件Control也存储在 中EventHandlerList,但由于某些未知原因,它们的键具有不同的名称,例如EventForeColor。您可以使用与上面相同的方法来获取这些密钥并检查是否附加了处理程序。