To create a new event handler on a control you can do this
c.Click += new EventHandler(mainFormButton_Click);
or this
c.Cli
Wow. I found this solution, but nothing worked like I wanted. But this is so good:
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);
}
I found this answer and it almost fit my needs. Thanks to SwDevMan81 for the class. I have modified it to allow suppression and resumation of individual methods, and I thought I'd post it here.
// 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);
}
}
}
}
}
}
From Removing All Event Handlers:
Directly no, in large part because you cannot simply set the event to null.
Indirectly, you could make the actual event private and create a property around it that tracks all of the delegates being added/subtracted to it.
Take the following:
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(); }
If you reaallly have to do this... it'll take reflection and quite some time to do this. Event handlers are managed in an event-to-delegate-map inside a control. You would need to
In short, a lot of work. It is possible in theory... I never tried something like this.
See if you can have better control/discipline over the subscribe-unsubscribe phase for the control.
I found another working solution by Douglas.
This method removes all event handlers which are set on a specific routet event on a element.
Use it like
Remove_RoutedEventHandlers(myImage, Image.MouseLeftButtonDownEvent);
Full code:
/// <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);
}
This page helped me a lot. The code I got from here was meant to remove a click event from a button. I need to remove double click events from some panels and click events from some buttons. So I made a control extension, which will remove all event handlers for a certain event.
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]);
}
}
Now, the usage of this extenstion. If you need to remove click events from a button,
Button button = new Button();
button.RemoveEvents(nameof(button.EventClick));
If you need to remove doubleclick events from a panel,
Panel panel = new Panel();
panel.RemoveEvents(nameof(panel.EventDoubleClick));
I am not an expert in C#, so if there are any bugs please forgive me and kindly let me know about it.