我有一個按鈕控件,我需要刪除所有連接到它的Click event的事件處理程序。如何刪除「按鈕」的「點擊」事件的所有事件處理程序?
這怎麼可能?
Button button = GetButton();
button.Click.RemoveAllEventHandlers();
我有一個按鈕控件,我需要刪除所有連接到它的Click event的事件處理程序。如何刪除「按鈕」的「點擊」事件的所有事件處理程序?
這怎麼可能?
Button button = GetButton();
button.Click.RemoveAllEventHandlers();
你不能,基本上 - 至少不是沒有反思和大量的不滿。
事件嚴格地是「訂閱,取消訂閱」 - 你不能取消訂閱別人的處理程序,除了你可以改變別人對對象的引用。
這正是我想要的;取消訂閱別人的處理程序!我正在使用第三方的自定義按鈕,並希望刪除作者的單擊事件處理程序... –
@William:你基本上不能 - 除非自定義按鈕公開這樣的行爲,否則不能不依賴實現細節和反射。事件的封裝是處理程序不會相互干擾。 –
使用反射它有什麼問題? –
我在這裏找到這個答案在計算器上:
How to remove all event handlers from a control
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]);
}
其中的原始海報發現here:
雖然這是特定於實現的 - 答案出現在2008年,但我甚至不想說它是否可以在.NET 4上工作。依靠這樣的事情是一個非常糟糕的主意。 –
謝謝,但這行總是返回null:typeof(Control).GetField(「EventClick」,BindingFlags.Static | BindingFlags.NonPublic); –
我實現了一個類似的解決方案,它使用EventHandlerList對象的更多內部方法。看到答案http://stackoverflow.com/questions/11031149/solution-to-remove-event-handler-dynamically-using-reflection-is-there-a-bett –
注意:由於這個問題上,我貼我的原答案已關閉as a duplicate這個問題,我交叉發佈我的答案的改進版本他回覆。 此答案只適用於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);
編輯:我已經複製了bug fix implemented by corona,從扔NullReferenceException
在任何情況下,停止方法處理程序已訂閱。信用(和upvotes)應該去他們的答案。
是否有可能在silverlight做到這一點? silverlight沒有RoutedEventHandlerInfo。 –
...這可以擴展成擴展方法嗎?這將是非常甜蜜的... – Will
我的代碼Jamie Dixon發佈了一個空錯誤問題,並且沒有發生Click事件。
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]);
}
}
我想這可以做得更好,但它適用於我目前的需要。希望這對某人有用。
只是想擴大道格拉斯的例程略,我非常喜歡。 我發現我需要將額外的空檢查添加到eventHandlersStore來處理傳遞的元素沒有附加任何事件的任何情況。
/// <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);
}
你可以使用MyButtonClass替換Button嗎? –
我認爲更簡單的方法是禁用按鈕 – V4Vendetta
我想以後只添加一個事件處理程序,所以禁用將無濟於事。 –