EventInfo.AddEventHandler Method

July 28, 2014

Adds an event handler to an event source.

Namespace:  System.Reflection
Assembly:  mscorlib (in mscorlib.dll)

public virtual void AddEventHandler(
	Object target,
	Delegate handler
)

Parameters

target
Type: System.Object
The event source.
handler
Type: System.Delegate
Encapsulation of a method or methods to be invoked when the event is raised by the target.

ExceptionCondition
InvalidOperationException

The event does not have a public add accessor.

ArgumentException

The handler that was passed in cannot be used.

TargetException

The target parameter is null and the event is not static.

-or-

The EventInfo is not declared on the target.

MemberAccessException

This member is invoked late-bound through mechanisms such as Type.InvokeMember.

Use the AddEventHandler method to hook up events in late-bound scenarios.

This method attempts to hook up an event handler for the current event on the event source specified by target, by calling the add accessor.

NoteNote:

In reflection, the add accessor can be obtained by calling the GetAddMethod method.

Version Notes

Windows Phone

 AddEventHandler throws ArgumentNullException instead of TargetException when target is null or the EventInfo is not declared on the target.

AddEventHandler throws ArgumentNullException instead of InvalidOperationException when the event does not have a public add accessor.

The example in this section shows how to do the following:

  • Determine the signature of an unknown event by using reflection, and emit an event handler by using a dynamic assembly.

  • Hook up the emitted event handler by using late binding.

  • Hook up a hard-coded event handler by using late binding, assuming that the event handler has the same signature as the event.

The example creates an instance of the System.Windows.Threading.DispatcherTimer class, stored in a variable of type Object. The example uses the Type.GetEvent method to get the DispatcherTimer.Tick event, and then uses the EventHandlerType property to get the delegate type for the event.

The example gets a MethodInfo for the Invoke method of the delegate type, and uses the MethodInfo to discover the signature of the delegate. The example then creates a dynamic assembly that contains a single type named Handler. Handler has a field to hold the TextBlock that is used for output, a constructor that takes a TextBlock and stores it in the field, and a method named DynamicHandler that handles the event.

After the dynamic type is created, the example gets a MethodInfo for the finished method and uses it to create a delegate instance. This instance is passed to the AddEventHandler method to hook up the event.

The example then uses the AddEventHandler method to hook up the hard-coded event handler, HardCodedHandler.

Finally, the example starts the timer and hooks up another event handler that lets you click the TextBlock to stop the example and unhook the events.


using System;
using System.Reflection;
using System.Reflection.Emit;

public class Example
{
   // The type used for this code example is the DispatcherTimer 
   // class. The Timer object is stored in a variable of type object,
   // and all code that accesses the Timer does so late-bound. This
   // is because the scenario in which you might use the AddEVentHander
   // method is when you load the type after the program is already
   // compiled, when it is not possible to use the Visual Basic
   // AddHandler syntax to hook up the event. 
   //
   private static object timer;

   private static System.Windows.Controls.TextBlock outputBlock;

   public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      Example.outputBlock = outputBlock;

      // Get a Type object for the TextBlock.
      Type obType = outputBlock.GetType();

      // Get a Type object representing the DispatcherTimer type.
      Type t = typeof(System.Windows.Threading.DispatcherTimer);

      // Create an instance of the Timer type.
      timer = Activator.CreateInstance(t);

      // Use reflection to get the Tick event.
      EventInfo eInfo = t.GetEvent("Tick");

      // In order to create a method to handle the Tick event,
      // it is necessary to know the signature of the delegate 
      // used to raise the event. Reflection.Emit can then be
      // used to construct a dynamic class with a static method
      // that has the correct signature.
      //
      // Get the event handler type of the Tick event. This is
      // a delegate type, so it has an Invoke method that has
      // the same signature as the delegate. The following code
      // creates an array of Type objects that represent the 
      // parameter types of the Invoke method.
      //
      Type handlerType = eInfo.EventHandlerType;
      MethodInfo invokeMethod = handlerType.GetMethod("Invoke");
      ParameterInfo[] parms = invokeMethod.GetParameters();
      Type[] parmTypes = new Type[parms.Length];
      for(int i = 0; i < parms.Length; i++)
      {
         parmTypes[i] = parms[i].ParameterType;
      }

