วิธีลบตัวจัดการเหตุการณ์ทั้งหมดออกจากเหตุการณ์


366

ในการสร้างตัวจัดการเหตุการณ์ใหม่บนตัวควบคุมคุณสามารถทำได้

c.Click += new EventHandler(mainFormButton_Click);

หรือสิ่งนี้

c.Click += mainFormButton_Click;

และเมื่อต้องการลบตัวจัดการเหตุการณ์คุณสามารถทำได้

c.Click -= mainFormButton_Click;

แต่คุณจะลบตัวจัดการเหตุการณ์ทั้งหมดออกจากเหตุการณ์ได้อย่างไร


10
หากใครมาที่นี่เพื่อค้นหาโซลูชัน WPF คุณอาจต้องการดูคำตอบนี้
ดักลาส

1
คุณไม่สามารถตั้งค่าได้c.Click = nullหรือไม่
alexania

นี่คือสิ่งหนึ่งที่ฉันพบว่ามันซับซ้อนเกินไป ง่ายClearวิธีการก็คือความพยายามมากเกินไปเห็นได้ชัด
Zimano

คำตอบ:


167

ผมพบว่าวิธีการแก้ปัญหาเกี่ยวกับการที่ฟอรั่ม MSDN โค้ดตัวอย่างด้านล่างจะลบทุกเหตุการณ์ที่เกิดขึ้นจากClickbutton1

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

หาก button1 ถูกตั้งค่าเป็น null ตัวจัดการเหตุการณ์ทั้งหมดถูกเชื่อมต่อกับ button1.Click ถูกต้องหรือไม่
Damien

3
ถูกต้องฉันหากฉันผิด แต่ไม่ควรบรรทัดแรกของการRemoveClickEventเริ่มต้นด้วย: FieldInfo f1 = typeof(Button)? ฉันได้รับจาก null หากฉันใช้GetField Control
ป้องกันหนึ่ง

2
ดูเหมือนจะไม่ทำงานกับ ToolStripButtons ฉันได้แทนที่ปุ่มใน RemoveClickEvent ด้วย ToolStripButton แต่เหตุการณ์ยังคงเกิดขึ้นหลังจากโทร RemoveClickEvent มีใครแก้ปัญหานี้หรือไม่?
Skalli

1
ลิงค์ด้านบนใน MSDN แนะนำให้ลอง myButton.Click + = null; ถ้าคุณต้องการลบผู้รับมอบสิทธิ์ทั้งหมด (ไม่ใช่สำหรับ Click แต่สำหรับกิจกรรมอื่น ๆ .. )
hello_earth

1
@hello_earth ดูเหมือนจะใช้งานไม่ได้ObservableCollection.CollectionChanged += null;
Mike de Klerk

146

พวกคุณกำลังทำวิธีนี้ยากเกินไปสำหรับตัวคุณเอง มันง่ายมาก:

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

57
สิ่งนี้จะใช้งานได้หากคุณเป็นเจ้าของกิจกรรม ลองทำด้วยการควบคุม
Delyan

226
... และหากคุณเป็นเจ้าของกิจกรรมคุณสามารถเขียนFindClicked = null;ได้ง่ายกว่า
Jon Skeet

79
FindClicked คืออะไร
Levitikon

3
สิ่งนี้ไม่สามารถใช้ได้กับเหตุการณ์ Kinect - kinect.ColorFrameReady -= MyEventHanderทำได้ แต่ไม่มีGetInvocationList()วิธีในการใช้อินสแตนซ์ kinect เพื่อทำซ้ำผ่านตัวแทนของพวกเขา
Brent Faust

GetInvocationListไม่พบ.
โจ๊ก Huang

75

จากการลบตัวจัดการกิจกรรมทั้งหมด :

ไม่โดยตรงส่วนใหญ่เพราะคุณไม่สามารถตั้งค่าเหตุการณ์ให้เป็นโมฆะ

ทางอ้อมคุณสามารถทำให้เหตุการณ์จริงเป็นส่วนตัวและสร้างสถานที่ให้บริการที่ติดตามผู้ได้รับมอบหมายทั้งหมดที่ถูกเพิ่ม / ลบออกไป

ทำสิ่งต่อไปนี้:

List<EventHandler> delegates = new List<EventHandler>();

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

4
ฉันคิดว่า OP หมายถึงตัวควบคุม. net ทั่วไป .. ซึ่งการห่อแบบนี้อาจเป็นไปไม่ได้
Gishu

