c# - SerialPort en WPF lanzó excepción de E/S
serial-port (3)
Cuando abres el puerto, agregas el controlador de eventos, al cerrar creo que deberías eliminarlo.
Intenta hacer esto:
private void PortClose_Click(object sender, RoutedEventArgs e)
{
if (serialPort1.IsOpen)
{
serialPort1.DataReceived -= Receive;
serialPort1.Close();
}
}
Espero que esto solucione el problema.
Estoy trabajando en un programa muy simple (aplicación C # WPF en VS2010) que muestra datos de SerialPort y se muestran en un TextBox. El programa funciona bien en circunstancias normales. Pero cuando el usuario abre una conexión, recopila algunos datos, lo cierra y lo vuelve a abrir, y lo hace durante varios ciclos, el programa lanzará una excepción:
"La operación de E / S se ha cancelado debido a una salida de subproceso o una solicitud de aplicación". [La excepción de E / S se produjo en la ReadLine ()]
Algún día el programa me arrojaría una excepción; a veces el programa simplemente se cuelga. A continuación está mi código:
/* 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();
}
}
A continuación, resumo mis intentos de golpear la cabeza contra la mesa en las últimas 40 horas, que no dieron lugar a ningún progreso:
- He intentado agregar
Thread.Sleep(3000)
antes y después deOpen()
yClose()
. Y empiezo a sentirme tan frustrado que pongoThread.Sleep
entre cada línea. Pensé que eso me daría tiempo suficiente para trabajar inacabadamente en segundo plano. No resuelve el problema - Intenté el mensaje de Zach Saw . Una gran cantidad de comentarios que quedan en la publicación del blog son muy positivos. Probé el enfoque e incluso copié y pegué el código exacto al mío. No resuelve el problema Una publicación muy larga que desperdició la mitad de mi día.
- Kim Hamilton aborda los problemas aquí . que sugieren usar
BeginInvoke
lugar deInvoke
. Intentó y aún persiste el mismo problema. - Había una muy buena librería comercial de SerialPort, Franson SerialTools, que es bastante barata y funciona de maravilla sin errores, independientemente de la cantidad de tiempo y la rapidez con la que abro () o cierro () el puerto serial. Sin embargo, han interrumpido su desarrollo y la biblioteca solo funciona en la aplicación de formulario, no en WPF. Algunos de sus argumentos en su API solo aceptan Forms.Control. demasiado. Hay otros productos comerciales por ahí, pero o son demasiado caros o no ofrecen un camino gratis, así que no sabría si funciona o no antes de la compra.
¿Alguien consigue el .NET SerialPort para trabajar y realmente busca errores (Abrir () y Cerrar () muchas veces, incluso cuando no hay datos entrantes)?
Imagino que la llamada de bloqueo a ReadLine
ve interrumpida por una llamada a Close
from the UI thread. ¿Qué hay de malo en detectar este error? Yo esperaría que sucediera.
La solución de @Reniuz tampoco me ayudó. En realidad, no podía entender cómo podría ayudar, obviamente, como comenta @ans Passant, el DataReceived podría estar en progreso al anular la suscripción al evento. Mi solución para esto fue anular la suscripción dentro del evento DataReceived, solo levantar una bandera cuando sea necesario cancelar la suscripción y verificarla en el evento 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
}
}