Làm cách nào để xóa tất cả các trình xử lý sự kiện khỏi một sự kiện


366

Để tạo một trình xử lý sự kiện mới trên một điều khiển, bạn có thể làm điều này

c.Click += new EventHandler(mainFormButton_Click);

hoặc cái này

c.Click += mainFormButton_Click;

và để loại bỏ một trình xử lý sự kiện, bạn có thể làm điều này

c.Click -= mainFormButton_Click;

Nhưng làm thế nào để bạn loại bỏ tất cả các trình xử lý sự kiện từ một sự kiện?


10
Nếu bất cứ ai đến đây tìm kiếm một giải pháp WPF, bạn có thể muốn xem câu trả lời này .
Douglas

1
Bạn có thể không chỉ thiết lập c.Click = null?
alexania

Đây là một trong những điều mà tôi thấy quá lố bịch. Một Clearphương pháp đơn giản là quá nhiều nỗ lực rõ ràng
Zimano

Câu trả lời:


167

Tôi tìm thấy một giải pháp trên các diễn đàn MSDN . Mã mẫu dưới đây sẽ loại bỏ tất cả các Clicksự kiện từ 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]);
        }
    }
}

Nếu button1 được đặt thành null, tất cả các trình xử lý sự kiện được đính kèm với button1. Nhấp vào được xử lý đúng không?
Damien

3
Sửa lỗi cho tôi nếu tôi sai, nhưng không phải là dòng đầu tiên RemoveClickEventbắt đầu bằng : FieldInfo f1 = typeof(Button)? Tôi nhận được null từ GetFieldnếu tôi sử dụng Control.
Người bảo vệ một

2
Điều này dường như không hoạt động cho ToolStripButtons. Tôi đã thay thế Nút trong RemoveClickEvent bằng ToolStripButton, nhưng các sự kiện vẫn diễn ra sau khi gọi RemoveClickEvent. Có ai có một giải pháp cho vấn đề này?
Skalli

1
liên kết trên trong MSDN cũng đề nghị dùng thử myButton.Click + = null; nếu bạn muốn xóa tất cả các đại biểu (không phải cho Nhấp chuột, nhưng cho các sự kiện khác ..)
hello_earth

1
@hello_earth Dường như không hoạt độngObservableCollection.CollectionChanged += null;
Mike de Klerk

146

Các bạn đang làm cho CÁCH này quá khó khăn với chính mình. Thật dễ dàng:

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

57
Điều này sẽ chỉ hoạt động nếu bạn sở hữu sự kiện. Hãy thử làm điều đó trên một điều khiển.
Delyan

226
... Và nếu bạn sở hữu sự kiện này, bạn có thể viết FindClicked = null;nó khá đơn giản.
Jon Skeet

79
FindClicky là gì?
Levitikon

3
Điều này không hoạt động đối với các sự kiện Kinect - kinect.ColorFrameReady -= MyEventHanderkhông, nhưng không có GetInvocationList()phương pháp nào trong các trường hợp kinect để lặp lại các đại biểu của họ.
Brent Faust

GetInvocationListkhông tìm thấy.
Trò đùa Hoàng

75

Từ việc xóa tất cả các trình xử lý sự kiện :

Trực tiếp không, phần lớn vì bạn không thể đơn giản đặt sự kiện thành null.

Một cách gián tiếp, bạn có thể đặt sự kiện thực tế ở chế độ riêng tư và tạo một thuộc tính xung quanh nó để theo dõi tất cả các đại biểu được thêm / bớt vào nó.

Thực hiện như sau:

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
Tôi nghĩ rằng OP đang đề cập đến các điều khiển .net chung .. trong đó loại gói này có thể không thực hiện được.
Gishu

4
bạn có thể lấy được quyền kiểm soát, sau đó nó sẽ
Tom Fobear

Điều này cũng dẫn đến việc duy trì hai danh sách, xem stackoverflow.com/questions/91778/ Khăn để đặt lại hoặc stackoverflow.com/questions/91778/ vào để truy cập danh sách.
TN.

63

Câu trả lời được chấp nhận là không đầy đủ. Nó không hoạt động cho các sự kiện được khai báo là {add; tẩy;}

Đây là mã làm việc:

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
Phiên bản này đã làm việc cho tôi. Phiên bản được chấp nhận không hoạt động. +1 cho điều đó.
Meister Schnitzel

