Поиск событий через отражение C#

У меня есть проблема, касающаяся событий и отражения в C#. В настоящее время я программирую с помощью Microsoft Kinect (SDK 1.7) и хочу реализовать щелчок, отличный от подхода "Push-To-Press". Сам ClickEvent объявлен в классе KinectControl.

    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);
            }
        }
    } 

Элемент управления, который должен вызывать этот ClickEvent и вызывать соответствующий метод, является объектом "Menu_Point", который наследуется от класса KinectControl.

После распознавания жеста щелчка объект "source" и соответственно "Menu_Point" вызывает ClickEvent следующим образом:

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

который вызывает следующий метод:

        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 });
            }
        }
    }

Он работает нормально, пока вызывается метод Raise и попадает в эту строку:FieldInfo fieldInfo = source.GetType().GetField(eventName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.GetField);Я не знаю почему, но поле информации всегда остается null что вызывает исключение, если eventDelegate пытается получить к нему доступ. К сожалению, я не могу найти причину, почему ClickEvent не найден в этом случае. Член eventName имеет значение "Click", которое является именем события в KinectControl-классе. Я также искал ответы на этом сайте (но ни одно из решений не помогло мне до сих пор), и я прочитал все виды блогов, таких как DotNetPearls.com, но все же я не могу найти ошибку здесь. Я надеюсь, что вы можете помочь мне. Заранее спасибо!

Редактировать: добавлено BindingFlags.Static; забыл, что в FieldInfo. Спасибо, Майкл Гюнтер. Тем не менее, не работает, хотя.

2 ответа

Решение

Было бы лучше, если бы вы просто призвать UIElement.RaiseEvent - RoutedEvents не нужно иметь фактическую реализацию EventHandler - поэтому они просто делегируют эту работу UIElement.AddHandlerа также UIElement.RemoveHandler,

Сказав это - вот как вы, скорее всего, найдете событие:

    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));
    }
}

Надеюсь это поможет!

Это похоже на работу:

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 });
Другие вопросы по тегам