2017-09-12 6 views
2

Windowsフォームプロジェクトでは、編集用にメモ帳にファイルを開くボタン用のハンドラがあります。メモ帳が閉じられると、私は関数RefreshTextBox()を呼び出してテキストファイルを解析し、値に基づいてTextBoxを更新します。ここではメモ帳を開き、その閉じた後にリフレッシュメソッドを呼び出す方法は次のとおりです。このコードはどのように別のスレッドで実行されていますか?

private void button_Click(object sender, EventArgs e) 
    { 
      Process p = new Process 
      { 
       EnableRaisingEvents = true, 
       StartInfo = 
       { 
        FileName = "NOTEPAD.EXE", 
        Arguments = _path, 
        WindowStyle = ProcessWindowStyle.Maximized, 
        CreateNoWindow = false 
       } 
      }; 

      p.Exited += (a, b) => 
      { 
       RefreshTextBox(); 
       p.Dispose(); 
      }; 

      p.Start(); 
    } 

とテキストボックスを更新するためのコード:

private void RefreshTextBox() 
    { 
     using (StreamReader reader = File.OpenText(_appSettingsPath)) 
     { 
      string text = reader.ReadToEnd(); 

      // Code to parse text looking for value... 

      // InvalidOperationException thrown here: 
      textBox.Text = reader.Value.ToString(); 
     } 
    } 

これは、スレッドからコントロールを更新しようとしているため、例外がスローされますそれが作成されたものを除いて。私はなぜ理解しているのか分かりません。私はこれを新しい仕事や背景職人などでやっていません。明らかにメモ帳は別のスレッドで実行されていますが、リフレッシュメソッドはプロセスが終了するまで呼び出されません。

編集:Visual Studio(管理者用)でデバッグするときに、このエラーが致命的な例外ポップアップをスローすることを追加する必要があります。アプリケーションが単独で実行されているときにポップアップが表示されない場合は、例外が黙って飲み込まれたり、それが発生したりしません。ドキュメントを1として

+2

'Exited'イベントは別のスレッドで発生している可能性があります。これはおそらく多くの場合、決して見られません。 (Windows Formsスレッドのような「アイドリング」がないコンソールアプリケーションを想像してみてください) –

+0

問題を解決するのに役立つ別のスレッドからUIを更新する方法についての記事です。 https://stackoverflow.com/questions/661561/how-to-update-the-gui-from-another-thread-in-c –

答えて

6

プロセスSynchronizingObjectは、それがするSynchronizingObjectがnullの場合は、あなたがSynchronizingObject

フォームのインスタンスに設定する必要があり、これを回避して、UIスレッドでそのイベントハンドラを実行するために、システムのスレッドプールで終了イベントを実行します設定されていない場合Exitedイベントを処理するメソッドは、システムスレッドプールからのスレッドで呼び出されます。システムスレッドプールの詳細については、 ThreadPoolを参照してください。

あなたは

p.SynchronizingObject = WindowsFormName; 

を設定する場合、それは同じスレッドで実行するか、それがcrossthread例外が発生しますスレッドスレッドプールシステムで実行されます。

MSDN Reference

0
private void button_Click(object sender, EventArgs e) 
    { 
     Process p = new Process 
     { 

      EnableRaisingEvents = true, 
      StartInfo = 
      { 
       FileName = "NOTEPAD.EXE", 
       Arguments = _path, 
       WindowStyle = ProcessWindowStyle.Maximized, 
       CreateNoWindow = false 
      } 
     }; 
     //p.SynchronizingObject = this; 
     p.Exited += (a, b) => 
     { 
      RefreshTextBox(); 
      p.Dispose(); 
     }; 

     p.Start(); 
    } 
    private void RefreshTextBox() 
    { 
     using (StreamReader reader = File.OpenText(_appSettingsPath)) 
     { 
      string text = reader.ReadToEnd(); 

      // Code to parse text looking for value... 

      //textBox.Text = text; // reader.Value.ToString(); 
      threadSafeControlUpdate(textBox, text); 
     } 
    } 
    public delegate void updateUIfunc(Control c, object v); 
    public void threadSafeControlUpdate(Control c, object v) 
    { 
     if (this.InvokeRequired) 
     { 
      this.BeginInvoke(new updateUIfunc(threadSafeControlUpdate), c, v); 
      return; 
     } 
     if (c is TextBox && v is string) 
     { 
      c.Text = (string)v; 
     } 
    } 
+0

p.SynchronizingObjectを使用して、通常のUI更新と互換性のあるスレッドで強制的に実行できますsumeet kumarで示されていますが、別のスレッドで実行したい場合は、デリゲートを使用して別のスレッドからコントロールを更新できます。私はコントロールの型と更新に渡されるデータの型を決定する一般的なthreadSafeControlUpdateを使用します。私はテキストボックスのコードをコピーしただけですが、私の通常のthreadSafeControlUpdate()はpictureBox、DataGridViewなどを扱います... – wdomains

0

私は、同期コンテキストをキャプチャし、その上にRefreshTextBoxコールを投稿推薦します。次のようなものがあります。

関連する問題