How to get the delegate list form event of the control in WPF.
I have tried the following code but it will return the field info as null
TextBox cont = new TextBox();
cont.TextChanged += new TextChangedEventHandler(cont_TextChanged);
FieldInfo fi = cont.GetType().GetField("TextChanged", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.Public | BindingFlags.Static);
Delegate del = (Delegate)fi.GetValue(cont);
I dont know why the people say it's not possible:
Lets say you want to disable any event temporary, you can create a method like this:
static Delegate[] DisableEvents(this Control ctrl, string eventName)
{
PropertyInfo propertyInfo = ctrl.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
EventHandlerList eventHandlerList = propertyInfo.GetValue(ctrl, new object[] { }) as EventHandlerList;
FieldInfo fieldInfo = typeof(Control).GetField("Event"+eventName, BindingFlags.NonPublic | BindingFlags.Static);
object eventKey = fieldInfo.GetValue(ctrl);
var eventHandler = eventHandlerList[eventKey] as Delegate;
Delegate[] invocationList = eventHandler.GetInvocationList();
foreach (EventHandler item in invocationList)
{
ctrl.GetType().GetEvent(eventName).RemoveEventHandler(ctrl, item);
}
return invocationList;
}|
You can call it like this:
var events = textbox1.DisableEvents("GotFocus")
If you want to add them again you just need to go through the events list.
The approach described in the previous answer works perfectly. However, to use it, you need to be sure that the event is implemented not as a field, but as a property. At the same time, the reference to the delegate is stored in the internal object of the Dictionary class. You can read more here: How to: Use a Dictionary to Store Event Instances (C# Programming Guide)
Reflection, as recommended by Kenneth J. Sanchez Venegas, is the only way to get an invocation list of event outside of a class. But when performance is important, we can make a helper with compiled lambdas like this:
public class EventHelper<TClass, TDelegate> where TDelegate : Delegate
{
public EventHelper(string eventName)
{
var fieldInfo = typeof(TClass).GetField(eventName, BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance) ??
throw new ArgumentException("Event was not found", nameof(eventName));
var thisArg = Expression.Parameter(typeof(TClass));
var body = Expression.Convert(Expression.Field(thisArg, fieldInfo), typeof(TDelegate));
Get = Expression.Lambda<Func<TClass, TDelegate?>>(body, thisArg).Compile();
}
public Func<TClass, TDelegate?> Get { get; }
public IEnumerable<TDelegate> GetInvocationList(TClass forInstance)
{
var eventDelegate = Get(forInstance);
if (eventDelegate is null)
yield break;
foreach (var d in eventDelegate.GetInvocationList())
yield return (TDelegate)d;
}
}
Assuming we will have one instance of this helper and use it every time:
private static readonly EventHelper<JsonSerializer, EventHandler<ErrorEventArgs>> _errorHelper = new(nameof(JsonSerializer.Error));
...
JsonSerializerSettings settings = new();
foreach (var errorHandler in _errorHelper.GetInvocationList(serializer))
settings.Error += errorHandler;
...
*I'm using this code to extract settings from Json.NET JsonSerializer so examples are taken from that context
**Code examples using C# 9.0 syntax features, tested on .NET 5 and .NET 6.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With