C# 如何删除';单击';发生';按钮';?
我有一个按钮控件,我需要删除所有附加到其上的事件处理程序 那怎么可能呢C# 如何删除';单击';发生';按钮';?,c#,.net,events,event-handling,C#,.net,Events,Event Handling,我有一个按钮控件,我需要删除所有附加到其上的事件处理程序 那怎么可能呢 Button button = GetButton(); button.Click.RemoveAllEventHandlers(); 你不能,基本上-至少不能没有反思和大量的肮脏 事件严格来说是“订阅,取消订阅”-你不能取消订阅其他人的处理程序,就像你不能更改其他人对对象的引用一样。我在StackOverflow上找到了这个答案: 最初的海报发现: 注意:由于我发布原始答案的问题已结束,我将在此处交叉发布我答案的改进版
Button button = GetButton();
button.Click.RemoveAllEventHandlers();
你不能,基本上-至少不能没有反思和大量的肮脏
事件严格来说是“订阅,取消订阅”-你不能取消订阅其他人的处理程序,就像你不能更改其他人对对象的引用一样。我在StackOverflow上找到了这个答案: 最初的海报发现: 注意:由于我发布原始答案的问题已结束,我将在此处交叉发布我答案的改进版本此答案仅适用于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);
}
Edit:我复制了,当没有订阅任何事件处理程序时,它会阻止方法抛出
NullReferenceException
。积分(和投票)应该在他们的答案上。我有一个空错误问题,代码是杰米·迪克森(Jamie Dixon)在没有点击事件的情况下发布的
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添加额外的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);
}
//
///从指定元素中删除订阅指定路由事件的所有事件处理程序。
///
///定义路由事件的UI元素。
///要删除其事件处理程序的路由事件。
公共静态空隙清除器OutDeventhandler(UIElement元素,RoutedEvent RoutedEvent)
{
//获取EventHandlersStore实例,该实例保存指定元素的事件处理程序。
//EventHandlersStore类声明为内部。
var eventHandlersStoreProperty=typeof(UIElement).GetProperty(
“EventHandlersStore”,BindingFlags.Instance | BindingFlags.NonPublic);
对象eventHandlersStore=eventHandlersStoreProperty.GetValue(元素,null);
if(eventHandlersStore==null)返回;
//在EventHandlersStore实例上调用GetRoutedEventHandlers方法
//用于获取订阅的事件处理程序数组。
var getRoutedEventHandlers=eventHandlersStore.GetType().GetMethod(
“GetRoutedEventHandler”,BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var routedEventHandlers=(RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke(
eventHandlersStore,新对象[]{routedEvent});
//迭代地从元素中删除所有路由事件处理程序。
foreach(路由EventHandler中的变量routedEventHandler)
元素。RemoveHandler(routedEvent,routedEventHandler.Handler);
}
我正在处理WinForms项目,在该项目中,我必须从ToolStripMenuItem中删除click EventHandler,并将其替换为我自己的处理程序。(我必须修改单击上下文菜单项时采取的操作)
对我来说,来自user2113340的代码不起作用。为了使用ToolStripMenuItem,我不得不这样修改它:
private void RemoveClickEvent(ToolStripMenuItem control)
{
FieldInfo eventClick = typeof(Control).GetField("EventClick", BindingFlags.NonPublic | BindingFlags.Static);
PropertyInfo eventsProp = typeof(Component).GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
EventHandlerList events = (EventHandlerList)eventsProp.GetValue(control, null);
FieldInfo headInfo = events.GetType().GetField("head", BindingFlags.NonPublic | BindingFlags.Instance);
object head = headInfo.GetValue(events);
FieldInfo keyType = head.GetType().GetField("key", BindingFlags.NonPublic | BindingFlags.Instance);
object key = keyType.GetValue(head);
Delegate d1 = events[key];
events.RemoveHandler(key, d1);
}
不过这是具体实现的问题——答案出现在2008年,我甚至不想说它是否能在.NET4上运行。依赖这样的东西是一个非常糟糕的主意。谢谢,但是这一行总是返回null:typeof(Control).GetField(“EventClick”,BindingFlags.Static | BindingFlags.NonPublic);我实现了一个类似的解决方案,该解决方案使用EventHandlerList对象的几个内部方法。查看答案你能用MyButtonClass替换Button吗?我想更简单的方法是禁用Button我想在之后只添加一个事件处理程序,所以禁用不会有帮助。可能重复我知道这是一个非常老的问题,但我认为您可能应该将所选答案改为道格拉斯给出的反射选项。“你不能”是一个非常糟糕的答案,尤其是当有一个非常好的例子表明你现在可以的时候;取消订阅其他人的处理程序!我正在使用第三方的自定义按钮,并希望删除作者的单击事件处理程序…@William:基本上,如果不依赖实现细节和反射,就不能删除,除非自定义按钮公开此类行为。事件的封装是为了处理程序不会相互干扰。@William:1)您使用控件的方式不是为它设计的,因此很容易造成问题。2) 您的解决方案很可能在将来的版本中中断。3) 它在信任度低的环境中不起作用。基本上,你希望你的代码有多脆弱;考虑设计而不仅仅是实现。我已经创建了自己的自定义按钮,并从原始按钮复制了我需要的(图标等)。是否可以在silverlight中执行此操作?silverlight没有路由EventHandlerInfo。。。。是否可以将其扩展为扩展方法?那太好了。。。
/// <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);
}
private void RemoveClickEvent(ToolStripMenuItem control)
{
FieldInfo eventClick = typeof(Control).GetField("EventClick", BindingFlags.NonPublic | BindingFlags.Static);
PropertyInfo eventsProp = typeof(Component).GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
EventHandlerList events = (EventHandlerList)eventsProp.GetValue(control, null);
FieldInfo headInfo = events.GetType().GetField("head", BindingFlags.NonPublic | BindingFlags.Instance);
object head = headInfo.GetValue(events);
FieldInfo keyType = head.GetType().GetField("key", BindingFlags.NonPublic | BindingFlags.Instance);
object key = keyType.GetValue(head);
Delegate d1 = events[key];
events.RemoveHandler(key, d1);
}