我只想分享这些我能够编写的方法扩展,并根据@Jimi 回答关于EventInfo 用法的建议,使其适用于System.ComponentModel.Component 类,以及他的回答:
-
Component.GetEvent(String, Boolean) As EventInfo
-
Component.TryGetEvent(String, Boolean) As EventInfo
-
Component.GetEvents(Boolean) As IReadOnlyCollection(Of EventInfo)
-
Component.GetSubscribedEvents(Boolean) As IReadOnlyCollection(Of EventInfo)
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets all the events declared in the source <see cref="Component"/>.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <example> This is a code example.
''' <code language="VB.NET">
''' Dim ctrl As New Button()
''' Dim events As IReadOnlyCollection(Of EventInfo) = ctrl.GetEvents(declaredOnly:=True)
'''
''' For Each ev As EventInfo In events
''' Console.WriteLine($"Event Name: {ev.Name}")
''' Next
''' </code>
''' </example>
''' ----------------------------------------------------------------------------------------------------
''' <param name="component">
''' The source <see cref="Component"/>.
''' </param>
'''
''' <param name="declaredOnly">
''' If <see langword="True"/>, only events declared at the
''' level of the supplied type's hierarchy should be considered.
''' Inherited events are not considered.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' All the events declared in the source <see cref="Component"/>
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
<Extension>
<EditorBrowsable(EditorBrowsableState.Always)>
Public Function GetEvents(component As Component, declaredOnly As Boolean) As IReadOnlyCollection(Of EventInfo)
If declaredOnly Then
Const flags As BindingFlags = BindingFlags.DeclaredOnly Or
BindingFlags.Instance Or
BindingFlags.Public Or
BindingFlags.NonPublic
Return (From ev As EventInfo In component.GetType().GetEvents(flags)
Order By ev.Name Ascending).ToList()
Else
Return (From ev As EventInfo In component.GetType().GetEvents()
Order By ev.Name Ascending).ToList()
End If
End Function
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets a list of events declared in the source <see cref="Component"/>
''' that are subscribed to a event-handler.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <example> This is a code example.
''' <code language="VB.NET">
''' Dim ctrl As New Button()
''' AddHandler ctrl.Click, Sub() Console.WriteLine("Test")
''' AddHandler ctrl.DoubleClick, Sub() Console.WriteLine("Test") ' declaredOnly:=True
'''
''' Dim subscribedEvents As IReadOnlyCollection(Of EventInfo) = ctrl.GetSubscribedEvents(declaredOnly:=True)
''' For Each ev As EventInfo In subscribedEvents
''' Console.WriteLine($"Event Name: {ev.Name}")
''' Next ev
''' </code>
''' </example>
''' ----------------------------------------------------------------------------------------------------
''' <param name="component">
''' The source <see cref="Component"/>.
''' </param>
'''
''' <param name="declaredOnly">
''' If <see langword="True"/>, only events declared at the
''' level of the supplied type's hierarchy should be considered.
''' Inherited events are not considered.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' A list of events declared in the source <see cref="Component"/>
''' that are subscribed to a event-handler.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
<Extension>
<EditorBrowsable(EditorBrowsableState.Always)>
Public Function GetSubscribedEvents(component As Component, declaredOnly As Boolean) As IReadOnlyCollection(Of EventInfo)
Dim events As IReadOnlyCollection(Of EventInfo) =
GetEvents(component, declaredOnly)
Dim subscribedEvents As New List(Of EventInfo)
For Each ev As EventInfo In events
If component.GetEventHandlers(ev.Name).Any() Then
subscribedEvents.Add(ev)
End If
Next ev
Return subscribedEvents
End Function
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets a <see cref="EventInfo"/> that match the specified event name
''' declared in the source <see cref="Component"/>.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <example> This is a code example.
''' <code language="VB.NET">
''' Dim ctrl As New Button()
'''
''' Dim ev As EventInfo
''' Try
''' ev = ctrl.GetEvent(NameOf(Button.MouseDoubleClick), declaredOnly:=True)
''' Console.WriteLine($"Event Name: {ev.Name}")
'''
''' Catch ex As ArgumentException When ex.ParamName = "eventName"
''' Console.WriteLine($"No event found matching the supplied name: {ev.Name}")
'''
''' End Try
''' </code>
''' </example>
''' ----------------------------------------------------------------------------------------------------
''' <param name="component">
''' The source <see cref="Component"/>.
''' </param>
'''
''' <param name="eventName">
''' The name of the event.
''' </param>
'''
''' <param name="declaredOnly">
''' If <see langword="True"/>, only events declared at the
''' level of the supplied type's hierarchy should be considered.
''' Inherited events are not considered.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <exception cref="ArgumentException">
''' No event found matching the supplied name: {eventName},
''' </exception>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' The resulting <see cref="EventInfo"/>
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
<Extension>
<EditorBrowsable(EditorBrowsableState.Always)>
Public Function GetEvent(component As Component, eventName As String, declaredOnly As Boolean) As EventInfo
Dim ev As EventInfo = TryGetEvent(component, eventName, declaredOnly)
If ev Is Nothing Then
Throw New ArgumentException($"No event found matching the supplied name: {eventName}", paramName:=NameOf(eventName))
End If
Return ev
End Function
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Tries to get a <see cref="EventInfo"/> that match the specified event name
''' declared in the source <see cref="Component"/>.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <example> This is a code example.
''' <code language="VB.NET">
''' Dim ctrl As New Button()
''' Dim ev As EventInfo = ctrl.TryGetEvent(NameOf(Button.MouseDoubleClick), declaredOnly:=True)
''' If ev IsNot Nothing Then
''' Console.WriteLine($"Event Name: {ev.Name}")
''' Else
''' Console.WriteLine($"No event found matching the supplied name: {ev.Name}")
''' End If
''' </code>
''' </example>
''' ----------------------------------------------------------------------------------------------------
''' <param name="component">
''' The source <see cref="Component"/>.
''' </param>
'''
''' <param name="eventName">
''' The name of the event.
''' </param>
'''
''' <param name="declaredOnly">
''' If <see langword="True"/>, only events declared at the
''' level of the supplied type's hierarchy should be considered.
''' Inherited events are not considered.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' The resulting <see cref="EventInfo"/>,
''' or <see langword="Nothing"/> (null) if no event found matching the supplied name.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
<Extension>
<EditorBrowsable(EditorBrowsableState.Always)>
Public Function TryGetEvent(component As Component, eventName As String, declaredOnly As Boolean) As EventInfo
Dim events As IReadOnlyCollection(Of EventInfo) =
GetEvents(component, declaredOnly)
Return (From ev As EventInfo In events
Where ev.Name.Equals(eventName, StringComparison.OrdinalIgnoreCase)
).SingleOrDefault()
End Function
另外,我编写了一个辅助函数来获取事件字段名称的可能变体列表(如果与此结合使用,这是必不可少的:Get all the event-handlers of a event declared in a custom user-control)
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets a list of possible variants for an event field name.
''' <para></para>
''' Example event name: ValueChanged
''' <para></para>
''' Result field names: EventValueChanged, EventValue, EVENT_VALUECHANGED, EVENT_VALUE, ValueChangedEvent, ValueEvent
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <param name="eventName">
''' The name of the event.
''' <para></para>
''' Note: the name is case-insensitive.
''' </param>
'''
''' <returns>
''' A list of possible variants for an event field name.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Private Function GetEventFieldNameVariants(eventName As String) As IReadOnlyCollection(Of String)
' Example input event name:
' ValueChanged
'
' Resulting field names:
' EventValueChanged, EventValue (Fields declared in 'System.Windows.Forms.Control' class.)
' EVENT_VALUECHANGED, EVENT_VALUE (Fields declared in 'System.Windows.Forms.Form' class.)
' ValueChangedEvent, ValueEvent (Fields (auto-generated) declared in other classes.)
Dim names As New List(Of String) From {
$"Event{eventName}", ' EventName
$"EVENT_{eventName.ToUpper()}", ' EVENT_NAME
$"{eventName}Event" ' NameEvent
}
If eventName.EndsWith("Changed", StringComparison.OrdinalIgnoreCase) Then
names.Add($"Event{eventName.RemoveEnd(0, 7)}") ' EventName
names.Add($"EVENT_{eventName.RemoveEnd(0, 7).ToUpper()}") ' EVENT_NAME
names.Add($"{eventName.RemoveEnd(0, 7)}Event") ' NameEvent
End If
Return names
End Function
Public Function RemoveEnd(input As String, startIndex As Integer, length As Integer) As String
Return source.Remove((input.Length - startIndex - length), length)
End Function