1
Không hoạt động cho các sự kiện WPF cho đến khi tôi sử dụng BindingFlags.Publictrong GetFieldcuộc gọi đầu tiên .
Lennart

40

Sẽ không có hại gì khi xóa một trình xử lý sự kiện không tồn tại. Vì vậy, nếu bạn biết những gì xử lý có thể có, bạn chỉ cần xóa tất cả chúng. Tôi chỉ có trường hợp tương tự. Điều này có thể giúp trong một số trường hợp.

Giống:

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

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

16

Tôi thực sự đang sử dụng phương pháp này và nó hoạt động hoàn hảo. Tôi đã được "truyền cảm hứng" bởi mã được viết bởi Aeonhack ở đây .

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

Trường MyEventEvent bị ẩn, nhưng nó tồn tại.

Gỡ lỗi, bạn có thể thấy d.targetđối tượng thực sự xử lý sự kiện và d.methodphương thức của nó như thế nào . Bạn chỉ phải loại bỏ nó.

Nó hoạt động rất tốt. Không có nhiều đối tượng không được GC vì xử lý sự kiện.


2
Xin vui lòng không viết câu trả lời bằng các ngôn ngữ khác.
Hille

10

Tôi ghét bất kỳ giải pháp hoàn chỉnh nào được hiển thị ở đây, tôi đã kết hợp và thử nghiệm ngay bây giờ, làm việc cho bất kỳ trình xử lý sự kiện nào:

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

Dễ dàng! Cảm ơn Stephen Punak.

Tôi đã sử dụng nó bởi vì tôi sử dụng một phương thức cục bộ chung để loại bỏ các đại biểu và phương thức cục bộ được gọi sau các trường hợp khác nhau, khi các đại biểu khác nhau được giải quyết.


4

Nếu bạn thực sự phải làm điều này ... nó sẽ mất thời gian và khá lâu để làm điều này. Trình xử lý sự kiện được quản lý theo bản đồ từ sự kiện đến đại biểu trong một điều khiển. Bạn sẽ cần phải

  • Phản ánh và có được bản đồ này trong trường hợp kiểm soát.
  • Lặp lại cho mỗi sự kiện, nhận đại biểu
    • lần lượt mỗi đại biểu có thể là một chuỗi các trình xử lý sự kiện. Vì vậy, hãy gọi obControl.RemoveHandler (sự kiện, xử lý)

Tóm lại, rất nhiều công việc. Về mặt lý thuyết thì có thể ... Tôi chưa bao giờ thử thứ gì như thế này.

Xem nếu bạn có thể kiểm soát / kỷ luật tốt hơn trong giai đoạn đăng ký-hủy đăng ký để kiểm soát.


3

Stephen có quyền. Nó rất dễ:

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
Chúa ơi, trình biên dịch nên cấm loại tên biến đó. graphs_must_be_redrawn bằng tiếng Pháp.
gracchus

4
Dịch từ tiếng Pháp foreach (EventHandler<MyCompletedArgs> handler in CompletionCompleted.GetInvocationList()) { CompletionCompleted -= handler; }
Anton K

Bản dịch tiếng Anh của @AntonK hoạt động tốt. Hãy nhớ kiểm tra null trên trình xử lý tài sản.
Brett

2

Tôi vừa tìm thấy Cách tạm dừng các sự kiện khi đặt thuộc tính của điều khiển WinForms . Nó sẽ xóa tất cả các sự kiện khỏi một điều khiển:

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
Điều này rất hữu ích, nhưng có một điều cần phải thay đổi: Trong Resume (), bạn đang thêm trình xử lý theo thứ tự ngược lại (Tôi giả sử đó là bản sao / dán từ Suppress, nơi bạn muốn làm việc ngược lại như không gây rối với bộ sưu tập mà bạn đang lặp đi lặp lại). Một số mã dựa trên các trình xử lý bắn theo một thứ tự nhất định, vì vậy người ta không nên lộn xộn với điều đó.
Michael

1

Ồ Tôi tìm thấy giải pháp này, nhưng không có gì hoạt động như tôi muốn. Nhưng điều này là rất tốt:

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

