-3

メインのWindowsFormでこのコードを実行しようとすると、次の例外が発生します。

System.Windows.Forms.dllで、タイプ 'System.InvalidOperationException'の未処理の例外が発生しました 追加情報:スレッド間操作が無効です。コントロール 'richTextBox1'が、それが作成されたスレッド以外のスレッドからアクセスしました。

私はイベント、イベントハンドラ、そしてスレッドについて多くのことを見つけました。しかし、私は実際にイベントやそれらを手動で作成する方法やマルチスレッドについて深く取り組んではいません。 私はMSDNでこの記事を見つけました

- >リンク< - しかし、私は本当にそれを理解していませんでした。出力をrichtextbox1に書き込もうとすると、エラーが表示されます。

SerialPort Arduino = new SerialPort();
    public Form1()
    {
        InitializeComponent();
        this.Load += Form1_Load;

    }

    void Form1_Load(object sender, EventArgs e)
    {
      string[] k = SerialPort.GetPortNames();
      cBPortWaehlen.DataSource = k;

    } 
    private void btnOpenPort_Click(object sender, EventArgs e)

    {
        if (!Arduino.IsOpen)
        {
            Arduino.DataReceived += Arduino_DataReceived;
            Arduino.BaudRate = 115200;
            Arduino.PortName = cBPortWaehlen.SelectedItem.ToString();
            Arduino.Open();
        }
        else
        {
            MessageBox.Show("Port schon offen");
        }

    }

    private void Arduino_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
            this.richTextBox1.AppendText(Arduino.ReadExisting());

    }

    private void btnClosePort_Click(object sender, EventArgs e)
    {
        Arduino.Close();

    }

2 답변


3

でデータを受信したとき

private void Arduino_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
        this.richTextBox1.AppendText(Arduino.ReadExisting());

}

そのイベントはあなたのArduinoを監視している別のスレッドから発生します。

デフォルトでは、あなたのwinformsアプリケーションは少なくとも一つのスレッド(UIスレッド)を持っています。 そのスレッドでコードを実行すると、UIが停止して応答しなくなります。

そのため、UIが反応している間にバックグラウンドで問題が発生したい場合は、別のスレッドで実行する必要があります。

残念ながら(ただし、実際的ではない理由で)、スレッドは互いの参照を使用できません。

しかし彼らはお互いにメッセージを送ることができます。

その1つが、特定のアクションを呼び出す要求です。 これを利用するために、Windowsフォームには便利なメソッドがいくつか組み込まれています。

private void Arduino_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
        if(richTextBox1.InvokeRequired)
        {
            richTextBox1.Invoke(
               (Action)delegate 
               { 
                 richTextBox1.AppendText(Arduino.ReadExisting()); 
               }
            );
        }
}


  • あなたはなぜあなたが呼び出しが必要かどうかをチェックしています知っている呼び出しが必要ですか?書くようなものですif(true)あなたのコードで。 - Servy
  • @Servyコンパイラ/ジッタがそれを認識していてステートメントを削除したかどうかを知るのは面白いでしょう... - James Thorpe
  • もちろんできません。それあなたがしたとしても、そのイベントが常に別のスレッドから起動されることを知ることはできません。 - Servy
  • @Servyああ、もちろん。私はそれがそれを最適化するそれの考えだったと思いますif (true)それは私にそれを考えさせました:) - James Thorpe

1

UIスレッドのみでフォームを更新していることを確認してください。 UIコンポーネントのプロパティ(this.richTextBox1.AppendTextなど)にアクセスを設定するたびに、クロススレッド例外を回避するためにUIスレッドに委任していることに注意してください。

次のようにすることができます。

delegate void UpdateDelegate(string text);

private void UpdateInformation(string text)
{
   if(this.InvokeRequired)
   {
      UpdateDelegate ud = new UpdateDelegate(UpdateInformation);
      this.BeginInvoke(ud, new object[] { text } );
   }
   else 
   {
      this.myTextBox.Text = text;
   }
}

匿名デリゲートを使用することもできますが、上記のことは理解しやすいかもしれません。

リンクされた質問


関連する質問

最近の質問