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の最後にあるパラメーターを使用したいと思います。このような:AddHandlercontrolInList.MouseEnter

AddHandler eventToHandle, eventHandlerDelegate

そうすれば、この関数を form.load メソッドで動的に呼び出すことができ、以前に子コントロールに対して自分自身を再帰的に呼び出すサブで行った方法と同じように呼び出すことができます。どういうわけか、「このコントロールのリストでは、このデリゲートを 'MouseEnter' イベント ハンドラーとして使用したい」と言います。そのようです:

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

これはただの希望的観測かもしれません。このレベルの「汎用性」ではこれはまったく不可能だと思い始めていますが、少なくとも質問する必要があると考えた十分に興味深い問題です。

ソリューションの編集:

Reflection を使用するという 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

2 つのオプション:

  • ラムダ式を介して「サブスクリプション デリゲート」を指定します。これが VB でどのようになるかは推測したくありませんが、C# では次のようになります。

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

    次に、各コントロールをデリゲートに渡すだけです。

  • イベント名を文字列として指定し、リフレクションを使用してイベントを取得し、サブスクライブします ( Type.GetEventthen EventInfo.AddEventHandler)。

于 2013-09-25T17:48:35.210 に答える