是什么阻止我的事件处理程序方法完成?

What is preventing my event handler method from completing?

我正在使用 SerialPort、用于用户界面的 WPF、用于处理应用程序逻辑的 'ui' 对象以及 SerialPort 的包装器。

当触发 SerialPort.DataReceived 事件时调用相关方法。它开始 运行,然后在读取数据后,似乎就退出了,尽管它还有很多事情要做。

它似乎没有抛出任何异常,它不像卡在循环中一样(同步读取应该超时 + 我会得到大量 "I READ A THING"),而且我我难住了。几乎所有的 GiveFeedback 调用都是我尝试调试正在发生的事情的结果,因为我无法在我正在写这篇文章的机器上进行测试。

'ui' 符号指的是在调用 GiveFeedback(string) 时触发事件的对象,最终通过调用 Dispatcher.BeginInvoke(stuff) 更新文本框的内容。

完整代码如下:


public void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    try
    {
        ui.GiveFeedback("DataReceived... Begin");
        List<byte> bytes = new List<byte>();
        int r = comm.comPort.ReadByte();
        while ( r != -1 )
        {
            bytes.Add((byte) r);
            try
            {
                r = comm.comPort.ReadByte();
            }
            catch(Exception ioe)
            {
                r = -1;
                ui.GiveFeedback(ioe.Message);
            }
            ui.GiveFeedback("read a byte...");
            ui.GiveFeedback("read : '" + System.Text.Encoding.ASCII.GetString(bytes.ToArray()) + "'");
        }
        //It NEVER reaches this line.
        //It NEVER throws an exception of any kind.
        throw new ApplicationException("I threw myself");
        i.GiveFeedback("done read : '" + System.Text.Encoding.ASCII.GetString(bytes.ToArray()) + "'");

        string msg = BitConverter.ToString(bytes.ToArray()).Replace("-", " ");

        string submsg;
        if ( msg.Length > 5 )
            submsg = msg.Substring(0, 5);
        else
        {
            submsg = msg.Substring(0, 2);
        }
        ui.GiveFeedback("msg: " + msg);
        ui.GiveFeedback("submsg: " + submsg);

        switch ( submsg )
        {
            case "10":
                ui.GiveFeedback("'Incoming -- VMC: Reset - 10' -- CommInterface");
                ACK();
                break;

            case "00":
                //DisplayData(MessageType.Incoming, " VMC: ACK - 00\n");
                ui.GiveFeedback("'Incoming -- VMC: ACK - 00' -- CommInterface");
                break;

            case "12":
                ui.GiveFeedback("'Incoming -- VMC: Poll - 12' -- CommInterface");
                switch ( ui.Stage )
                {
                    case Stages.SessionSelect:
                        BeginSession();
                        Poll();
                        break;
                        default:
                            ACK();
                            break;
                }
                break;

            case "14 01":
                //DisplayData(MessageType.Incoming, " VMC: Enable Reader - 14 01\n");
                ui.GiveFeedback("'Incoming -- VMC: Enable Reader - 14 01' -- CommInterface");
                ACK();
                break;

            case "14 00":
                //DisplayData(MessageType.Incoming, " VMC: Disable Reader - 14 00\n");
                ui.GiveFeedback("'Incoming -- VMC: Disable Reader - 14 00' -- CommInterface");
                ACK();
                break;

            case "11 00":
                ui.GiveFeedback("'Incoming -- VMC: Setup Config - 11 00' -- CommInterface");
                ConfigurationDataLevel01();
                break;

            case "11 01":
                ui.GiveFeedback("'Incoming -- VMC: Setup Max Min Price - 00' -- CommInterface");
                SetupMaxMinPrices();
                break;

            case "13 00":
                //DisplayData(MessageType.Incoming, " VMC: Vend Request - 13 00\n");
                ui.GiveFeedback("'Incoming -- VMC: Vend Request - 13 00' -- CommInterface");
                if ( ui.Stage == Stages.SessionSelect )
                {
                    ui.NextStage();
                    ApproveVend();
                }
                else
                    DenyVend();
                break;

            case "13 02":
                //DisplayData(MessageType.Incoming, " VMC: Vend Success - 13 02\n");
                ui.GiveFeedback("'Incoming -- VMC: VendSuccess - 13 02' -- CommInterface");
                ui.NextStage();
                ACK();
                break;

            case "13 05":
                //DisplayData(MessageType.Incoming, " VMC: Cash Sale - 13 05\n");
                ui.GiveFeedback("'Incoming -- VMC: Cash Sale - 13 05' -- CommInterface");
                ACK();
                break;

            case "13 04":
                //DisplayData(MessageType.Incoming, " VMC: Session Complete - 13 04\n");
                ui.GiveFeedback("'Incoming -- VMC: Session Complete - 13 04' -- CommInterface");
                ACK();
                break;

            case "17 00":
                //DisplayData(MessageType.Incoming, " VMC: Expansion Command - 17 00\n");
                ui.GiveFeedback("'Incoming -- VMC: Expansion Command - 17 00' -- CommInterface");
                break;

            default:
                //DisplayData(MessageType.Incoming, "unknown\n");
                ui.GiveFeedback("'Incoming -- VMC: Unknown - ?? ??' -- CommInterface");
                ACK();
                break;
        }
        ui.GiveFeedback("DataReceived... End");
    }
    catch(Exception ex)
    {
        ui.GiveFeedback("Exception Thrown!");
        ui.GiveFeedback(ex.Message);
        ex = ex.InnerException;
        while (ex != null)
        {
            ui.GiveFeedback(ex.Message);
            ex = ex.InnerException;
        }
    }
}

我不知道发生了什么,也找不到任何可以帮助我的资源。我试过 运行 在没有任何 try/catches 的情况下使用它,看看它是否抛出了一些奇怪的东西,我已经尝试 运行 使用特定的异常捕获来使用它,我已经尝试了所有我想做的事情能想到,知道做。

为什么一直没有 运行ning,我该如何解决?即使你有一个有助于调试这个的想法,我也很乐意听到它!拜托,Whosebug,你是我唯一的希望!

这里有很多可能性...

首先,当数据被放入串行缓冲区时,SerialDataReceivedEvent 被触发。这并不意味着整个消息可用,只是串行端口对象已从底层流中缓冲字节。然后,您将使用 while 循环读取字节,直到获得 -1。

ReadByte 方法说它 returns -1 如果已读取流的结尾。这需要仔细解读,因为流的结尾实际上是 Eof 字符,不一定没有更多数据要接收。

除此之外,您正在捕获异常,我假设您可以判断读取何时超时。如果您设置了一个非常非常大的超时,或者将其保留为默认值 SerialPort.InfiniteTimeout,那么您将永远不会抛出此异常。

最后,当数据被读入缓冲区时会引发事件,这并不是说事件不能被引发多次。因此,例如,当您收到 10 个字节时,它可能会引发事件,而当您循环遍历数据时,它可能会再次引发它,创建您的处理程序的另一个实例,然后它们会相互争夺数据。

我只会使用事件来通知另一个线程读取数据。如果另一个线程已经在读取它,那么它不会做任何事情。当线程无法工作时,它应该挂起。您还应该检查 SerialPort.BytesToRead 属性 以确定是否有更多数据,请参阅 https://msdn.microsoft.com/en-us/library/system.io.ports.serialport.bytestoread(v=vs.110).aspx 我也不确定为什么您可以逐字节循环致电 SerialPort.ReadExisting 一次通话即可获得所有可用信息...?