事件处理程序为null

时间:2013-07-30 03:46:21

标签: c# events

我目前正在玩LeapSDK。我想创建一个自定义类来封装LeapSDK,这样我就可以将它简单地导入到我将来创建的任何应用程序中。

LeapSDK为开发人员提供了一个接口,可以向控制器添加监听器。我们可以定义在侦听器中做什么。

事实上,我的问题与LeapSDK无关,但我想告诉我在做什么,以便你了解我的需求。因为我不确定我是否正在以一种好的方式工作,你可能会有一些建议,比如以聪明的方式做同样的事情。请随时分享。

所以,这是一个描述它如何工作的示例(示例由SDK提供):

class Sample
{
    public static void Main ()
    {
        SampleListener listener = new SampleListener ();
        Controller controller = new Controller ();

        // Have the sample listener receive events from the controller
        controller.AddListener (listener);

        // Keep this process running until Enter is pressed
        Console.WriteLine ("Press Enter to quit...");
        Console.ReadLine ();

        // Remove the sample listener when done
        controller.RemoveListener (listener);
        controller.Dispose ();
    }
}
class SampleListener : Listener
{
    private Object thisLock = new Object ();

    private void SafeWriteLine (String line)
    {
        lock (thisLock) {
            Console.WriteLine (line);
        }
    }

    public override void OnInit (Controller controller)
    {
        SafeWriteLine ("Initialized");
    }

    public override void OnConnect (Controller controller)
    {
        SafeWriteLine ("Connected");
        controller.EnableGesture (Gesture.GestureType.TYPECIRCLE);
        controller.EnableGesture (Gesture.GestureType.TYPEKEYTAP);
        controller.EnableGesture (Gesture.GestureType.TYPESCREENTAP);
        controller.EnableGesture (Gesture.GestureType.TYPESWIPE);
    }

    public override void OnDisconnect (Controller controller)
    {
        //Note: not dispatched when running in a debugger.
        SafeWriteLine ("Disconnected");
    }

    public override void OnExit (Controller controller)
    {
        SafeWriteLine ("Exited");
    }
}

我已经测试了上面的代码,它运行得很好。

现在让我们转到我的问题。我创建了一个名为 LeapEventInterpretator 的类,它有一个事件监听器,用于响应设备生成的事件,就像上面的方法一样。我尝试将一个事件处理程序传递给侦听器,以便侦听器可以调用它来生成主应用程序线程的事件。

这是我的代码:

    class LeapEventInterpretator
{
    private Controller controller;
    private DeviceEventListener deviceEventListener;

    public delegate void LeapEventHandler(object sender, Gesture args);
    public event LeapEventHandler GestureDetected;

    public LeapEventInterpretator()
    {
        Connect();    
    }
    private void Connect()
    {
        controller = new Controller();

        deviceEventListener = new DeviceEventListener(GestureDetected);
        controller.AddListener(deviceEventListener);

    }

    public enum Gesture { SwipeLeft, SwipeRight };
}

class DeviceEventListener : Listener
{
    LeapEventInterpretator.LeapEventHandler handler;
    public DeviceEventListener(LeapEventInterpretator.LeapEventHandler h)
    {
        this.handler = h;
    }
    public override void OnConnect(Controller arg0)
    {
        if (this.handler != null)
            handler(this, LeapEventInterpretator.Gesture.SwipeLeft);
    }
}

当引发OnConnect时,this.handler为null,然后我无法将自定义事件触发到app类。有什么想法吗?

同样,这可能是解决问题的愚蠢方法。即使对我自己,我也不觉得将事件处理程序传递给另一个类,但我想不出另一种方法来完成这项工作。所以请随时发表评论。

非常感谢你的帮助。

1 个答案:

答案 0 :(得分:1)

在这种情况下,您不希望将事件作为参数传递给侦听器。您希望将回调传递给将引发事件的方法(即委托)。

在您的示例中,行deviceEventListener = new DeviceEventListener(GestureDetected);正在将未初始化的委托(为空)传递给侦听器。这是因为您没有将事件作为参数传递给事件的自动生成的后备字段的值。一个事件只不过是一对方法,添加和删除,外部代码可以用来说“订阅我”或“取消订阅我”。

你想做更像这样的事情:

class LeapEventInterpretator
{
    private Controller controller;
    private DeviceEventListener deviceEventListener;

    public delegate void LeapEventHandler(object sender, Gesture args);
    public event LeapEventHandler GestureDetected;

    public LeapEventInterpretator()
    {
        Connect();    
    }
    private void Connect()
    {
        controller = new Controller();

        // pass a callback that will raise the event.
        deviceEventListener = new DeviceEventListener(RaiseGestureDetected);
        controller.AddListener(deviceEventListener);

    }

    // a method to raise the event
    private void RaiseGestureDetected(Gesture gesture)
    {
         var handler = GestureDetected;
         if (handler != null)
             handler(this, gesture);
    }

    public enum Gesture { SwipeLeft, SwipeRight };
}

class DeviceEventListener : Listener
{
    Action<LeapEventInterpretator.Gesture> handler;
    public DeviceEventListener(Action<LeapEventInterpretator.Gesture> h)
    {
        this.handler = h;
    }
    public override void OnConnect(Controller arg0)
    {
        if (this.handler != null)
            handler(LeapEventInterpretator.Gesture.SwipeLeft);
    }
}

我不确定OnConnect方法对我有意义,但现在你应该在调用OnConnect时触发事件。

当然,你必须为活动签名:

var interpreter = new LeapEventInterpretator();
intpreter.GestureDetected += (o, g) => { Console.WriteLine("Gesture detected: {0}", g); };
// do something to make the OnConnected get called.