8

Iam trying to get the Click event of a button via reflection and this is my code :

Assembly assem = Assembly.GetExecutingAssembly();

Type tExForm = btnSave.GetType();
Object exFormAsObj = Activator.CreateInstance(tExForm);

EventInfo evClick = tExForm.GetEvent("Click");
Type tDelegate = evClick.EventHandlerType;

MethodInfo miHandler=
btnSave.GetType().GetMethod("Click",
BindingFlags.NonPublic | BindingFlags.Instance);

Delegate d = Delegate.CreateDelegate(tDelegate, btnSave, miHandler);

MethodInfo addHandler = evClick.GetAddMethod();
Object[] addHandlerArgs = { d };
addHandler.Invoke(exFormAsObj, addHandlerArgs);

However the miHandler variable is always null!

Note The main issue I am concerned in is how to invoke an event of a specific control at run time, is there a way? For example I want to choose which click event to trigger when the user presses F1.

Legends
  • 21,202
  • 16
  • 97
  • 123
Hasan Shouman
  • 2,162
  • 1
  • 20
  • 26

2 Answers2

7

Based on additional comments below the question, the real goal is to raise an event via reflection.

I'll start by saying this is almost guaranteed to be a really terrible idea. It's going to be error-prone and brittle; it's just asking for bugs. What I'd recommend instead is having many event handlers (button click handler, keypress event handler, etc.) all simply call a common method which does the actual thing you want.

That having been said, here's how to do it. Reflection is always brittle, and this is a prime example of it - you have to rely on the current implementation details of how events in .NET work, which could change tomorrow, and this will stop working. You get a private field stored on the object which holds references to all the subscribing event handlers, loop through each one and invoke it. You also need to manually create the arguments that will be passed (like the EventArgs):

var eventArgs = EventArgs.Empty; //replace with real args

var eventInfo = tExForm.GetType().GetEvent("Click", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
var eventDelegate = (MulticastDelegate)tExForm.GetType().GetField("Click", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(tExForm);
if (eventDelegate != null)
{
  foreach (var handler in eventDelegate.GetInvocationList())
  {
    handler.Method.Invoke(handler.Target, new object[] { tExForm, eventArgs });
  }
}
Rex M
  • 142,167
  • 33
  • 283
  • 313
3

You should include the BindingFlag.FlattenHierarchy since Click is defined on Control, not Button.

EventInfo miHandler =
  btnSave.GetType(). GetEvent("Click",
  BindingFlags.FlattenHierarchy | BindingFlags.Instance);
djv
  • 15,168
  • 7
  • 48
  • 72
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325