Search code examples
.netwpfreflectionexpression-blend

How Does System.Windows.Interactivity.EventTrigger.EventName Efficiently Work With Or Without Reflection?


I see that the System.Windows.Interactivity.EventTrigger.EventName takes in a string. Also, I would imagine they need to hook up to that event via reflection.

But reflection has a bit of a bad name especially with performance, so are there performance issues with the System.Windows.Interactivity.EventTrigger. So is the code below the most efficient way to hook up to an event and is Expression Blend's SDK doing something special?

public class EventToCommand
{
    public static readonly DependencyProperty EventNameProperty = DependencyProperty.RegisterAttached("EventName", typeof(string), typeof(EventToCommand), new UIPropertyMetadata(OnEventHandlerChanged));

    public static string GetEventName(DependencyObject obj)
    {
        return (string)obj.GetValue(EventNameProperty);
    }

    public static void SetEventName(DependencyObject obj, string value)
    {
        obj.SetValue(EventNameProperty, value);
    }

    private static void OnEventHandlerChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        Type objType = obj.GetType();
        var info = objType.GetEvent((string)args.NewValue);

        MethodInfo handler = typeof(EventToCommand).GetMethod("OnEventHandlerRaised", BindingFlags.Instance | BindingFlags.NonPublic);
        var o = Activator.CreateInstance(typeof(EventToCommand));
        Delegate d = Delegate.CreateDelegate(info.EventHandlerType, o, handler);
        MethodInfo addHandler = info.GetAddMethod();
        object[] addHandlerArgs = { d };
        addHandler.Invoke(obj, addHandlerArgs);
    }

    private void OnEventHandlerRaised(object sender, EventArgs args)
    {
        // Is it a unique instance?
        Console.WriteLine(value);
    }

    Guid value = Guid.NewGuid();
    public EventToCommand()
    {
    }
}

Solution

  • The method I provided in my question is definitely the slower way to do it. The better way is to use the following and not use invoke:

        Type objType = obj.GetType();
        var info = objType.GetEvent((string)args.NewValue);
    
        MethodInfo handler = typeof(EventToCommand).GetMethod("OnEventHandlerRaised", BindingFlags.Instance | BindingFlags.NonPublic);
        var o = Activator.CreateInstance(typeof(EventToCommand));
        Delegate d = Delegate.CreateDelegate(info.EventHandlerType, o, handler);
        info.AddEventHandler(obj, d);
    

    The above method is a lot faster than using Reflection's invoke. You can then remove it via info.RemoveEventHandler(obj, d).