4
คุณสามารถควบคุมได้จากนั้นมันจะ
Tom Fobear

นอกจากนี้ยังนำไปสู่การรักษาสองรายการดูstackoverflow.com/questions/91778/…สำหรับการรีเซ็ตหรือstackoverflow.com/questions/91778/…เพื่อเข้าถึงรายการ
เทนเนสซี

63

คำตอบที่ยอมรับไม่เต็ม ไม่สามารถใช้ได้กับกิจกรรมที่ประกาศเป็น {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;
}

4
รุ่นนี้ใช้งานได้สำหรับฉัน รุ่นที่ยอมรับไม่ทำงาน +1 สำหรับสิ่งนั้น
Meister Schnitzel

1
ไม่ทำงานกับกิจกรรม WPF จนกว่าฉันจะใช้BindingFlags.PublicในการGetFieldโทรครั้งแรก
Lennart

40

การลบตัวจัดการเหตุการณ์ที่ไม่มีอยู่จะไม่เป็นอันตรายใด ๆ ดังนั้นถ้าคุณรู้ว่ามีตัวจัดการอะไรคุณสามารถลบทั้งหมดได้ ฉันเพิ่งมีกรณีที่คล้ายกัน สิ่งนี้อาจช่วยได้ในบางกรณี

ชอบ:

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

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

16

จริงๆแล้วฉันใช้วิธีนี้และทำงานได้อย่างสมบูรณ์ ผมเป็น 'แรงบันดาลใจ' ตามรหัสที่เขียนโดย 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'ed เนื่องจากตัวจัดการเหตุการณ์


2
โปรดอย่าเขียนคำตอบเป็นภาษาอื่น
Hille

10

ฉันเกลียดวิธีแก้ปัญหาทั้งหมดที่แสดงที่นี่ฉันทำมิกซ์และทดสอบแล้วทำงานกับตัวจัดการเหตุการณ์:

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

ฉันใช้มันเพราะฉันใช้วิธีการทั่วไปในการลบผู้รับมอบสิทธิ์และวิธีการในท้องถิ่นถูกเรียกหลังจากกรณีที่แตกต่างกันเมื่อผู้ได้รับมอบหมายที่แตกต่างกันจะถูกกำหนด


4

หากคุณreaalllyต้องทำเช่นนี้ ... มันจะใช้เวลาการสะท้อนและค่อนข้างบางเวลาที่จะทำเช่นนี้ ตัวจัดการเหตุการณ์ได้รับการจัดการในการแมปเหตุการณ์กับผู้รับมอบสิทธิ์ภายในการควบคุม คุณจะต้อง

  • สะท้อนและรับแผนที่นี้ในอินสแตนซ์ควบคุม
  • ทำซ้ำสำหรับแต่ละเหตุการณ์รับตัวแทน
    • ผู้รับมอบสิทธิ์แต่ละรายอาจเป็นชุดตัวจัดการเหตุการณ์ที่ถูกผูกมัด ดังนั้นเรียก obControl.RemoveHandler (เหตุการณ์ตัวจัดการ)

ในระยะสั้นการทำงานมาก เป็นไปได้ในทางทฤษฎี ... ฉันไม่เคยลองแบบนี้

ดูว่าคุณสามารถมีการควบคุม / วินัยที่ดีขึ้นในช่วงสมัคร - ยกเลิกการเป็นสมาชิกสำหรับการควบคุม


3

สตีเฟ่นมีสิทธิ มันง่ายมาก ๆ:

public event EventHandler<Cles_graph_doivent_etre_redessines> les_graph_doivent_etre_redessines;
public void remove_event()
{
    if (this.les_graph_doivent_etre_redessines != null)
    {
        foreach (EventHandler<Cles_graph_doivent_etre_redessines> F_les_graph_doivent_etre_redessines in this.les_graph_doivent_etre_redessines.GetInvocationList())
        {
            this.les_graph_doivent_etre_redessines -= F_les_graph_doivent_etre_redessines;
        }
    }
}

38
พระเจ้าผู้รวบรวมควรห้ามชื่อตัวแปรชนิดนั้น graphs_must_be_redrawn ในภาษาฝรั่งเศส
gracchus

4
แปลจากภาษาฝรั่งเศส foreach (EventHandler<MyCompletedArgs> handler in CompletionCompleted.GetInvocationList()) { CompletionCompleted -= handler; }
แอนตัน K

