SerialPort в WPF бросил I / O Exception - PullRequest
3 голосов
/ 23 июня 2011

Я работаю над очень простой программой (приложение C # WPF в VS2010), которая отображает данные из SerialPort и отображает их в TextBox. Программа отлично работает в нормальных условиях. Но когда пользователь откроет соединение, соберет некоторые данные, закроет его и снова откроет, и сделает это в течение нескольких циклов, программа в конечном итоге выдаст исключение:

"Операция ввода-вывода была прервана из-за выхода из потока или запроса приложения." [Исключение ввода / вывода произошло в 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. Я попробовал Пост Зака ​​Со . Множество комментариев, оставленных в блоге, очень положительные. Я попробовал подход и даже скопировал и вставил точный код в мой. Не решает проблему. Очень длинный пост, потраченный впустую половину моего дня.
  3. Ким Гамильтон решает вопросы здесь . которые предлагают использовать BeginInvoke вместо Invoke. Пробовал и до сих пор сохраняется та же проблема.
  4. Была очень хорошая коммерческая библиотека SerialPort Franson SerialTools , которая довольно дешева и работает фантастически без ошибок независимо от того, сколько времени и как быстро я открываю () или закрываю () последовательный порт. Однако они прекратили свою разработку, и библиотека, которая у них есть, работает только с приложением Form, а не с WPF. Некоторые из их аргументов в их API принимают только Forms.Control. очень плохо. Существуют и другие коммерческие продукты, но они либо слишком дорогие, либо не предлагают бесплатный след, поэтому я не знаю, работает ли он или нет, перед покупкой

Кто-нибудь заставляет .NET SerialPort работать и на самом деле проверять наличие ошибок (Open () и Close () много раз - даже когда нет входящих данных)?

Ответы [ 3 ]

2 голосов
/ 23 июня 2011

Когда вы открываете порт, вы добавляете обработчик событий, при закрытии я думаю, что вы должны удалить его.

Попробуйте сделать это:

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

Надеюсь, что это решит проблему.

0 голосов
/ 10 мая 2016

@ Решение Reniuz мне тоже не помогло.На самом деле я не мог понять, как это вообще могло помочь, очевидно, как в комментарии @Hans Passant, DataReceived может быть уже запущен во время отписки о событии.Мое решение для этого состояло в том, чтобы отписаться в событии DataReceived, просто поднять флаг всякий раз, когда требуется отписаться, и проверить его в событии DataReceived.

public void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
// Brief:   Handle data received event
{
  // Read the data
  // ~~~~~~~~~~~~~

  // Check for unsubscribe
  // ~~~~~~~~~~~~~~~~~~~~~
  if (bStopDataRequested)
  {
    serialPort1.DataReceived -= DataReceivedHandler;  // Unsubscribe to DataReceived event

    // Only then close the port
  }
}
0 голосов
/ 23 июня 2011

Я предполагаю, что блокирующий вызов ReadLine прерывается вызовом Close из потока пользовательского интерфейса.Что не так с ловлей этой ошибки?Я ожидаю, что это произойдет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...