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

标签 .net vb.net winforms function handler

我需要编写一个通用函数,用于删除 SubFunc 的所有事件处理程序(我需要通用函数才能与子例程和函数)。

...问题是我不知道如何做到这一点,我看到了声明委托(delegate)的示例,但这并不像我精确的那样通用。

我已阅读 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

感谢您的阅读。

UPDATE

我尝试将上面的代码转换为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

UPDATE

这是我会做的一个例子:

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

UPDATE:

另一个激发你想象力的例子......:

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

最佳答案

这是用 C# 编写的,但它是通用的。据我了解,你的类(class)有很多事件。您将使用相同的方法订阅多个事件。您想要从它订阅的所有事件中删除该方法。我写了一个快速测试,可能是一些极端情况

    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();
            }
}

关于.net - 清除程序的所有处理程序的通用函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17012426/

相关文章:

javascript - 从vb.net中的json文件上的数组返回多个元素,绑定(bind)到数据表

c# - VB/C#.net 动态添加带有Background Worker的控件项

c# - 在表单之间传递值时出错

c# - NHibernate查询问题

.NET 签名 XML 前缀

c# - 在构造函数中声明的 C# 对象的垃圾收集

c# - 在.NET(C#或VB.NET)中生成摩尔斯电码(或任何音频),而无需第三方依赖,也无需使用音频文件

mysql - vb.net 消费nusoap报错

c# - BackgroundWorker 的任务并行库替换?

.net - 如何使用流畅的 API 添加主键 - Entity Framework EF 4.x Code First