0

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

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

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

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 关于使用反射的建议最终对我有用。这是最终的功能:

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 行代码。最好的部分是,如果我将来添加任何内容,我不必担心回去添加这个处理程序,它会在运行时得到处理。它可能不是最干净的解决方案,但它最终对我来说效果很好。

4

1 回答 1

4

两种选择:

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

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

    然后,您只需将每个控件传递给委托。

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

于 2013-09-25T17:48:35.210 回答