2011-06-23 36 views
3

私はSerialPortからのデータを表示し、TextBoxに表示する非常に簡単なプログラム(VS2010のC#WPFアプリケーション)で作業しています。このプログラムは、通常の状況で正常に動作します。しかし、ユーザーが接続を開いていくつかのデータを集めてからもう一度開いて数サイクル繰り返すと、プログラムは最終的に例外をスローします:WPFのSerialPortがI/O例外を投げた

"I/O操作はスレッド出口かアプリケーション要求のどちらかです。 " [ReadLine()でI/O例外が発生しました]

いつかプログラムが例外をスローします。ときどきプログラムがハングすることがあります。以下 は私のコードです:

/* 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. 私はOpen()前後にThread.Sleep(3000)を追加しようとしていますおよびClose()。そして私はとても不満を持ち始め、私はThread.Sleepをすべての1行の間に入れます。私はそれがバックグラウンドで未完成の仕事のための十分な時間を許すでしょう。問題を解決しません。
  2. 私はZach Saw's Postを試しました。ブログ記事に残っているコメントは非常に肯定的です。私はこのアプローチを試し、正確なコードをコピーして貼り付けることさえできました。問題を解決しません。私の一日の半分を無駄にした非常に長い投稿。
  3. キム・ハミルトンが問題に対処するhereInvokeの代わりにBeginInvokeを使用することをお勧めします。試してみても、同じ問題が残っています。
  4. 非常にいい商用のSerialPortライブラリFranson SerialToolsがありました。これはかなり安価で、何回の時間とどのくらいの速さでSerialPortをOpen()またはClose()するかにかかわらず、素晴らしいバグで動作します。しかし、彼らは開発を中止しており、WPFではなくフォームアプリケーションでしか動作していないライブラリです。 APIの引数の中には、Forms.Controlだけを受け入れるものもあります。残念な。他にも、市販品はそこにあるが、どちらか彼らは過度に販売されていますか、私はそれが動作するかどうかを知っているかないように自由な証跡を提供していないではない購入前

い誰.NET SERIALPORTが仕事と実際に確認してもらいますバグ(Open()とClose()は何度も何度も入っていますが、データが入っていなくても)?

+1

MSDNのドキュメントは、あなたが、この文を使用してイベントハンドラにブロック読み込み置くべきではないことをほのめかす「一つだけのイベントハンドラを一度に実行することができます。」ハンドラでReadLineを使用しないことを強くお勧めします。 – dbasnett

+0

@dbasnett、良い点、私は仕事をしてスレッドを作成する必要があると思います。 – KMC

+1

利用可能なバイトを読み取って、それらのバイトを別のスレッドの処理のためにキューに入れないのはなぜですか?この方法では、改行を手動で検出する必要があります。 – dbasnett

答えて

1

イベントハンドラを追加するポートを開くと、閉じるときに削除する必要があります。

はこれを行うにしてください:

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

希望これで問題が解決します。

+0

あなたのソリューションと同じくらいシンプルで、私の問題を解決しました。あなたは、私の週末に頭を叩くのを救い、提供するupvoteがもっとあることを願っています。近くに電話をかけている間にReadLine()がまだ読書しているのが不思議です。そして、私はそれを避けるためにイベントを削除する必要があります.. – KMC

+0

これは問題を解決しない、例外がスローされたときにDataReceivedが既に実行されています。 –

+0

なぜ閉じるのか前にハンドラを削除する必要があります。 – Reniuz

0

ReadLineへのブロッキングコールが、UIスレッドからCloseへのコールによって中断されたとします。このエラーをキャッチすると何が問題になりますか?私はそれが起こると期待します。

+0

はい、ReadLine()がClose()を中断しています。では私は何をすべきですか? ReadLineの後でCloseの前にスレッドをスリープさせようとしました。まだ成功していない。 – KMC

+1

変数bool isClosingを追加し、 'if(serialPort1.IsOpen &&!isClosing)'でチェックし、ボタンをクリックしたときにisClosing = trueを設定しますか? – Reniuz

+0

@Reniuz、いいトリックのように聞こえました。私は同じ行にI/O例外を与えようとしましたが、違いは: "I/O操作はスレッド終了かアプリケーション要求のために中止されました。" – KMC

0

@Reniuzの解決策も私を助けませんでした。 実際に、ハンス・パサントのコメントとして明らかに役立つことが分かりませんでした。イベントの購読中にDataReceivedがすでに進行中である可能性があります。 私の解決策は、DataReceivedイベントの中で退会することでした。なぜなら、unsubscribeが必要なときにフラグを立てて、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 
    } 
} 
関連する問題