Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vb.net/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 清除过程的所有处理程序的通用函数?_.net_Vb.net_Winforms_Function_Handler - Fatal编程技术网

.net 清除过程的所有处理程序的通用函数?

.net 清除过程的所有处理程序的通用函数?,.net,vb.net,winforms,function,handler,.net,Vb.net,Winforms,Function,Handler,我需要编写一个通用函数,该函数将用于删除子函数和函数的所有事件处理程序(我需要通用函数与子程序和函数一起正常工作) …问题是我不知道如何做到这一点,我看到了声明委托的示例,但这不像我所说的那样通用 我读过这篇关于CodeProject的文章,但代码是C语言的,我什么都看不懂: 这是我唯一能自己做的: Public Class Form1 ' Call the function to remove all the handlers of "MySub" ' Clear_Handl

我需要编写一个通用函数,该函数将用于删除子函数和函数的所有事件处理程序(我需要通用函数与子程序和函数一起正常工作)

…问题是我不知道如何做到这一点,我看到了声明委托的示例,但这不像我所说的那样通用

我读过这篇关于CodeProject的文章,但代码是C语言的,我什么都看不懂:

这是我唯一能自己做的:

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 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

试着这样做:

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
建议先使用原文。让你的正面与它正确对接。然后做翻译。这样你就有了一条底线,知道它应该如何运作

更新:

我认为造成混乱的部分原因在于术语的误用。在update中,MyMethod是一个处理程序,它不包含处理程序,但可以处理多个事件。按钮1。单击是一个事件。按钮1是一个按钮。因此,使用适当的术语,您似乎希望删除由特定处理程序(MyMethod)处理的所有事件(Button1.Click、Button2.Click等)

这里有一种方法,假设所有控件都相同:

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,让子程序从该控件单击事件中删除处理程序

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
建议先使用原文。让你的正面与它正确对接。然后做翻译。这样你就有了一条底线,知道它应该如何运作

更新:

我认为造成混乱的部分原因在于术语的误用。在update中,MyMethod是一个处理程序,它不包含处理程序,但可以处理多个事件。按钮1。单击是一个事件。按钮1是一个按钮。因此,使用适当的术语,您似乎希望删除由特定处理程序(MyMethod)处理的所有事件(Button1.Click、Button2.Click等)

这里有一种方法,假设所有控件都相同:

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,以使子程序从控制单击事件的处理程序中删除该处理程序

这在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();
            }
}
这是用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();
            }
}

你真的不需要理解C。代码已准备好编译为.dll,或者将代码作为单独的项目包含在解决方案中。然后,只需将其添加为引用,然后导入名称空间。这篇文章向您展示了如何调用函数,只需去掉分号即可。@tinstaafl谢谢,我没有注意到这一点,但现在我正在尝试使用该类,但我无法通过将过程的名称作为参数来使用它,那么如何使用它呢?请看我更新的问题。你真的不需要理解C。代码已准备好编译为.dll,或者将代码作为单独的项目包含在解决方案中。然后,只需将其添加为引用,然后导入名称空间。这篇文章向您展示了如何调用函数,只需去掉分号即可。@tinstaafl谢谢,我没有注意到这一点,但现在我正在尝试使用该类,但我无法通过将过程的名称作为参数来使用它,那么如何使用它呢?请看我更新的问题。我很感激,但是你给我看的代码对我的目的没有帮助,因为它们希望消除控件的所有句柄,但我需要删除特定子控件的一个句柄,例如:如果我有“MySub()句柄Button1.Click”和“MyFunc()句柄Button1.Click”然后根据您的建议,它将删除Sub和Func中的相同句柄,但我只想删除MySub()上的句柄,并保留MyFunc中的另一个“Button1.Click”,问题:原始代码满足我的需要?首先,您不能将函数用作事件处理程序,它必须是子函数。其次,您有哪些条件要求更改事件处理程序?另外,如果更改很简单并且已知,您可以使用RemoveHandler方法我对函数的错误,但无论如何,我需要做的是删除子控件中处理的所有处理程序,而不是控件的所有处理程序。例如:对于MethodName:removehandler hdl中作为处理程序的每个hdl,您现在明白我的意思了吗?谢谢,我想现在越来越清楚了。您希望从每个绑定了事件的控件中删除一个处理程序。是否知道哪些控件的事件绑定到该处理程序?您可以做的是,不要使用handles子句,使用addhandler语句在form load事件中设置处理程序。对于每个控件,添加处理程序以将标记对象设置为字典(字符串,布尔值),并添加一个条目以标识它使用的事件和处理程序,例如,布尔值设置为true。添加(“单击-1”,true)具有“单击-1”的每个按钮设置为true删除它的单击处理程序。我正在寻找一种通用的方法来完成它。PS:对不起,我的英语不总是正确的单词,这正是我想要做的,但我需要一个通用的方法,因为我的sub是处理多个控制事件的事件。我很感激,但t