การแปลภาษาอังกฤษโดย @AntonK ทำงานได้ดี อย่าลืมตรวจสอบ null ในตัวจัดการคุณสมบัติ
Brett

2

ฉันเพิ่งค้นพบวิธีที่จะระงับเหตุการณ์เมื่อตั้งค่าคุณสมบัติของตัวควบคุม WinForms มันจะลบกิจกรรมทั้งหมดจากการควบคุม:

namespace CMessWin05
{
    public class EventSuppressor
    {
        Control _source;
        EventHandlerList _sourceEventHandlerList;
        FieldInfo _headFI;
        Dictionary<object, Delegate[]> _handlers;
        PropertyInfo _sourceEventsInfo;
        Type _eventHandlerListType;
        Type _sourceType;


        public EventSuppressor(Control control)
        {
            if (control == null)
                throw new ArgumentNullException("control", "An instance of a control must be provided.");

            _source = control;
            _sourceType = _source.GetType();
            _sourceEventsInfo = _sourceType.GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic);
            _sourceEventHandlerList = (EventHandlerList)_sourceEventsInfo.GetValue(_source, null);
            _eventHandlerListType = _sourceEventHandlerList.GetType();
            _headFI = _eventHandlerListType.GetField("head", BindingFlags.Instance | BindingFlags.NonPublic);
        }

        private void BuildList()
        {
            _handlers = new Dictionary<object, Delegate[]>();
            object head = _headFI.GetValue(_sourceEventHandlerList);
            if (head != null)
            {
                Type listEntryType = head.GetType();
                FieldInfo delegateFI = listEntryType.GetField("handler", BindingFlags.Instance | BindingFlags.NonPublic);
                FieldInfo keyFI = listEntryType.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic);
                FieldInfo nextFI = listEntryType.GetField("next", BindingFlags.Instance | BindingFlags.NonPublic);
                BuildListWalk(head, delegateFI, keyFI, nextFI);
            }
        }

        private void BuildListWalk(object entry, FieldInfo delegateFI, FieldInfo keyFI, FieldInfo nextFI)
        {
            if (entry != null)
            {
                Delegate dele = (Delegate)delegateFI.GetValue(entry);
                object key = keyFI.GetValue(entry);
                object next = nextFI.GetValue(entry);

                Delegate[] listeners = dele.GetInvocationList();
                if(listeners != null && listeners.Length > 0)
                    _handlers.Add(key, listeners);

                if (next != null)
                {
                    BuildListWalk(next, delegateFI, keyFI, nextFI);
                }
            }
        }

        public void Resume()
        {
            if (_handlers == null)
                throw new ApplicationException("Events have not been suppressed.");

            foreach (KeyValuePair<object, Delegate[]> pair in _handlers)
            {
                for (int x = 0; x < pair.Value.Length; x++)
                    _sourceEventHandlerList.AddHandler(pair.Key, pair.Value[x]);
            }

            _handlers = null;
        }

        public void Suppress()
        {
            if (_handlers != null)
                throw new ApplicationException("Events are already being suppressed.");

            BuildList();

            foreach (KeyValuePair<object, Delegate[]> pair in _handlers)
            {
                for (int x = pair.Value.Length - 1; x >= 0; x--)
                    _sourceEventHandlerList.RemoveHandler(pair.Key, pair.Value[x]);
            }
        }

    }
}

1
สิ่งนี้มีประโยชน์มาก แต่มีสิ่งหนึ่งที่ต้องเปลี่ยน: ใน Resume () คุณกำลังเพิ่มตัวจัดการกลับในลำดับย้อนกลับ (ฉันสมมติว่ามันเป็นสำเนา / วางจาก Suppress ที่คุณต้องการทำงานย้อนกลับดังนั้น เพื่อไม่ให้ยุ่งกับคอลเล็กชันที่คุณทำซ้ำ) โค้ดบางตัวนับบนตัวจัดการที่เริ่มทำงานตามลำดับที่กำหนดดังนั้นจึงไม่ควรยุ่งกับสิ่งนั้น
Michael

1

ว้าว. ฉันพบโซลูชันนี้ แต่ไม่มีอะไรทำงานเหมือนที่ฉันต้องการ แต่นี่เป็นสิ่งที่ดีมาก:

EventHandlerList listaEventos;

