Question

I have a problem concerning Events and Reflection in C#. I'm currently programming with the Microsoft Kinect (SDK 1.7) and want to implement a different click than the "Push-To-Press"-Approach. The ClickEvent itself is declared in the KinectControl class.

    public partial class KinectControl : UserControl
    {
        /**
        \brief Default Click event 
        */

        public static readonly RoutedEvent ClickEvent =
            EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(KinectControl)); 
        [...]

        public event RoutedEventHandler Click
        {
            add
            {
                AddHandler(ClickEvent, value);
            }
            remove
            {
                RemoveHandler(ClickEvent, value);
            }
        }
    } 

The Control which should raise this ClickEvent and invoke the proper method is a "Menu_Point"-object which inherits from the KinectControl-class.

After recognizing a click gesture, the "source" respectively "Menu_Point"-object raises the ClickEvent like this:

invokeCtrl.Raise<RoutedEventArgs>("Click", new RoutedEventArgs(KinectControl.ClickEvent));

which calls the following method:

        public static void Raise<TEventArgs>(this object source, string eventName, TEventArgs eventArgs) where TEventArgs : EventArgs
    {
        var list = 
            source.GetType().GetFields(BindingFlags.Public | 
            BindingFlags.NonPublic | BindingFlags.Instance | 
            BindingFlags.Static | BindingFlags.SetField | 
            BindingFlags.InvokeMethod | BindingFlags.Instance);
        FieldInfo fieldInfo = 
            source.GetType().GetField(eventName, BindingFlags.Public | 
            BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static |
            BindingFlags.GetField);

        var eventDelegate = 
            (MulticastDelegate)fieldInfo.GetValue(source);

        if (eventDelegate != null)
        {
            foreach (var handler in eventDelegate.GetInvocationList())
            {
                handler.Method.Invoke(handler.Target, new object[]{ source, eventArgs });
            }
        }
    }

It works fine intil the Raise-method is called and gets to this line: FieldInfo fieldInfo = source.GetType().GetField(eventName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.GetField); I don't know why, but the fieldInfo ist always remaining null which causes an exception if eventDelegate is trying to get access to it. Unfortunately I'm not able to find the reason why the ClickEvent is not found in this case. The member eventName has the value "Click" which is the name of the Event in the KinectControl-class. I also searched this site for answers (but none of the solutions helped me so far) and I read all kinds of regarding blogs like DotNetPearls.com but still I can't seem to find the mistake here. I hope you can help me out. Thanks in advance!

Edit: added BindingFlags.Static; forgot that in the FieldInfo. Thanks @Michael Gunter. Still doesn't work, though.

Was it helpful?

Solution

It would be better if you just invoke UIElement.RaiseEvent - RoutedEvents don't need to have an actual EventHandler implementation - that's why they simply delegate that work to UIElement.AddHandlerand UIElement.RemoveHandler.

Having said that - here's how you'll most likely find the event:

    public static RoutedEvent GetEvent(this UIElement source, string eventName)
    {
        if (source == null)
            throw new ArgumentNullException("source");

        if (string.IsNullOrEmpty(eventName))
            throw new ArgumentException("eventName");

        // check if the type is directly in there, otherwise you need a second pass and a more general approach
        RoutedEvent routedEvent = null;

        // this may return null...
        RoutedEvent[] events = EventManager.GetRoutedEventsForOwner(source.GetType());

        if (events != null)
            routedEvent = events.FirstOrDefault(p => p.Name == eventName);

        return routedEvent ?? EventManager.GetRoutedEvents().FirstOrDefault(p => p.OwnerType.IsInstanceOfType(source) && p.Name == eventName);
    }

    public static void RaiseEvent(this UIElement source, string eventName)
    {
        RoutedEvent routedEvent = GetEvent(source, eventName);

        if (routedEvent != null)
            source.RaiseEvent(new RoutedEventArgs(routedEvent, source));
    }
}

Hope this helps!

OTHER TIPS

This seems to work:

var eventField = source.GetType().GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic);
var eventDelegate = eventField.GetValue(source) as MulticastDelegate;
if (eventDelegate != null)
    eventDelegate.DynamicInvoke(new object[] { source, eventArgs });
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top