【问题标题】:What is preventing my event handler method from completing?是什么阻止我的事件处理程序方法完成?
【发布时间】:2015-06-12 20:19:12
【问题描述】:

我正在使用 SerialPort、WPF 作为用户界面、一个“ui”对象来处理应用程序逻辑,以及一个围绕 SerialPort 的包装器。

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

它似乎没有抛出任何异常,它并没有像卡在循环中一样(同步读取应该超时+我会得到大量的“我读过一个东西”),而且我'米难住了。几乎所有的 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;
        }
    }
}

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

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

【问题讨论】:

    标签: c# wpf concurrency exception-handling event-handling


    【解决方案1】:

    这里有很多可能性...

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

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

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

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

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

    【讨论】:

    • 我没有触及超时,显然它默认为无限。谢谢!另外,感谢您关于将线程专用于阅读的建议。我会这样做的。
    猜你喜欢
    • 2020-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多