WPF中的SerialPort引发了I / O异常

时间:2011-06-23 10:05:30

标签: c# wpf serial-port

我正在开发一个非常简单的程序(VS2010中的C#WPF应用程序),它显示来自SerialPort的数据并显示在TextBox上。该程序在正常情况下工作正常。但是当用户打开一个连接,收集一些数据,关闭它并再次打开它,并执行几个循环时,程序最终会抛出异常:

“由于线程退出或应用程序请求,I / O操作已中止。” [I / O异常发生在ReadLine()]

有时程序会给我一个例外;有时程序只是挂起。 以下是我的代码:

/* Click to Open ComPort */
private void PortOpen_Click(object sender, RoutedEventArgs e)
{
    if (!serialPort1.IsOpen)
    {
        serialPort1.PortName = "COM1";
        serialPort1.BaudRate = 9600;
        serialPort1.ReceivedBytesThreshold = 1;
        serialPort1.NewLine = "\r\n";
        serialPort1.Parity = Parity.None;
        serialPort1.StopBits = StopBits.One;
        serialPort1.DataBits = 8;
        serialPort1.Handshake = Handshake.None;

        serialPort1.Open();

        serialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(Receive);
    }
}

/* Receive data from ComPort */
private void Receive(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    if (serialPort1.IsOpen)
    {
        try
        {
            string1 = serialPort1.ReadLine(); /* This is where I/O Exception occurred */
            Dispatcher.Invoke(DispatcherPriority.Send, new UpdateUiTextDelegate(DisplayText), string1);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }
}

private void DisplayText(string string1)
{
    textBox1.Text = string1;
}
/* Close ComPort */
private void PortClose_Click(object sender, RoutedEventArgs e)
{
    if (serialPort1.IsOpen)
    {
        serialPort1.Close();
    }            
}

总结过去40小时内我的头撞击桌面尝试导致没有进展:

  1. 我尝试在Thread.Sleep(3000)Open()之前和之后添加Close()。我开始变得非常沮丧,我把Thread.Sleep放在每一行之间。我虽然这样可以留出足够的时间来完成一些未完成的工作。没有解决问题。
  2. 我试过Zach Saw's Post。博客文章中留下的很多评论非常积极。我尝试了这种方法,甚至将确切的代码复制并粘贴到我的。不解决问题。一个很长的帖子,浪费了我一半的时间。
  3. Kim Hamilton解决问题here。建议使用BeginInvoke代替Invoke。试过并仍然坚持同样的问题。
  4. 有一个非常好的商业SerialPort库Franson SerialTools,它相当便宜,无论有多少时间和多快我打开()或关闭()serialPort都没有错误。但是,他们已经停止了他们的开发和他们只在Form应用程序上工作的库,而不是WPF。他们的API中的一些参数只接受Forms.Control。太糟糕了。还有其他商业产品,但要么价格过高,要么不提供免费试用,所以在购买之前我不知道它是否有效
  5. 有没有人让.NET SerialPort工作并实际检查错误(Open()和Close()多次 - 即使没有传入数据)?

3 个答案:

答案 0 :(得分:2)

当您打开端口时添加事件处理程序,关闭时我认为您应该删除它。

尝试这样做:

private void PortClose_Click(object sender, RoutedEventArgs e)
{
    if (serialPort1.IsOpen)
    {
        serialPort1.DataReceived -= Receive;
        serialPort1.Close();
    }            
}

希望这能解决问题。

答案 1 :(得分:0)

我想通过从UI线程调用ReadLine来中断对Close的阻止调用。捕获此错误有什么问题?我希望它会发生。

答案 2 :(得分:0)

@Reniuz解决方案对我也没有帮助。 实际上我根本无法理解它是如何起作用的,显然正如@Hans Passant评论一样,DataReceived可能在取消订阅事件时已经在进行中。 我的解决方案是在DataReceived事件中取消订阅,只需在需要取消订阅时引发一个标志,并在DataReceived事件中检查它。

if @profile.update_attributes(profile_params)
  params[:profile][:schedule_display] == '1' ? 
    profile.turn_schedule_on : profile.turn_schedule_off