2

SubFuncのすべてのイベント ハンドラーを削除するために使用されるジェネリック関数を作成する必要があります(サブルーチンと関数の両方で適切に動作するには、ジェネリック関数が必要です)。

...問題は、これを行う方法がわからないことです。デリゲートを宣言する例を見ましたが、それは正確なように一般的ではありません。

CodeProject でこの記事を読みましたが、コードは C# で書かれており、理解できません: http://www.codeproject.com/Articles/103542/Removing-Event-Handlers-using-Reflection

これは私が自分でできる唯一のことです:

Public Class Form1

    ' Call the function to remove all the handlers of "MySub"
    ' Clear_Handles(Of MySub)

    Private Function Clear_Handles(Of T)(ByVal MethodName As T)
        ' Code to remove all handlers(of "MethodName")
    End Function

    Private Sub MySub() Handles event1, event2, event3
        ' bla bla bla
    End Sub

End Class

読んでくれてありがとう。

アップデート

試しに上記のコードを VB に変換しようとしましたが、使用できません。使用方法がわかりません。これが私が行ったことです。

Public Class Form1

Private Sub MySub() Handles Button1.Click, Button2.click
    ' Do nothing
End Sub

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    ' Attempting to remove "Button1.Click" and "Button2.click" events of "MySub()"
    PSLib.cEventHelper.RemoveAllEventHandlers(MySub)
End Sub

End Class

...これは翻訳されたコードです。メソッドの使用方法がわからないため、機能するかどうかはわかりません。

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.IO
Imports System.Management
Imports System.Reflection
Imports System.Text

Namespace PSLib
    '--------------------------------------------------------------------------------
    Public NotInheritable Class cEventHelper
        Private Sub New()
        End Sub
        Shared dicEventFieldInfos As New Dictionary(Of Type, List(Of FieldInfo))()

        Private Shared ReadOnly Property AllBindings() As BindingFlags
            Get
                Return BindingFlags.IgnoreCase Or BindingFlags.[Public] Or BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.[Static]
            End Get
        End Property

        '--------------------------------------------------------------------------------
        Private Shared Function GetTypeEventFields(t As Type) As List(Of FieldInfo)
            If dicEventFieldInfos.ContainsKey(t) Then
                Return dicEventFieldInfos(t)
            End If

            Dim lst As New List(Of FieldInfo)()
            BuildEventFields(t, lst)
            dicEventFieldInfos.Add(t, lst)
            Return lst
        End Function

        '--------------------------------------------------------------------------------
        Private Shared Sub BuildEventFields(t As Type, lst As List(Of FieldInfo))
            ' Type.GetEvent(s) gets all Events for the type AND it's ancestors
            ' Type.GetField(s) gets only Fields for the exact type.
            '  (BindingFlags.FlattenHierarchy only works on PROTECTED & PUBLIC
            '   doesn't work because Fieds are PRIVATE)

            ' NEW version of this routine uses .GetEvents and then uses .DeclaringType
            ' to get the correct ancestor type so that we can get the FieldInfo.
            For Each ei As EventInfo In t.GetEvents(AllBindings)
                Dim dt As Type = ei.DeclaringType
                Dim fi As FieldInfo = dt.GetField(ei.Name, AllBindings)
                If fi IsNot Nothing Then
                    lst.Add(fi)
                End If
            Next

        End Sub

        '--------------------------------------------------------------------------------
        Private Shared Function GetStaticEventHandlerList(t As Type, obj As Object) As EventHandlerList
            Dim mi As MethodInfo = t.GetMethod("get_Events", AllBindings)
            Return DirectCast(mi.Invoke(obj, New Object() {}), EventHandlerList)
        End Function

        '--------------------------------------------------------------------------------
        Public Shared Sub RemoveAllEventHandlers(obj As Object)
            RemoveEventHandler(obj, "")
        End Sub

        '--------------------------------------------------------------------------------
        Public Shared Sub RemoveEventHandler(obj As Object, EventName As String)
            If obj Is Nothing Then
                Return
            End If

            Dim t As Type = obj.[GetType]()
            Dim event_fields As List(Of FieldInfo) = GetTypeEventFields(t)
            Dim static_event_handlers As EventHandlerList = Nothing

            For Each fi As FieldInfo In event_fields
                If EventName <> "" AndAlso String.Compare(EventName, fi.Name, True) <> 0 Then
                    Continue For
                End If

                ' After hours and hours of research and trial and error, it turns out that
                ' STATIC Events have to be treated differently from INSTANCE Events...
                If fi.IsStatic Then
                    ' STATIC EVENT
                    If static_event_handlers Is Nothing Then
                        static_event_handlers = GetStaticEventHandlerList(t, obj)
                    End If

                    Dim idx As Object = fi.GetValue(obj)
                    Dim eh As [Delegate] = static_event_handlers(idx)
                    If eh Is Nothing Then
                        Continue For
                    End If

                    Dim dels As [Delegate]() = eh.GetInvocationList()
                    If dels Is Nothing Then
                        Continue For
                    End If

                    Dim ei As EventInfo = t.GetEvent(fi.Name, AllBindings)
                    For Each del As [Delegate] In dels
                        ei.RemoveEventHandler(obj, del)
                    Next
                Else
                    ' INSTANCE EVENT
                    Dim ei As EventInfo = t.GetEvent(fi.Name, AllBindings)
                    If ei IsNot Nothing Then
                        Dim val As Object = fi.GetValue(obj)
                        Dim mdel As [Delegate] = TryCast(val, [Delegate])
                        If mdel IsNot Nothing Then
                            For Each del As [Delegate] In mdel.GetInvocationList()
                                ei.RemoveEventHandler(obj, del)
                            Next
                        End If
                    End If
                End If
            Next
        End Sub

    End Class