      // Use Reflection.Emit to create a dynamic assembly that
      // will be run but not saved. An assembly must have at 
      // least one module, which in this case contains a single
      // type. The only purpose of this type is to contain the 
      // event handler method and the TextBlock where output is
      // displayed. 
      AssemblyName aName = new AssemblyName();
      aName.Name = "DynamicTypes";
      AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, 
                                                  AssemblyBuilderAccess.Run);
      ModuleBuilder mb = ab.DefineDynamicModule(aName.Name);
      TypeBuilder tb = mb.DefineType("Handler", TypeAttributes.Public);

      // Define a field to hold the TextBlock where output will
      // be displayed.
      FieldBuilder output = tb.DefineField("outputBlock", obType, FieldAttributes.Private);

      // Define a constructor that takes a TextBlock.
      Type[] ctorParams = {obType};
      ConstructorBuilder ctor = tb.DefineConstructor(MethodAttributes.Public, 
                                            CallingConventions.Standard, ctorParams);

      ILGenerator il = ctor.GetILGenerator();

      // Base class constructor.
      ConstructorInfo objCtor = typeof(object).GetConstructor(new Type[] {});
      il.Emit(OpCodes.Ldarg_0);
      il.Emit(OpCodes.Call, objCtor);

      // The constructor stores the TextBlock in the field. First, get 
      // the new DynamicHandler instance, then get the parameter passed
      // to the constructor, then store that value in the field.
      il.Emit(OpCodes.Ldarg_0);
      il.Emit(OpCodes.Ldarg_1);
      il.Emit(OpCodes.Stfld, output);
      // The stack is now clear. Return.
      il.Emit(OpCodes.Ret);

      // Create the method that will handle the event. The name
      // is not important.
      //
      // The parameter types and return type of the method are
      // the same as those of the delegate's Invoke method, 
      // captured earlier.
      MethodBuilder handler = tb.DefineMethod("DynamicHandler", 
                         MethodAttributes.Public, invokeMethod.ReturnType, parmTypes);

      // Generate code to handle the event. 
      il = handler.GetILGenerator();

      // In this case, the handler concatenates a text
      // string to the Text property of the TextBlock.
      // To obtain the current text from the text block, and to 
      // store the updated value, get the "get" and "set" accessors
      // for the Text property:
      PropertyInfo textProp = obType.GetProperty("Text");
      MethodInfo getter = textProp.GetGetMethod();
      MethodInfo setter = textProp.GetSetMethod();

      // To concatenate two strings, get the static Concat method of 
      // the String class:
      MethodInfo concat2 = typeof(string).GetMethod("Concat", 
                 BindingFlags.Public | BindingFlags.Static,
                 Type.DefaultBinder, 
                 new Type[] { typeof(string), typeof(string) }, null);

      // At the very end of the method, the TextBlock instance needs 
      // to be on the execution stack, to call the "set" accessor for
      // the Text property. The TextBlock is stored in the private 
      // field. Use the Handler instance to retrieve it.
      il.Emit(OpCodes.Ldarg_0);
      il.Emit(OpCodes.Ldfld, output);

      // The existing value of the TextBlock.Text property must be on
      // the stack, too, so load the TextBlock instance again. Then 
      // call the "get" accessor for the Text property. The second
      // TextBlock reference is popped off the stack, and the string 
      // value is pushed onto the stack.
      il.Emit(OpCodes.Ldarg_0);
      il.Emit(OpCodes.Ldfld, output);
      il.Emit(OpCodes.Callvirt, getter);

      // Load the output string, then call String.Concat to 
      // Concatenate the two strings.
      il.Emit(OpCodes.Ldstr, "Timer's Tick event is handled by Handler.DynamicHandler.\n");
      il.Emit(OpCodes.Call, concat2);

      // The stack now has an instance of TextBlock and the concatenated
      // string. Call the "set" accessor, which pops these items off the
      // stack and stores the string in the property. 
      il.Emit(OpCodes.Callvirt, setter);

      // There is nothing left on the stack, so it is safe to return 
      // from the void method.
      il.Emit(OpCodes.Ret);


      // CreateType must be called before the Handler type can
      // be used. Pass the TextBlock to the new instance of Handler.
      Type finished = tb.CreateType();
      object helper = Activator.CreateInstance(finished, new object[] { outputBlock });

      // In order to create the delegate that will
      // handle the event, a MethodInfo from the finished type
      // is required.
      MethodInfo eventHandler = finished.GetMethod("DynamicHandler");

      // Use the MethodInfo to create a delegate of the correct 
      // type, and call the AddEventHandler method to hook up 
      // the event.
      Delegate d = Delegate.CreateDelegate(handlerType, helper, eventHandler);
      eInfo.AddEventHandler(timer, d);

      // Save this delegate in a Shared field, so the StopExample
      // method can unhook it.
      emittedHandler = d;


      // Now add a second handler, using a hard-coded method (that is,
      // one that already exists in this class). In order to use this 
      // technique, you must know the signature of the unknown event 
      // at the time write your code. 
      d = Delegate.CreateDelegate(handlerType, 
                   typeof(Example).GetMethod("HardCodedHandler", 
                   BindingFlags.NonPublic | BindingFlags.Static));
      eInfo.AddEventHandler(timer, d);

      // Save this delegate in a Shared field, so the StopExample
      // method can unhook it.
      hcHandler = d;

      // Late-bound calls to the Interval and Start property 
      // are required to start the timer with a one-second
      // interval.
      t.InvokeMember("Interval", BindingFlags.SetProperty, null, timer, 
                                  new object[] { new TimeSpan(0, 0, 1) });
      t.InvokeMember("Start", BindingFlags.InvokeMethod, null, timer, null);


      // Add a handler for clicking the TextBlock, to stop the  
      // timer and unhook the handlers.
      outputBlock.MouseLeftButtonUp += 
         new System.Windows.Input.MouseButtonEventHandler(StopExample);
      outputBlock.Text += "Click here to stop the example.\r\n";

   }

   // An existing event handler that can be hooked up to an event
   // by using reflection, if the signature of the event matches the
   // signature of the handler.
   private static void HardCodedHandler(object sender, System.EventArgs e)
   {

      outputBlock.Text += "Timer's Tick event is handled by Example.HardCodedHandler.\n";
   }


   private static Delegate emittedHandler;
   private static Delegate hcHandler;

   private static void StopExample(object sender, System.Windows.Input.MouseButtonEventArgs e)
   {

      // Stop the timer.
      timer.GetType().InvokeMember("Stop", BindingFlags.InvokeMethod, null, timer, null);

      // Unhook the handlers.
      EventInfo eInfo = timer.GetType().GetEvent("Tick");
      eInfo.RemoveEventHandler(timer, emittedHandler);
      eInfo.RemoveEventHandler(timer, hcHandler);

      // Unhook the mouse event.
      outputBlock.MouseLeftButtonUp -= 
                new System.Windows.Input.MouseButtonEventHandler(StopExample);
      outputBlock.Text += "Refresh the page to run the example again.\r\n";
   }
}

/* This code example produces output similar to the following:

Press the Enter key to end the program.
Timer's Tick event is handled by Handler.DynamicHandler.
Timer's Tick event is handled by Example.HardCodedHandler.
Timer's Tick event is handled by Handler.DynamicHandler.
Timer's Tick event is handled by Example.HardCodedHandler.
Timer's Tick event is handled by Handler.DynamicHandler.
Timer's Tick event is handled by Example.HardCodedHandler.
Refresh the page to run the example again.
 */


Windows Phone OS

Supported in: 8.1, 8.0, 7.1, 7.0

Windows Phone

Show:
© 2014 Microsoft