C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

■96002 / 親階層)  Task起動先が、Task起動元の終了を検知する方法について
□投稿者/ taro (11回)-(2020/10/15(Thu) 10:33:04)

分類:[C#] 

VisualStudio2019で、C#の学習をしております。
当方、C++やJAVA等の他言語は多少の経験がありますが、C#は未経験です。

以下のようなテストアプリを作って、Taskの学習をしています。

・アプリ起動すると、ボタンが1つだけのForm1が起動する。
・Form1のボタンを押すと、Form2が起動する(Form1はForm2を起動する為だけのもの)。
・Form2は
 ・終了ボタン(押すとForm2を終了し、処理をForm1に戻す)「button1」
 ・ログ出力テキストボックス「textBox1」
 だけがある。
・Form2起動時(Shownイベント)に、「処理タスク」を起動する。
・「処理タスク」は、ログ出力テキストボックスに対して、1秒間隔で"処理"という文字列を出力する。


■困っていること

Form2を起動し、1秒間隔で"処理"と出力されている途中に、終了ボタンを押すと
-----
System.InvalidOperationException: 'ウィンドウ ハンドルが作成される前、コントロールで Invoke または BeginInvoke を呼び出せません。'
-----
が発生する。
原因は、ログ出力テキストボックスがあるForm2が既に閉じられている為と思われる。


■Form2のコード(Form1は割愛)

public partial class Form2 : Form
{
  public Form2()
  {
    InitializeComponent();
  }

  /// <summary>
  /// 「終了」ボタン押下
  /// </summary>
  private void button1_Click(object sender, EventArgs e)
  {
    // フォームを閉じて上位に返す
    this.DialogResult = DialogResult.OK;
    this.Close();
  }
  

  /// <summary>
  /// フォーム表示直後に一度だけ実行されるShownイベントのコールバック
  /// </summary>
  private void Form2_Shown(object sender, EventArgs e)
  {
    // テキストボックスにログ出力
    // (このテキストボックスは、メインタスクからも処理タスクからも出力処理が行われる)
    textBox1.AppendText("UDP通信タスクを起動します" + "\r\n");

    // 「処理タスク」を起動
    Task task = Task.Run(() => {
      RunProcTask();
    });
  }

  /// <summary>
  /// 処理タスク
  /// </summary>
  private void RunProcTask()
  {
    // 1秒ごとにログを出力する
    while (true) {
      // 1秒待ってからログ出力
      Thread.Sleep(1000);
      //textBox1.AppendText("処理" + "\r\n");  //←このような出力はできない
      Invoke(new Action<string>(this._PutLog), "処理");  //←ここで例外が発生する
    }
  }

  /// <summary>
  /// 処理タスクからログ出力を行う
  /// </summary>
  private void _PutLog(string msg)
  {
    textBox1.AppendText(msg + "\r\n");
  }
}


■教えてほしいこと

・処理タスクからログを出力する方法として、色々調べた結果上記のようにInvokeを用いていますが、
 効率や可読性・処理速度等、総合的に見てベストな対応でしょうか?
・InvalidOperationExceptionを回避する方法として
 ・Form2に「static bool flg;」というメンバを用意し、Form2_Shownメソッド冒頭でtrueセット、button1_Clickメソッド冒頭でfalseセット。
 ・「Invoke(new Action<string>(this._PutLog), "処理");」は、flgがtrueの場合のみ実行
 という対応をしました。
 「Form1起動→ボタンを押下しForm2起動→"処理"出力中に終了ボタン押下→無事Form1に戻る」まではいいのですが、
 再度Form1のボタンを押下しForm2を起動したところ、
 System.InvalidOperationException: 'ウィンドウ ハンドルが作成される前、コントロールで Invoke または BeginInvoke を呼び出せません。'
 というエラーが発生しました。
 何か足らないことがあるのでしょうか?
・上記の「Form2が存在するかどうかをフラグで判定」という方法はベストではない気がしています。
 本当は、終了ボタン押下時に「処理タスクを止める」という事をしたかったのですが、やり方が分からず・・・。
 ベストな実装はどのようなものでしょうか?


長くなりましたが、よろしくお願い致します。


 



編集キー/

前の記事(元になった記事) 次の記事(この記事の返信)
親記事 →Re[1]: Task起動先が、Task起動元の終了を検知する方法について /WebSurfer
→Re[1]: Task起動先が、Task起動元の終了を検知する方法について /WebSurfer
→Re[1]: Task起動先が、Task起動元の終了を検知する方法について /kiku
→Re[1]: Task起動先が、Task起動元の終了を検知する方法について /WebSurfer
→Re[1]: Task起動先が、Task起動元の終了を検知する方法について /WebSurfer
 
上記関連ツリー

Task起動先が、Task起動元の終了を検知する方法について / taro (20/10/15(Thu) 10:33) #96002 ←Now
Re[1]: Task起動先が、Task起動元の終了を検知する方法について / WebSurfer (20/10/15(Thu) 10:51) #96003
Re[1]: Task起動先が、Task起動元の終了を検知する方法について / WebSurfer (20/10/15(Thu) 11:10) #96005
Re[1]: Task起動先が、Task起動元の終了を検知する方法について / kiku (20/10/15(Thu) 14:58) #96009
│└ Re[2]: Task起動先が、Task起動元の終了を検知する方法について / furu (20/10/15(Thu) 15:45) #96010
│  └ Re[3]: Task起動先が、Task起動元の終了を検知する方法について / kiku (20/10/15(Thu) 15:48) #96011
│    └ Re[4]: Task起動先が、Task起動元の終了を検知する方法について / furu (20/10/15(Thu) 16:03) #96012
Re[1]: Task起動先が、Task起動元の終了を検知する方法について / WebSurfer (20/10/16(Fri) 11:05) #96016
Re[1]: Task起動先が、Task起動元の終了を検知する方法について / WebSurfer (20/10/21(Wed) 11:50) #96093
  └ Re[2]: Task起動先が、Task起動元の終了を検知する方法について / taro (20/10/23(Fri) 14:40) #96149 解決済み

上記ツリーを一括表示 / 上記ツリーをトピック表示
 
上記の記事へ返信