使用AddHandler时是否可以动态指定事件类型?

时间:2013-09-25 17:36:30

标签: vb.net events reflection event-handling system.reflection

我正在尝试编写一个聪明的小函数,它将指定的委托作为事件处理程序添加到任何动态事件的集合中的所有控件。我想要做的是将它写成一个完全通用的函数,以便我可以在各种不同的项目中使用它(可能包含在某种工具库中)。

基本上我想指定一组控件,处理事件的委托以及要处理的事件类型。我遇到的问题是我无法弄清楚如何在运行时动态指定事件。

这是我的“正在进行中的工作”子目录:

Private Sub AddHandlerToControls(controlList As ControlCollection, eventToHandle As EventHandler, eventHandlerDelegate As Func(Of Object, EventArgs), Optional filterList As List(Of Type) = {})
    For Each controlInList As Control In controlList
        If controlInList.HasChildren Then
            AddHandlerToControls(controlInList.Controls, controlInList.MouseEnter, eventHandlerDelegate, filterList)
        End If
        If filterList.Count > 0 Then
            If filterList.Contains(controlInList.GetType) = False Then
                Continue For
            End If
        End If
        AddHandler controlInList.MouseEnter, eventHandlerDelegate
    Next
End Sub

理想情况下,我想在eventToHandle语句的末尾使用AddHandler参数,而不是专门使用controlInList.MouseEnter。像这样:

AddHandler eventToHandle, eventHandlerDelegate

这样我就可以在form.load方法中动态调用这个函数,并且调用它就像我之前在sub中所做的那样,它递归地为子控件调用它自己。不知何故说“对于这个控件列表,我想将此委托用作'MouseEnter'事件处理程序”。像所以:

AddHandlerToControls(Me.Controls, control.MouseEnter, MouseEnterHandlerDelegate, new List(Of Type) {TextBox, ComboBox})

这可能只是一厢情愿的想法,我开始认为这在“通用性”这个层面上是不可能的,但这是一个有趣的问题,我认为我至少应该问。

编辑解决方案:

Jon Skeet建议使用Reflection最终为我工作。这是最后的功能:

Private Shared Sub AddHandlerToControls(controlList As Control.ControlCollection, eventToHandle As String, eventHandlerDelegate As MethodInfo, Optional filterList As List(Of Type) = Nothing)
    For Each controlInList As Control In controlList
        If controlInList.HasChildren Then
            AddHandlerToControls(controlInList.Controls, eventToHandle, eventHandlerDelegate, filterList)
        End If
        If Not filterList Is Nothing Then
            If filterList.Contains(controlInList.GetType) = False Then
                Continue For
            End If
        End If

        Dim dynamicEventInfo As EventInfo = controlInList.GetType.GetEvent(eventToHandle)
        Dim handlerType As Type = dynamicEventInfo.EventHandlerType
        Dim eventDelegate As [Delegate] = [Delegate].CreateDelegate(handlerType, eventHandlerDelegate)
        dynamicEventInfo.AddEventHandler(controlInList, eventDelegate)
    Next
End Sub

我如何称呼它和使用的代表:

AddHandlerToControls(Controls, "MouseClick", GetType(MainFrm).GetMethod("MouseClickEventDelegate"), New List(Of Type) From {GetType(TextBox), GetType(ComboBox)})

Shared Sub MouseClickEventDelegate(sender As Object, eventArgs As EventArgs)
    sender.SelectAll()
End Sub

这允许我在我的表单上设置所有文本框和组合框(有很多)在点击时选择所有文本,大约20行代码。最好的部分是,如果我将来添加任何内容,我将不必担心返回添加此处理程序,它将在运行时处理。它可能不是最干净的解决方案,但最终对我来说效果很好。

1 个答案:

答案 0 :(得分:4)

两个选项:

  • 通过lambda表达式指定“订阅委托”。我不想猜测这在VB中会是什么样子,但在C#中它会是这样的:

    (control, handler) => control.MouseEnter += handler;
    

    然后你只需要将每个控件传递给委托。

  • 将事件名称指定为字符串,并使用反射来获取事件并订阅(Type.GetEvent然后EventInfo.AddEventHandler)。