web-dev-qa-db-ja.com

「ボタン」の「クリック」イベントのすべてのイベントハンドラーを削除するにはどうすればよいですか?

ボタンコントロールがあり、それに接続されているすべてのイベントハンドラーを削除する必要があります クリックイベント

それはどのように可能でしょうか?

Button button = GetButton();
button.Click.RemoveAllEventHandlers();
17
The Light

基本的にはできません-少なくとも反省と多くの不機嫌がなければ。

イベントは厳密に「サブスクライブ、サブスクライブ解除」です。他の誰かのオブジェクトへの参照を変更できる以上に、他の誰かのハンドラーのサブスクライブを解除することはできません。

9
Jon Skeet

:元の回答を投稿した質問が閉じられたので 重複として この質問のクロスです-私の答えの改善版をここに投稿します。 この回答はWPFにのみ適用されます。Windowsフォームやその他のUIフレームワークでは機能しません。

以下は、特定の要素でルーティングされたイベントにサブスクライブされているすべてのイベントハンドラーを削除するための便利なユーティリティメソッドです。必要に応じて、これを拡張メソッドに簡単に変換できます。

/// <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="routedEvent">The routed event for which to remove the event handlers.</param>
public static void RemoveRoutedEventHandlers(UIElement element, RoutedEvent routedEvent)
{
    // Get the EventHandlersStore instance which holds event handlers for the specified element.
    // The EventHandlersStore class is declared as internal.
    var eventHandlersStoreProperty = typeof(UIElement).GetProperty(
        "EventHandlersStore", BindingFlags.Instance | BindingFlags.NonPublic);
    object eventHandlersStore = eventHandlersStoreProperty.GetValue(element, null);

    // If no event handlers are subscribed, eventHandlersStore will be null.
    // Credit: https://stackoverflow.com/a/16392387/1149773
    if (eventHandlersStore == null)
        return;

    // Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance 
    // for getting an array of the subscribed event handlers.
    var getRoutedEventHandlers = eventHandlersStore.GetType().GetMethod(
        "GetRoutedEventHandlers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
    var routedEventHandlers = (RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke(
        eventHandlersStore, new object[] { routedEvent });

    // Iteratively remove all routed event handlers from the element.
    foreach (var routedEventHandler in routedEventHandlers)
        element.RemoveHandler(routedEvent, routedEventHandler.Handler);
}

次に、ボタンのClickイベントに対してこのユーティリティメソッドを簡単に呼び出すことができます。

RemoveRoutedEventHandlers(button, Button.ClickEvent);

編集コロナによって実装されたバグ修正 をコピーしました。これにより、イベントハンドラーがない場合にメソッドがNullReferenceExceptionをスローしなくなります。購読しています。クレジット(および賛成票)は彼らの答えに行くべきです。

36
Douglas

ダグラスのルーティンを少し拡張したかっただけで、とても気に入りました。渡された要素にまだイベントが添付されていない場合を処理するために、eventHandlersStoreに追加のnullチェックを追加する必要があることがわかりました。

/// <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="routedEvent">The routed event for which to remove the event handlers.</param>
public static void RemoveRoutedEventHandlers(UIElement element, RoutedEvent routedEvent)
{
    // Get the EventHandlersStore instance which holds event handlers for the specified element.
    // The EventHandlersStore class is declared as internal.
    var eventHandlersStoreProperty = typeof(UIElement).GetProperty(
        "EventHandlersStore", BindingFlags.Instance | BindingFlags.NonPublic);
    object eventHandlersStore = eventHandlersStoreProperty.GetValue(element, null);

    if (eventHandlersStore == null) return;

    // Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance 
    // for getting an array of the subscribed event handlers.
    var getRoutedEventHandlers = eventHandlersStore.GetType().GetMethod(
        "GetRoutedEventHandlers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
    var routedEventHandlers = (RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke(
        eventHandlersStore, new object[] { routedEvent });

    // Iteratively remove all routed event handlers from the element.
    foreach (var routedEventHandler in routedEventHandlers)
        element.RemoveHandler(routedEvent, routedEventHandler.Handler);
}
11
corona

私はここStackOverflowでこの答えを見つけました:

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

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

元のポスターが見つけたもの ここ

4
Jamie Dixon

Clickイベントがないことを考慮してJamieDixonが投稿したコードでnullエラーの問題が発生しました。

private void RemoveClickEvent(Control control)
{
    // chenged "FieldInfo f1 = typeof(Control)" to "var f1 = b.GetType()". By changing to 
    // the type of the  passed in control we can use this for any control with a click event.
    // using var allows for null checking and lowering the chance of exceptions.

    var fi = control.GetType().GetField("EventClick", BindingFlags.Static | BindingFlags.NonPublic);
    if (fi != null)
    {
        object obj = fi.GetValue(control);
        PropertyInfo pi = control.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
        EventHandlerList list = (EventHandlerList)pi.GetValue(control, null);
        list.RemoveHandler(obj, list[obj]);
    }

}

その後、小さな変更を加えれば、どんなイベントにも対応できるはずです。

private void RemoveClickEvent(Control control, string theEvent)
{
    // chenged "FieldInfo f1 = typeof(Control)" to "var f1 = b.GetType()". By changing to 
    // the type of the  passed in control we can use this for any control with a click event.
    // using var allows for null checking and lowering the chance of exceptions.

    var fi = control.GetType().GetField(theEvent, BindingFlags.Static | BindingFlags.NonPublic);
    if (fi != null)
    {
        object obj = fi.GetValue(control);
        PropertyInfo pi = control.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
        EventHandlerList list = (EventHandlerList)pi.GetValue(control, null);
        list.RemoveHandler(obj, list[obj]);
    }

}

これはもっと良くなると思いますが、私の現在のニーズにはうまくいきます。これが誰かに役立つことを願っています。

0
user2113340