Điều này chắc chắn là gọn gàng hơn câu trả lời trước. Liệu nó làm chính xác điều tương tự? Có vẻ như nó làm, nhưng có lẽ tôi đang thiếu một cái gì đó. Ngoài ra, tại sao bạn cần tạo một đối tượng mới khi tất cả những gì bạn muốn là một EventHandlerList? Không có c-tor có thể truy cập được cho EventHandlerList, sao cho người ta chỉ có thể lấy một cái được xây dựng bên trong cho một Thành phần?
Michael

1

Trang này đã giúp tôi rất nhiều. Mã tôi nhận được từ đây có nghĩa là để loại bỏ một sự kiện nhấp chuột từ một nút. Tôi cần xóa các sự kiện nhấp đúp từ một số bảng và nhấp vào các sự kiện từ một số nút. Vì vậy, tôi đã thực hiện một tiện ích mở rộng kiểm soát, sẽ loại bỏ tất cả các trình xử lý sự kiện cho một sự kiện nhất định.

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

Bây giờ, việc sử dụng extenstion này. Nếu bạn cần xóa các sự kiện nhấp chuột từ một nút,

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

Nếu bạn cần xóa các sự kiện doubleclick khỏi bảng điều khiển,

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

Tôi không phải là chuyên gia về C #, vì vậy nếu có bất kỳ lỗi nào xin vui lòng tha thứ cho tôi và vui lòng cho tôi biết về nó.


1
Phương thức mở rộng .CastTo <> () được tìm thấy chính xác ở đâu?
IbrarMumtaz

Bạn chỉ có thể tự viết: static static T CastTo <T> (đối tượng này objectToCast) {return (T) objectToCast; }
KingOfHypocites

0

Đôi khi chúng tôi phải làm việc với các điều khiển của ThirdParty và chúng tôi cần xây dựng các giải pháp khó xử này. Dựa trên câu trả lời @Anoop Muraleedharan Tôi đã tạo ra giải pháp này với loại suy luận và hỗ trợ 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]);
    }

Và bạn có thể sử dụng nó như thế này

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

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

0

Tôi tìm thấy một giải pháp làm việc khác của Douglas .

Phương pháp này loại bỏ tất cả các trình xử lý sự kiện được đặt trên một sự kiện định tuyến cụ thể trên một phần tử.
Sử dụng nó như

Remove_RoutedEventHandlers(myImage, Image.MouseLeftButtonDownEvent);

Mã đầy đủ:

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

xóa tất cả các trình xử lý cho nút: 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

Chà, ở đây có một giải pháp khác để loại bỏ một sự kiện liên quan (nếu bạn đã có một phương pháp để xử lý các sự kiện cho điều khiển):

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

Bạn chỉ có thể làm điều này. Vì vậy, nó sẽ không giúp giải quyết câu hỏi đó là làm thế nào để tìm ra đại biểu nào cần loại bỏ, đặc biệt nếu họ là nội tuyến.
Softlion

-1

Đây không phải là một câu trả lời cho OP, nhưng tôi nghĩ tôi sẽ đăng nó ở đây trong trường hợp nó có thể giúp đỡ người khác.

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

Tôi tìm thấy câu trả lời này và nó gần như phù hợp với nhu cầu của tôi. Cảm ơn SwDevMan81 cho lớp học. Tôi đã sửa đổi nó để cho phép triệt tiêu và tiếp tục các phương thức riêng lẻ và tôi nghĩ tôi sẽ đăng nó ở đây.

// 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
Đây là một giải pháp phức tạp và không bao giờ nên được sử dụng trong phần mềm cấp công nghiệp. Cách tiếp cận tốt nhất như đã đề cập: Quản lý đăng ký sự kiện của bạn và hủy đăng ký tốt và bạn sẽ không bao giờ gặp phải các vấn đề như vậy.
Tri Q Trần

Tôi đồng ý rằng chúng ta không nên sử dụng sự phản chiếu cho các sự kiện không mong muốn và đăng ký sự kiện và hủy đăng ký nên được ứng dụng quản lý. Tôi nghĩ rằng vấn đề trong cuộc tranh luận nên được sử dụng tại thời điểm DEBUG, để tìm hiểu xem chúng ta đang làm gì đó. Đây là điều bắt buộc đối với các ứng dụng cũ mà bạn đang tái cấu trúc.
Tiago Freitas Leal
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.