private void btnDetach_Click(object sender, EventArgs e)
{
    listaEventos = DetachEvents(comboBox1);
}

private void btnAttach_Click(object sender, EventArgs e)
{
    AttachEvents(comboBox1, listaEventos);
}

public EventHandlerList DetachEvents(Component obj)
{
    object objNew = obj.GetType().GetConstructor(new Type[] { }).Invoke(new object[] { });
    PropertyInfo propEvents = obj.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);

    EventHandlerList eventHandlerList_obj = (EventHandlerList)propEvents.GetValue(obj, null);
    EventHandlerList eventHandlerList_objNew = (EventHandlerList)propEvents.GetValue(objNew, null);

    eventHandlerList_objNew.AddHandlers(eventHandlerList_obj);
    eventHandlerList_obj.Dispose();

    return eventHandlerList_objNew;
}

public void AttachEvents(Component obj, EventHandlerList eventos)
{
    PropertyInfo propEvents = obj.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);

    EventHandlerList eventHandlerList_obj = (EventHandlerList)propEvents.GetValue(obj, null);

    eventHandlerList_obj.AddHandlers(eventos);
}

นี่เป็นสิ่งที่ดีกว่าคำตอบก่อนหน้านี้อย่างแน่นอน มันทำสิ่งเดียวกันหรือไม่ ดูเหมือนว่ามันจะเป็นไปได้ แต่บางทีฉันก็ขาดอะไรไป นอกจากนี้ทำไมคุณต้องสร้างวัตถุใหม่เมื่อสิ่งที่คุณต้องการคือ EventHandlerList? ไม่มี c-tor ที่สามารถเข้าถึงได้สำหรับ EventHandlerList เช่นนั้นสามารถรับได้เฉพาะที่ถูกสร้างขึ้นภายในสำหรับคอมโพเนนต์หรือไม่
Michael

1

หน้านี้ช่วยฉันได้มาก รหัสที่ฉันได้รับจากที่นี่มีไว้เพื่อลบกิจกรรมคลิกจากปุ่ม ฉันต้องลบกิจกรรมดับเบิลคลิกจากแผงควบคุมบางส่วนและคลิกกิจกรรมจากปุ่มบางปุ่ม ดังนั้นฉันจึงสร้างส่วนขยายการควบคุมซึ่งจะลบตัวจัดการเหตุการณ์ทั้งหมดสำหรับเหตุการณ์บางอย่าง

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Reflection;
public static class EventExtension
{
    public static void RemoveEvents<T>(this T target, string eventName) where T:Control
    {
        if (ReferenceEquals(target, null)) throw new NullReferenceException("Argument \"target\" may not be null.");
        FieldInfo fieldInfo = typeof(Control).GetField(eventName, BindingFlags.Static | BindingFlags.NonPublic);
        if (ReferenceEquals(fieldInfo, null)) throw new ArgumentException(
            string.Concat("The control ", typeof(T).Name, " does not have a property with the name \"", eventName, "\""), nameof(eventName));
        object eventInstance = fieldInfo.GetValue(target);
        PropertyInfo propInfo = typeof(T).GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
        EventHandlerList list = (EventHandlerList)propInfo.GetValue(target, null);
        list.RemoveHandler(eventInstance, list[eventInstance]);
    }
}

ตอนนี้การใช้ extenstion นี้ หากคุณต้องการลบกิจกรรมการคลิกออกจากปุ่ม

Button button = new Button();
button.RemoveEvents(nameof(button.EventClick));

หากคุณต้องการลบเหตุการณ์ดับเบิลคลิกจากแผงควบคุม

Panel panel = new Panel();
panel.RemoveEvents(nameof(panel.EventDoubleClick));

ฉันไม่ใช่ผู้เชี่ยวชาญใน C # ดังนั้นหากมีข้อบกพร่องใด ๆ โปรดยกโทษให้ฉันและกรุณาแจ้งให้เราทราบเกี่ยวกับเรื่องนี้


1
.CastTo <> () วิธีการขยายที่ตรงที่พบ?
IbrarMumtaz

คุณสามารถเขียนของคุณเอง: public T T CastTo <T> (วัตถุ objectToCast นี้) {return (T) objectToCast; }
KingOfHypocrites

0

