简体   繁体   English

通过反射C#查找事件

[英]finding events via reflection c#

I have a problem concerning Events and Reflection in C#. 我有一个关于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. 我目前正在使用Microsoft Kinect(SDK 1.7)进行编程,并希望实现与“按按”方法不同的单击。 The ClickEvent itself is declared in the KinectControl class. 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);
            }
        }
    } 

The Control which should raise this ClickEvent and invoke the proper method is a "Menu_Point"-object which inherits from the KinectControl-class. 应该引发此ClickEvent并调用适当方法的Control是从KinectControl类继承的“ Menu_Point”对象。

After recognizing a click gesture, the "source" respectively "Menu_Point"-object raises the ClickEvent like this: 识别点击手势后,“源”或“ Menu_Point”对象分别引发ClickEvent,如下所示:

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); 在调用Raise方法并到达此行之前,它工作正常: 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. 我不知道为什么,但是fieldInfo ist始终保持为null ,如果eventDelegate试图获取对它的访问权限,则会导致异常。 Unfortunately I'm not able to find the reason why the ClickEvent is not found in this case. 不幸的是,在这种情况下,我无法找到未找到ClickEvent的原因。 The member eventName has the value "Click" which is the name of the Event in the KinectControl-class. 成员eventName的值“ Click”是KinectControl类中Event的名称。 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. 我也在该站点上搜索了答案(但是到目前为止,没有一种解决方案对我有帮助),并且我阅读了各种有关DotNetPearls.com之类的博客,但我似乎仍然找不到这里的错误。 I hope you can help me out. 我希望你能帮助我。 Thanks in advance! 提前致谢!

Edit: added BindingFlags.Static ; 编辑:添加BindingFlags.Static ; forgot that in the FieldInfo. 在FieldInfo中忘记了。 Thanks @Michael Gunter. 谢谢@迈克尔·甘特。 Still doesn't work, though. 不过仍然无法正常工作。

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

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.AddHandler and UIElement.RemoveHandler . 如果只调用UIElement.RaiseEvent会更好-RoutedEvents不需要实际的EventHandler实现-这就是为什么它们仅将工作委托给UIElement.AddHandlerUIElement.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! 希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM