イベントからすべてのイベントハンドラーを削除する方法


367

コントロールに新しいイベントハンドラーを作成するには、次のようにします。

c.Click += new EventHandler(mainFormButton_Click);

またはこれ

c.Click += mainFormButton_Click;

イベントハンドラを削除するには、これを行うことができます

c.Click -= mainFormButton_Click;

しかし、イベントからすべてのイベントハンドラーをどのように削除しますか?


10
WPFソリューションを探して誰かがここに来た場合は、この回答を確認することをお勧めします。
ダグラス

1
設定できませんc.Click = nullか?
アレクサニア

これは、私がとんでもないほど複雑になっているものの1つです。単純なClear方法は明らかに労力が多すぎる
Zimano

回答:


167

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

button1がnullに設定されている場合、すべてのイベントハンドラーがbutton1にアタッチされていますか?
ダミアン

3
私が間違っているなら、私を修正しますが、すべきではないの最初の行RemoveClickEventで開始:FieldInfo f1 = typeof(Button)?をGetField使用するとnullが発生しますControl
プロテクター1

2
これはToolStripButtonsでは機能しないようです。RemoveClickEventのButtonをToolStripButtonに置き換えましたが、RemoveClickEventを呼び出した後もイベントはまだ残っています。誰かがこの問題の解決策を持っていますか?
スカリ

1
上記のMSDNのリンクでは、myButton.Click + = nullを試すことも推奨されています。すべてのデリゲートを削除する場合(クリック用ではなく、他のイベント用)
hello_earth 2013年

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

58
これは、イベントを所有している場合にのみ機能します。コントロールでそれをやってみてください。
Delyan、

227
...そして、イベントを所有している場合は、FindClicked = null;どちらかと言うと単純なものを書くことができます。
Jon Skeet、2012年

79
FindClickedとは何ですか?
Levitikon

3
これはKinectイベントでは機能しません- kinect.ColorFrameReady -= MyEventHander機能しますが、GetInvocationList()kinectインスタンスでデリゲートを反復するメソッドはありません。
ブレントファウスト

GetInvocationList見つかりません。
ジョーク・ファン

75

すべてのイベントハンドラーの削除から:

イベントを単にnullに設定することはできないため、大部分は直接はありません。

間接的に、実際のイベントをプライベートにして、イベントに追加/削除されるすべてのデリゲートを追跡するプロパティを作成できます。

次の点を考慮してください。

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コントロールを参照していると思いました。このようなラッピングは不可能かもしれません。
岐阜

4
あなたはコントロールを引き出すことができれば、そうするでしょう
トム・フォベア2011

これにより、2つのリストが維持されます。リセットについては、stackoverflow.com / questions / 91778 / を参照してください。リストにアクセスするには、stackoverflow.com / questions / 91778 / を参照してください。
TN。

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。
マイスターシュニッツェル2014年

1
BindingFlags.Public最初のGetField呼び出しで使用するまで、WPFイベントでは機能しませんでした。
Lennart 2017

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されていないオブジェクトはもうありません。


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

あなたが本当にこれをしなければならないなら...これを行うには熟考とかなりの時間がかかります。イベントハンドラーは、コントロール内のイベントからデリゲートへのマップで管理されます。あなたはする必要があります

  • このマップをコントロールインスタンスに反映して取得します。
  • イベントごとに繰り返し、デリゲートを取得します
    • 各デリゲートは、一連のイベントハンドラーのチェーンにすることができます。そのため、obControl.RemoveHandler(event、handler)を呼び出します

要するに、たくさんの仕事。理論的には可能です...私はこのようなことを試したことはありません。

コントロールのサブスクライブ/サブスクライブ解除フェーズよりも優れた制御/規律ができるかどうかを確認します。


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_redrawed。
gracchus 2013年

4
フランス語からの翻訳 foreach (EventHandler<MyCompletedArgs> handler in CompletionCompleted.GetInvocationList()) { CompletionCompleted -= handler; }
アントンK

@AntonKによる英語の翻訳はうまくいきます。プロパティハンドラでnullを確認することを忘れないでください。
ブレット

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
これは非常に役に立ちましたが、変更する必要があることが1つあります。Resume()では、ハンドラーを逆の順序で追加し直しています(これは、Suppressからのコピー/貼り付けであり、逆方向に作業したいためです。あなたが繰り返しているコレクションを台無しにしないように)。一部のコードは、ハンドラーが指定された順序で実行されることに依存しているため、これをいじる必要はありません。
マイケル

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だけが必要なのに、なぜ新しいオブジェクトを作成する必要があるのでしょうか。EventHandlerListにアクセスできるc-torがないので、コンポーネントの内部で構築されたものしか取得できませんか?
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]);
    }
}

さて、この拡張の使い方。ボタンからクリックイベントを削除する必要がある場合は、

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

パネルからdoubleclickイベントを削除する必要がある場合は、

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

私はC#の専門家ではないので、バグがありましたらご容赦ください。親切にお知らせください。


1
.CastTo <>()拡張メソッドは正確にどこにあるのですか?
IbrarMumtaz

あなたは自分で書くことができます:public static T CastTo <T>(this object objectToCast){return(T)objectToCast; }
KingOfHypocrites

0

時にはサードパーティのコントロールを使用する必要があり、これらの厄介なソリューションを構築する必要があります。@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);

this.button1.MouseDown-= Delegate.CreateDelegate(typeof(EventHandler)、this、 "button1_MouseDownClicked")を実行するだけです。したがって、特にデリゲートがインラインの場合、削除するデリゲートを見つける方法であるという質問の解決には役立ちません。
Softlion 2013年

-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 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.