บางครั้งเราต้องทำงานกับการควบคุม ThirdParty และเราจำเป็นต้องสร้างโซลูชั่นที่น่าอึดอัดใจเหล่านี้ ตาม @Anoop Muraleedharan คำตอบฉันสร้างโซลูชันนี้ด้วยการอนุมานประเภทและการสนับสนุน ToolStripItem

    public static void RemoveItemEvents<T>(this T target, string eventName) 
        where T : ToolStripItem
    {            
        RemoveObjectEvents<T>(target, eventName);
    }

    public static void RemoveControlEvents<T>(this T target, string eventName)
        where T : Control
    {
        RemoveObjectEvents<T>(target, eventName);
    }

    private static void RemoveObjectEvents<T>(T target, string Event) where T : class
    {
        var typeOfT = typeof(T);
        var fieldInfo = typeOfT.BaseType.GetField(
            Event, BindingFlags.Static | BindingFlags.NonPublic);
        var provertyValue = fieldInfo.GetValue(target);
        var propertyInfo = typeOfT.GetProperty(
            "Events", BindingFlags.NonPublic | BindingFlags.Instance);
        var eventHandlerList = (EventHandlerList)propertyInfo.GetValue(target, null);
        eventHandlerList.RemoveHandler(provertyValue, eventHandlerList[provertyValue]);
    }

และคุณสามารถใช้มันได้เช่นนี้

    var toolStripButton = new ToolStripButton();
    toolStripButton.RemoveItemEvents("EventClick");

    var button = new Button();
    button.RemoveControlEvents("EventClick");

0

ฉันพบโซลูชันการทำงานอื่นของดักลาสดักลาส

วิธีการนี้จะลบตัวจัดการเหตุการณ์ทั้งหมดที่ตั้งอยู่ในเหตุการณ์เส้นทางที่เฉพาะเจาะจงในองค์ประกอบ
ใช้มันเหมือน

Remove_RoutedEventHandlers(myImage, Image.MouseLeftButtonDownEvent);

รหัสเต็ม:

