0

私はシリアルポート関連のアプリケーションに取り組んでいます。DataReceivedのイベントを使用している間SerialPort、受信したバイトでテキストボックスを更新する必要があります。

private void Connection_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    ledReceive.On = true;

    var data = Connection.ReadExisting();

    _readBuffer.Add(data);
    Invoke(new EventHandler(AddReceivedPacketToTextBox));       
}

だから私Invokeはテキストボックスを更新するために使用します。しかし、大きな問題があります。接続を閉じようとすると、UIがフリーズします。これは、Invokeおそらく何かをしているためだと思います。

友人RequiredInvokeが私が使うべきだと言ったが、彼が本当に何を言っているのか私にはわからない。呼び出しスレッドとUIスレッドを台無しにせずに接続を閉じるにはどうすればよいですか?

これが私の閉じる方法です:

private void DisconnectFromSerialPort()
{
    if (Connection != null && Connection.IsOpen)
    {
        Connection.Close();
        _receivedPackets = 0; //reset received packet count
    }
}
4

1 に答える 1

1

完全にはわかりませんが、接続を閉じるとUIを更新しているスレッドが削除されると思います。これは、UIがフリーズする理由を説明している可能性があります。しかし、私はあなたのすべてのコードを掘り下げずに確信することはできません。

InvokeRequiredは、要素にアクセスしようとしているスレッドがUIにネイティブでない場合にtrueを返します。または、MSの説明を好む場合:

    // Summary:
    //     Gets a value indicating whether the caller must call an invoke method when
    //     making method calls to the control because the caller is on a different thread
    //     than the one the control was created on.
    //
    // Returns:
    //     true if the control's System.Windows.Forms.Control.Handle was created on
    //     a different thread than the calling thread (indicating that you must make
    //     calls to the control through an invoke method); otherwise, false.

そして基本的な実装:

    public void ReceiveCall()
    {
        if (this.InvokeRequired)
        {
            this.Invoke(new CallDelegate(ReceiveCall), new object[] { });
            return; // Important to not continue on this method.
        }

        // Whatever else this function is suppose to do when on the correct thread.
    }

Invokeは、そのスレッドがUIの奥深くに入るのを防ぐために、関数が最初に行うことです。これで、接続自体がUIのスレッドの境界内にあると判断された場合、「InvokeRequired」はトリガーされない可能性があります。これを防ぐ1つの方法は、接続にバインドされていないUIを更新するスレッドを手動で作成することです。

複数のUI要素のレンダリングを更新する時計でも同様の問題が発生しました。時計は正常に機能しますが、すべてのUIのレンダリングが完了するまで「ハング」します。これは、UIが多い場合、次のティックをスキップすることを意味します。

     Thread updateUI = new Thread(updateUIDelegate);
     updateUI.Start();

このようにして、私の時計(またはあなたの接続)は、それ自体でその処理を行う独立したスレッドを開始します。また、Monitorクラスまたはlockキーワードをチェックして、同じ変数を使用するスレッドまたは複数のスレッドの衝突を防ぐこともできます。

編集:または、で素晴らしい答えを読むことができます。これはおそらく私のものよりも理にかなっています:シリアルポートを閉じるときにUIがフリーズする原因は何ですか?

于 2012-10-16T12:02:26.467 に答える