当前位置:  开发笔记 > 编程语言 > 正文

如何从事件中删除所有事件处理程序

如何解决《如何从事件中删除所有事件处理程序》经验,为你挑选了8个好方法。

要在控件上创建新的事件处理程序,您可以执行此操作

c.Click += new EventHandler(mainFormButton_Click);

或这个

c.Click += mainFormButton_Click;

并删除事件处理程序,您可以执行此操作

c.Click -= mainFormButton_Click;

但是如何从事件中删除所有事件处理程序?



1> xsl..:

我在MSDN论坛上找到了一个解决方案.下面的示例代码将删除所有Click事件button1.

public partial class Form1 : Form
{
        public Form1()
        {
            InitializeComponent();

            button1.Click += button1_Click;
            button1.Click += button1_Click2;
            button2.Click += button2_Click;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Hello");
        }

        private void button1_Click2(object sender, EventArgs e)
        {
            MessageBox.Show("World");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            RemoveClickEvent(button1);
        }

        private void RemoveClickEvent(Button b)
        {
            FieldInfo f1 = typeof(Control).GetField("EventClick", 
                BindingFlags.Static | BindingFlags.NonPublic);
            object obj = f1.GetValue(b);
            PropertyInfo pi = b.GetType().GetProperty("Events",  
                BindingFlags.NonPublic | BindingFlags.Instance);
            EventHandlerList list = (EventHandlerList)pi.GetValue(b, null);
            list.RemoveHandler(obj, list[obj]);
        }
    }
}


如果我错了,请纠正我,但不应该以'RemoveClickEvent`的第一行开头:`FieldInfo f1 = typeof(Button)`?如果我使用`Control`,我从`GetField`得到null.
这似乎不适用于ToolStripButtons.我已经用ToolStripButton替换了RemoveClickEvent中的Button,但是在调用RemoveClickEvent之后事件仍然存在.有没有人解决这个问题?

2> 小智..:

你们这些方式对你们来说太过刻板了.就这么简单:

void OnFormClosing(object sender, FormClosingEventArgs e)
{
    foreach(Delegate d in FindClicked.GetInvocationList())
    {
        FindClicked -= (FindClickedHandler)d;
    }
}


...如果您拥有该事件,您可以编写`FindClicked = null;`这相当简单.
什么是FindClicked?
这只有在您拥有该活动时才有效.尝试在控件上执行此操作.
这不适用于Kinect事件 - "kinect.ColorFrameReady - = MyEventHander",但kinect实例上没有`GetInvocationList()`方法来迭代它们的代理.

3> Jorge Ferrei..:

删除所有事件处理程序:

直接不,很大程度上是因为你不能简单地将事件设置为null.

间接地,您可以将实际事件设为私有,并在其周围创建一个属性,跟踪所有被添加/减去的代理.

请考虑以下事项:

List delegates = new List();

private event EventHandler MyRealEvent;

public event EventHandler MyEvent
{
    add
    {
        MyRealEvent += value;
        delegates.Add(value);
    }

    remove
    {
        MyRealEvent -= value;
        delegates.Remove(value);
    }
}

public void RemoveAllEvents()
{
    foreach(EventHandler eh in delegates)
    {
        MyRealEvent -= eh;
    }
    delegates.Clear();
}


我认为OP指的是一般的.net控件..其中这种包装可能是不可能的.
你可以导出控件,然后就可以了

4> LionSoft..:

接受的答案不完整.它不适用于声明为{add; 去掉;}

这是工作代码:

public static void ClearEventInvocations(this object obj, string eventName)
{
    var fi = obj.GetType().GetEventField(eventName);
    if (fi == null) return;
    fi.SetValue(obj, null);
}

private static FieldInfo GetEventField(this Type type, string eventName)
{
    FieldInfo field = null;
    while (type != null)
    {
        /* Find events defined as field */
        field = type.GetField(eventName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic);
        if (field != null && (field.FieldType == typeof(MulticastDelegate) || field.FieldType.IsSubclassOf(typeof(MulticastDelegate))))
            break;

        /* Find events defined as property { add; remove; } */
        field = type.GetField("EVENT_" + eventName.ToUpper(), BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic);
        if (field != null)
            break;
        type = type.BaseType;
    }
    return field;
}


这个版本对我有用.接受的版本不起作用.为此+1.

5> 小智..:

删除不存在的事件处理程序没有任何损害.因此,如果你知道可能有哪些处理程序,你可以简单地删除它们.我刚才有类似的情况.在某些情况下这可能有所帮助.

喜欢:

// Add handlers...
if (something)
{
    c.Click += DoesSomething;
}
else
{
    c.Click += DoesSomethingElse;
}

// Remove handlers...
c.Click -= DoesSomething;
c.Click -= DoesSomethingElse;



6> Ivan Ferrer ..:

我实际上正在使用这种方法,它完美无缺.我被Aeonhack 在这里写的代码"启发"了.

Public Event MyEvent()
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If MyEventEvent IsNot Nothing Then
        For Each d In MyEventEvent.GetInvocationList ' If this throws an exception, try using .ToArray
            RemoveHandler MyEvent, d
        Next
    End If
End Sub

MyEventEvent字段是隐藏的,但确实存在.

调试时,您可以看到d.target对象实际上是如何处理事件的,以及d.method它的方法.你只需要删除它.

它很棒.由于事件处理程序,没有更多的对象没有GC.



7> 小智..:

我讨厌这里显示的任何完整的解决方案,我做了混合并现在测试,适用于任何事件处理程序:

public class MyMain()
    public void MyMethod() {
        AnotherClass.TheEventHandler += DoSomeThing;
    }

    private void DoSomething(object sender, EventArgs e) {
        Debug.WriteLine("I did something");
        AnotherClass.ClearAllDelegatesOfTheEventHandler();
    }

}

public static class AnotherClass {

    public static event EventHandler TheEventHandler;

    public static void ClearAllDelegatesOfTheEventHandler() {

        foreach (Delegate d in TheEventHandler.GetInvocationList())
        {
            TheEventHandler -= (EventHandler)d;
        }
    }
}

简单!谢谢Stephen Punak.

我使用它是因为我使用通用的本地方法来删除委托,并且在设置不同的委托时,在不同的情况下调用本地方法.



8> Gishu..:

如果你真的必须这样做......它需要反思并且需要相当长的时间才能做到这一点.事件处理程序在控件内的事件到委托映射中进行管理.你需要

在控件实例中反映并获取此映射.

迭代每个事件,获得代表

每个代表反过来可以是一系列链式事件处理程序.所以调用obControl.RemoveHandler(event,handler)

总之,做了很多工作.这在理论上是可能的......我从来没有尝试过这样的事情.

看看你是否可以在控件的subscribe-unsubscribe阶段有更好的控制/纪律.

推荐阅读
手机用户2402851155
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有