none
イベントの存在チェック RRS feed

  • 質問

  • VisualBasic2005であるイベントになにかメソッドが登録されているかどうかチェックする方法はあるのでしょうか?

    コレクションにアイテムを登録する時にアイテムの特定のイベントにメソッドが登録されていることを要求したり、イベントがない場合はイベントパラメータの作成処理を省いたりしたいのです。

    C#ではできるようなのですがVBにはないのでしょうか?

     

    2007年9月4日 1:44

回答

  • 海鶏さんこんにちは

    以下のURLを参考に作ってみました。

    http://www.technewsgroups.net/group/microsoft.public.dotnet.general/topic4196.aspx

    試されるときはForm1にボタンを2つ作ってください。

    Button2のClickイベントのハンドラが2つであることが検出できます。

    Code Snippet

    Imports system.componentmodel
    Imports system.Reflection

    Public Class Form1
      Private Shared ReadOnly Property All() As BindingFlags
        Get
          Return BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.IgnoreCase Or BindingFlags.Static
        End Get
      End Property

      Private Shared Function GetEventsMethod(ByVal objType As Type) As MethodInfo
        Dim mi As MethodInfo = objType.GetMethod("get_Events", All)
        If mi Is Nothing And Not (objType.BaseType Is Nothing) Then
          mi = GetEventsMethod(objType.BaseType)
        End If
        Return mi
      End Function 'GetEventsMethod

      Private Shared Function GetEvents(ByVal obj As Object) As EventHandlerList
        Dim mi As MethodInfo = GetEventsMethod(obj.GetType())
        If mi Is Nothing Then Return Nothing
        Return CType(mi.Invoke(obj, New Object() {}), EventHandlerList)
      End Function 'GetEvents

      Private Shared Function GetEventIDField(ByVal objType As Type, ByVal eventName As String) As FieldInfo
        Dim fi As FieldInfo = objType.GetField("Event" + eventName, All)
        If fi Is Nothing And Not (objType.BaseType Is Nothing) Then
          fi = GetEventIDField(objType.BaseType, eventName)
        End If
        Return fi
      End Function 'GetEventIDField

      Private Shared Function GetEventID(ByVal obj As Object, ByVal eventName As String) As Object
        Dim fi As FieldInfo = GetEventIDField(obj.GetType(), eventName)
        If fi Is Nothing Then Return Nothing
        Return fi.GetValue(obj)
      End Function 'GetEventID

      Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim list As EventHandlerList = GetEvents(Button2)
        Dim key As Object = GetEventID(Button2, "Click")
        Debug.Print(list(key).GetInvocationList.GetLength(0).ToString)
      End Sub

      Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click, Button2.Click
        'ダミー
      End Sub
    End Class

     

     

    もし、海鶏さんが既にC#のコードサンプルを見つけておられたのであれば、例えば以下のURLを使ってVisual Basicに変換してみることができます。

    http://authors.aspalliance.com/aldotnet/examples/translate.aspx

     

    2007年9月4日 8:32