/// <summary>
/// Removes all event handlers subscribed to the specified routed event from the specified element.
/// </summary>
/// <param name="element">The UI element on which the routed event is defined.</param>
/// <param name="RoutetEvent_ToRemove">The routed event for which to remove the event handlers.</param>
public static void RemoveRoutedEventHandlers(UIElement UIElement_Target, RoutedEvent RoutetEvent_ToRemove)
{
    // Get the EventHandlersStore instance which holds event handlers for the specified element.
    // The EventHandlersStore class is declared as internal.
    PropertyInfo PropertyInfo_EventHandlersStore = typeof(UIElement).GetProperty(
        "EventHandlersStore", BindingFlags.Instance | BindingFlags.NonPublic);
    object oEventHandlersStore = PropertyInfo_EventHandlersStore.GetValue(UIElement_Target, null);

    // If there's no event handler subscribed, return
    if (oEventHandlersStore == null) return;

    // Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance 
    // for getting an array of the subscribed event handlers.
    MethodInfo MethodInfo_RoutedEventHandlers = oEventHandlersStore.GetType().GetMethod(
        "GetRoutedEventHandlers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
    RoutedEventHandlerInfo[] RoutedEventHandlerInfos = (RoutedEventHandlerInfo[])MethodInfo_RoutedEventHandlers.Invoke(
        oEventHandlersStore, new object[] { RoutetEvent_ToRemove });

    // Iteratively remove all routed event handlers from the element.
    foreach (RoutedEventHandlerInfo RoutedEventHandlerInfo_Tmp in RoutedEventHandlerInfos)
        UIElement_Target.RemoveHandler(RoutetEvent_ToRemove, RoutedEventHandlerInfo_Tmp.Handler);
}

0

ลบตัวจัดการทั้งหมดสำหรับปุ่ม: save.RemoveEvents ();

public static class EventExtension
{
    public static void RemoveEvents<T>(this T target) where T : Control
    {
       var propInfo = typeof(T).GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
        var list = (EventHandlerList)propInfo.GetValue(target, null);
        list.Dispose();
    }
}

-1

ดีที่นี่มีวิธีอื่นในการลบกิจกรรมที่ไม่เกี่ยวข้อง (หากคุณมีวิธีจัดการเหตุการณ์สำหรับตัวควบคุมอยู่แล้ว):

EventDescriptor ed = TypeDescriptor.GetEvents(this.button1).Find("MouseDown",true);            
Delegate delegate = Delegate.CreateDelegate(typeof(EventHandler), this, "button1_MouseDownClicked");
if(ed!=null) 
    ed.RemoveEventHandler(this.button1, delegate);

คุณสามารถทำสิ่งนี้ได้ปุ่ม 1.MouseDown - = Delegate.CreateDelegate (typeof (EventHandler) สิ่งนี้ "button1_MouseDownClicked" ดังนั้นจะไม่ช่วยแก้ไขคำถามซึ่งเป็นวิธีการค้นหาว่าผู้รับมอบสิทธิ์รายใดจะลบโดยเฉพาะหากพวกเขาอยู่ในบรรทัด
Softlion

-1

นี่ไม่ใช่คำตอบของ OP แต่ฉันคิดว่าฉันโพสต์ที่นี่ในกรณีที่สามารถช่วยเหลือผู้อื่นได้

  /// <summary>
  /// Method to remove a (single) SocketAsyncEventArgs.Completed event handler. This is 
  /// partially based on information found here: http://stackoverflow.com/a/91853/253938
  /// 
  /// But note that this may not be a good idea, being very .Net implementation-dependent. Note 
  /// in particular use of "m_Completed" instead of "Completed".
  /// </summary>
  private static void RemoveCompletedEventHandler(SocketAsyncEventArgs eventArgs)
  {
     FieldInfo fieldInfo = typeof(SocketAsyncEventArgs).GetField("m_Completed", 
                                                BindingFlags.Instance | BindingFlags.NonPublic);
     eventArgs.Completed -= (EventHandler<SocketAsyncEventArgs>)fieldInfo.GetValue(eventArgs);
  }

-3

ฉันพบคำตอบนี้และมันเกือบจะพอดีกับความต้องการของฉัน ขอบคุณ SwDevMan81 สำหรับชั้นเรียน ฉันได้แก้ไขมันเพื่อให้การปราบปรามและการเริ่มต้นใหม่ของแต่ละวิธีและฉันคิดว่าฉันโพสต์ไว้ที่นี่

// This class allows you to selectively suppress event handlers for controls.  You instantiate
// the suppressor object with the control, and after that you can use it to suppress all events
// or a single event.  If you try to suppress an event which has already been suppressed
// it will be ignored.  Same with resuming; you can resume all events which were suppressed,
// or a single one.  If you try to resume an un-suppressed event handler, it will be ignored.

//cEventSuppressor _supButton1 = null;
//private cEventSuppressor SupButton1 {
//    get {
//        if (_supButton1 == null) {
//            _supButton1 = new cEventSuppressor(this.button1);
//        }
//        return _supButton1;
//    }
//}
//private void button1_Click(object sender, EventArgs e) {
//    MessageBox.Show("Clicked!");
//}

//private void button2_Click(object sender, EventArgs e) {
//    SupButton1.Suppress("button1_Click");
//}

//private void button3_Click(object sender, EventArgs e) {
//    SupButton1.Resume("button1_Click");
//}
using System;
using System.Collections.Generic;
using System.Text;

using System.Reflection;
using System.Windows.Forms;
using System.ComponentModel;

namespace Crystal.Utilities {
    public class cEventSuppressor {
        Control _source;
        EventHandlerList _sourceEventHandlerList;
        FieldInfo _headFI;
        Dictionary<object, Delegate[]> suppressedHandlers = new Dictionary<object, Delegate[]>();
        PropertyInfo _sourceEventsInfo;
        Type _eventHandlerListType;
        Type _sourceType;

        public cEventSuppressor(Control control) {
            if (control == null)
                throw new ArgumentNullException("control", "An instance of a control must be provided.");

            _source = control;
            _sourceType = _source.GetType();
            _sourceEventsInfo = _sourceType.GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic);
            _sourceEventHandlerList = (EventHandlerList)_sourceEventsInfo.GetValue(_source, null);
            _eventHandlerListType = _sourceEventHandlerList.GetType();
            _headFI = _eventHandlerListType.GetField("head", BindingFlags.Instance | BindingFlags.NonPublic);
        }
        private Dictionary<object, Delegate[]> BuildList() {
            Dictionary<object, Delegate[]> retval = new Dictionary<object, Delegate[]>();
            object head = _headFI.GetValue(_sourceEventHandlerList);
            if (head != null) {
                Type listEntryType = head.GetType();
                FieldInfo delegateFI = listEntryType.GetField("handler", BindingFlags.Instance | BindingFlags.NonPublic);
                FieldInfo keyFI = listEntryType.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic);
                FieldInfo nextFI = listEntryType.GetField("next", BindingFlags.Instance | BindingFlags.NonPublic);
                retval = BuildListWalk(retval, head, delegateFI, keyFI, nextFI);
            }
            return retval;
        }

        private Dictionary<object, Delegate[]> BuildListWalk(Dictionary<object, Delegate[]> dict,
                                    object entry, FieldInfo delegateFI, FieldInfo keyFI, FieldInfo nextFI) {
            if (entry != null) {
                Delegate dele = (Delegate)delegateFI.GetValue(entry);
                object key = keyFI.GetValue(entry);
                object next = nextFI.GetValue(entry);

                if (dele != null) {
                    Delegate[] listeners = dele.GetInvocationList();
                    if (listeners != null && listeners.Length > 0) {
                        dict.Add(key, listeners);
                    }
                }
                if (next != null) {
                    dict = BuildListWalk(dict, next, delegateFI, keyFI, nextFI);
                }
            }
            return dict;
        }
        public void Resume() {
        }
        public void Resume(string pMethodName) {
            //if (_handlers == null)
            //    throw new ApplicationException("Events have not been suppressed.");
            Dictionary<object, Delegate[]> toRemove = new Dictionary<object, Delegate[]>();

            // goes through all handlers which have been suppressed.  If we are resuming,
            // all handlers, or if we find the matching handler, add it back to the
            // control's event handlers
            foreach (KeyValuePair<object, Delegate[]> pair in suppressedHandlers) {

                for (int x = 0; x < pair.Value.Length; x++) {

                    string methodName = pair.Value[x].Method.Name;
                    if (pMethodName == null || methodName.Equals(pMethodName)) {
                        _sourceEventHandlerList.AddHandler(pair.Key, pair.Value[x]);
                        toRemove.Add(pair.Key, pair.Value);
                    }
                }
            }
            // remove all un-suppressed handlers from the list of suppressed handlers
            foreach (KeyValuePair<object, Delegate[]> pair in toRemove) {
                for (int x = 0; x < pair.Value.Length; x++) {
                    suppressedHandlers.Remove(pair.Key);
                }
            }
            //_handlers = null;
        }
        public void Suppress() {
            Suppress(null);
        }
        public void Suppress(string pMethodName) {
            //if (_handlers != null)
            //    throw new ApplicationException("Events are already being suppressed.");

            Dictionary<object, Delegate[]> dict = BuildList();

            foreach (KeyValuePair<object, Delegate[]> pair in dict) {
                for (int x = pair.Value.Length - 1; x >= 0; x--) {
                    //MethodInfo mi = pair.Value[x].Method;
                    //string s1 = mi.Name; // name of the method
                    //object o = pair.Value[x].Target;
                    // can use this to invoke method    pair.Value[x].DynamicInvoke
                    string methodName = pair.Value[x].Method.Name;

                    if (pMethodName == null || methodName.Equals(pMethodName)) {
                        _sourceEventHandlerList.RemoveHandler(pair.Key, pair.Value[x]);
                        suppressedHandlers.Add(pair.Key, pair.Value);
                    }
                }
            }
        }
    } 
}

8
นี่เป็นวิธีแก้ปัญหาที่ซับซ้อนและไม่ควรใช้ในซอฟต์แวร์ระดับอุตสาหกรรม แนวทางที่ดีที่สุดดังกล่าว: จัดการการสมัครสมาชิกกิจกรรมและการยกเลิกการสมัครสมาชิกของคุณอย่างดีและคุณจะไม่พบปัญหาดังกล่าว
Tri Q Tran

ฉันยอมรับว่าเราไม่ควรใช้ภาพสะท้อนกับเหตุการณ์ที่ไม่สงบและการสมัครสมาชิกกิจกรรมและการยกเลิกการสมัครควรได้รับการจัดการโดยแอปพลิเคชัน ฉันคิดว่าประเด็นในการโต้วาทีควรจะถูกนำมาใช้ในช่วงเวลาที่ดีบักเพื่อหาว่าเรากำลังคร่ำครวญอะไรไปบ้าง นี่เป็นสิ่งที่ต้องมีในแอปพลิเคชันรุ่นเก่าที่คุณกำลังสร้างใหม่
Tiago Freitas Leal
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.