End Namespace

アップデート

これは私がすることの例です:

private sub form1_shown() handles me.shown
    RemoveAll_EventHandlers(of MyMethod)
    ' So it will remove: button1.click, button2.click, button3.click 
end sub

Private sub MyMethod() handles button1.click, button2.click, button3.click
   ' Nothing to do here. . . 
end sub

public sub RemoveAll_EventHandlers(of T)(byval MethodName as T)
      For each evt as event in MethodName : removehandler control.event, addres of(T) 
end sub

アップデート:

あなたの想像力のための別の例...:

Private Sub RemoveAll_EventHandlers(Of T)(ByVal MethodName As T)
    For Each ctrl As Control In Me.Controls
        For Each evt As EventHandler In Control
            RemoveHandler ctrl.evt, addresof(T)
        Next
    Next
End Sub

private sub form1_shown() handles me.shown
    RemoveAll_EventHandlers(of MyMethod)
    ' So it will remove: button1.click, button2.click, button3.click 
end sub

Private sub MyMethod() handles button1.click, button2.click, button3.click
   ' Nothing to do here. . . 
end sub
4

2 に答える 2

3

これは C# ですが、一般的なものです。私が理解していることから、あなたにはたくさんのイベントがあるクラスがあります。同じメソッドで複数のイベントをサブスクライブします。サブスクライブしているすべてのイベントからメソッドを削除します。簡単なテストを書きましたが、いくつかのコーナーケースかもしれません

    public static class EventUtility
        {
            public static void Unsubscribe(object obj, Delegate method)
            {
                Type type = obj.GetType();
                foreach (EventInfo eventInfo in type.GetEvents(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
                {
                    FieldInfo field = type.GetField(eventInfo.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                    Delegate eventDelegate = field.GetValue(obj) as Delegate;
                    foreach (Delegate subscriber in eventDelegate.GetInvocationList())
                    {
                        if (subscriber.Method == method.Method)
                        {
                            eventInfo.RemoveEventHandler(obj, subscriber);
                        }
                    }
                }
            }
        }

        public class TestClass
        {
            public event EventHandler EventA;
            public event EventHandler EventB;
            public event EventHandler EventC;

            public void A()
            {
                Console.WriteLine("A Start");
                EventA(this, EventArgs.Empty);
                Console.WriteLine("A End");
            }

            public void B()
            {
                Console.WriteLine("B Start");
                EventB(this, EventArgs.Empty);
                Console.WriteLine("B End");
            }
            public void C()
            {
                Console.WriteLine("C Start");
                EventC(this, EventArgs.Empty);
                Console.WriteLine("C End");
            }

        }

        class Program
        {
            public static void test2()
            {
                TestClass t = new TestClass();
                t.EventA += Handler1;
                t.EventB += Handler1;
                t.EventC += Handler1;

                t.EventA += Handler2;
                t.EventB += Handler2;
                t.EventC += Handler2;

                t.EventA += Handler3;
                t.EventB += Handler3;
                t.EventC += Handler3;

                t.A();
                t.B();
                t.C();

                EventUtility.Unsubscribe(t, new EventHandler(Handler2));

                t.A();
                t.B();
                t.C();
            }


            private static void Handler1(object instance, EventArgs args)
            {
                Console.WriteLine("handler1 invoked.");
            }

            private static void Handler2(object instance, EventArgs args)
            {
                Console.WriteLine("handler2 invoked.");
            }

            private static void Handler3(object instance, EventArgs args)
            {
                Console.WriteLine("handler3 invoked.");
            }

            static void Main()
            {
                test2();
            }
}
于 2013-06-26T23:42:20.647 に答える
1

次のようなことを試してください:

For Each b As Button in MySub.Controls.OfType(Of Button)

    'This should remove all the handlers for each button
    PSLib.cEventHelper.RemoveAllEventHandlers(b)

    'Or like this to just remove just the Click handler for each button
    PSLib.cEventHelper.RemoveEventHandler(b, "Click")

Next

最初にオリジナルを使用することをお勧めします。フロントを適切に接続してください。次に翻訳を行います。このようにして、ベースラインがあり、それがどのように機能するかがわかります。

アップデート:

混乱の一部は、用語の誤用にあると思います。更新 MyMethod はハンドラーであり、ハンドラーは含まれていませんが、複数のイベントを処理できます。Button1.Click はイベントです。Button1 はボタンです。したがって、適切な用語を使用すると、特定のハンドラー (MyMethod) によって処理されるすべてのイベント (Button1.Click、Button2.Click など) を削除する必要があるように見えます。

すべてのコントロールが同じであると仮定した場合の 1 つの方法を次に示します。

Private Sub Form2_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    For Each b As Control In Me.Controls
        If b.Name.Contains("3") OrElse b.Name.Contains("4") Then
            b.Tag = New KeyValuePair(Of String, Boolean)("1", True)
            AddHandler b.Click, AddressOf Button_Click1
        Else
            b.Tag = New KeyValuePair(Of String, Boolean)("2", True)
            AddHandler b.Click, AddressOf Button_Click2
        End If
    Next
End Sub
Private Sub RemoveEvents(Handler As String)
    For Each b As Control In Me.Controls
        Dim TempTag As KeyValuePair(Of String, Boolean) = DirectCast(b.Tag, KeyValuePair(Of String, Boolean))
        If TempTag.Key = Handler AndAlso TempTag.Value = False Then
            Select Case Handler
                Case "1"
                    RemoveHandler b.Click, AddressOf Button_Click1
                Case "2"
                    RemoveHandler b.Click, AddressOf Button_Click2
            End Select
        End If
    Next
End Sub
Private Sub Button_Click1(sender As Object, e As EventArgs)
    'do stuff
End Sub
Private Sub Button_Click2(sender As Object, e As EventArgs)
    'do stuff
End Sub

タグの keyvaluepair 値の値を false に設定して、サブルーチンがクリック イベントを制御するハンドラーを削除するようにします。

于 2013-06-10T17:59:36.477 に答える