我有一个按钮控件,我需要删除所有连接到它的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
我想以后只添加一个事件处理程序,所以禁用将无济于事。 –