すべての返信

  • 海鶏さんこんにちは

    以下のURLを参考に作ってみました。

    http://www.technewsgroups.net/group/microsoft.public.dotnet.general/topic4196.aspx

    試されるときはForm1にボタンを2つ作ってください。

    Button2のClickイベントのハンドラが2つであることが検出できます。

    Code Snippet

    Imports system.componentmodel
    Imports system.Reflection

    Public Class Form1
      Private Shared ReadOnly Property All() As BindingFlags
        Get
          Return BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.IgnoreCase Or BindingFlags.Static
        End Get
      End Property

      Private Shared Function GetEventsMethod(ByVal objType As Type) As MethodInfo
        Dim mi As MethodInfo = objType.GetMethod("get_Events", All)
        If mi Is Nothing And Not (objType.BaseType Is Nothing) Then
          mi = GetEventsMethod(objType.BaseType)
        End If
        Return mi
      End Function 'GetEventsMethod

      Private Shared Function GetEvents(ByVal obj As Object) As EventHandlerList
        Dim mi As MethodInfo = GetEventsMethod(obj.GetType())
        If mi Is Nothing Then Return Nothing
        Return CType(mi.Invoke(obj, New Object() {}), EventHandlerList)
      End Function 'GetEvents

      Private Shared Function GetEventIDField(ByVal objType As Type, ByVal eventName As String) As FieldInfo
        Dim fi As FieldInfo = objType.GetField("Event" + eventName, All)
        If fi Is Nothing And Not (objType.BaseType Is Nothing) Then
          fi = GetEventIDField(objType.BaseType, eventName)
        End If
        Return fi
      End Function 'GetEventIDField

      Private Shared Function GetEventID(ByVal obj As Object, ByVal eventName As String) As Object
        Dim fi As FieldInfo = GetEventIDField(obj.GetType(), eventName)
        If fi Is Nothing Then Return Nothing
        Return fi.GetValue(obj)
      End Function 'GetEventID

      Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim list As EventHandlerList = GetEvents(Button2)
        Dim key As Object = GetEventID(Button2, "Click")
        Debug.Print(list(key).GetInvocationList.GetLength(0).ToString)
      End Sub

      Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click, Button2.Click
        'ダミー
      End Sub
    End Class

     

     

    もし、海鶏さんが既にC#のコードサンプルを見つけておられたのであれば、例えば以下のURLを使ってVisual Basicに変換してみることができます。

    http://authors.aspalliance.com/aldotnet/examples/translate.aspx

     

    2007年9月4日 8:32
  • サンプルコードありがとうございます。

    リフレクションを利用すればいいのとイベントの実装方法により取得方法が違うというのが理解できました。

     

    私が想定していたC#のコードは以下のもので。このような分岐をやりたかったのです。

    Code Snippet

            if(this.OnKeyDown != null)
              this.OnKeyDown(eventCode);
          }

     

     

    今回はEventHandlerのみなので以下の感じでどうにかできそうです。

    Formにボタン1個のサンプル

    Code Snippet

    Imports System.Reflection
    Public Class Form1
        Public Class EventTest
            Public Event Event1 As EventHandler
            Public Event Event2 As EventHandler
            Public Function IsRegistEvent1() As Boolean
                Return Not Event1Event Is Nothing
            End Function
            Public Function IsRegistEvent2() As Boolean
                Return Not Event2Event Is Nothing
            End Function
        End Class
        Public Function IsRegistEvent(ByVal o As Object, ByVal eventName As String) As Boolean
            Dim AllBindingFlags As BindingFlags = BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.IgnoreCase Or BindingFlags.Static Or BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.IgnoreCase Or BindingFlags.Static
            Dim fi As System.Reflection.FieldInfo = o.GetType.GetField(eventName & "Event", AllBindingFlags)
            Dim value As Object = fi.GetValue(o)
            If value Is Nothing Then
                Return False
            Else
                Return True
            End If
        End Function

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim et As EventTest = New EventTest
            AddHandler et.event1, AddressOf Button1_Click

            Debug.WriteLine(IsRegistEvent(et, "Event1"))
            Debug.WriteLine(IsRegistEvent(et, "Event2"))
            Debug.WriteLine(et.IsRegistEvent1)
            Debug.WriteLine(et.IsRegistEvent2)
        End Sub

    End Class

     

    暗黙のイベント用フィールドが存在したのですね。
    2007年9月4日 11:07
  • 海鶏さんのコードを拝見して私のコードを再検証しましたが、イベントが登録されていないときにSystem.NullReferenceExceptionが発生してしまいますね。単純に ○○Event フィールドの値の有無でハンドラが登録されているかどうか判断できることが海鶏さんのコードでわかりました。うまく簡素化されていますね。私も勉強になりました。

     

    2007年9月4日 11:55