別スレッドでSystem.Windows.Forms.Controlを受け取り、Invokeを使ってイベントを通知する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | Form1.cs /// <summary> /// 別スレッドからメインスレッドのフォームを操作する /// </summary> public partial class Form1 : Form { private NLog.Logger logger = NLog.LogManager.GetLogger("fooLogger"); private bool isSubThreadAllFinished = false; private int runSubThreads; private int endSubThreads; public Form1() { InitializeComponent(); } /// <summary> /// 別スレッドからフォームのテキストボックスへ値を入れる /// </summary> /// <param name="sender">呼び元オブジェクト</param> /// <param name="e">イベントデータ</param> private async void button1_Click(object sender, EventArgs e) { WorkerClass wc = null; int minThreads = 10; try { isSubThreadAllFinished = false; runSubThreads = 0; wc = new WorkerClass(logger, this); wc.OnSubThreadRunning += Form1_SubThreadRunning; wc.OnSubThreadFinished += Form1_SubThreadFinished; // スレッドプールスレッドが実行するメソッドを設定 WaitCallback waitCallback = new WaitCallback(wc.Execute); // スレッドプールスレッドの最小数を変更 ThreadPool.SetMinThreads(minThreads, minThreads); // 別スレッドを作る for (int i = 0; i < minThreads; i++) { // メソッドをスレッドプールキューに登録 ThreadPool.QueueUserWorkItem(waitCallback, 1000 * i); runSubThreads++; } // 別メソッドの終了数が実行した別メソッドの総数になったらループを抜ける await Task.Run(() => { while (!isSubThreadAllFinished) { logger.Info("終了まで待機中..."); } }); } catch (Exception ex) { logger.Error(ex); } finally { this.textBox1.Text = "別スレッドは全て終了"; if (wc != null) { wc = null; } } } /// <summary> /// 別スレッドが実行された時に呼ばれるイベントメソッド /// </summary> /// <param name="sender">呼び元オブジェクト</param> /// <param name="e">ユーザ定義イベントデータ</param> void Form1_SubThreadRunning(object sender, FooEventArgs e) { this.textBox1.Text = e.Message; } /// <summary> /// 別スレッドが終了するたびに呼ばれるイベントメソッド /// </summary> /// <param name="sender">呼び元オブジェクト</param> /// <param name="e">ユーザ定義イベントデータ</param> private void Form1_SubThreadFinished(object sender, EventArgs e) { // 終了した別メソッドをカウント endSubThreads++; // 別メソッドの終了数が実行した別メソッドの総数になったか判定 isSubThreadAllFinished = (runSubThreads <= endSubThreads); } } WorkerClass.cs /// <summary> /// 別スレッドで実行するクラス /// </summary> class WorkerClass { private NLog.Logger logger; private Control mainThreadForm; /// <summary> /// 別スレッドの実行通知用デリゲート(イベントハンドラ) /// </summary> /// <param name="sender">呼び元オブジェクト</param> /// <param name="e">ユーザ定義イベントデータ</param> public delegate void SubThreadRunningEventHandler(object sender, FooEventArgs e); /// <summary> /// 別スレッドの実行通知用イベント /// </summary> public event SubThreadRunningEventHandler OnSubThreadRunning; /// <summary> /// 別スレッドの終了通知用イベント /// </summary> public event EventHandler OnSubThreadFinished; /// <summary> /// カスタムコンストラクタ /// </summary> /// <param name="aLogger">NLog</param> /// <param name="aMainThreadForm">メインスレッドのフォーム</param> public WorkerClass(NLog.Logger aLogger, Control aMainThreadForm) { logger = aLogger; mainThreadForm = aMainThreadForm; } /// <summary> /// 別スレッドの実行メソッド /// </summary> /// <param name="state">パラメータ</param> public void Execute(object state) { try { // 渡されたパラメータの値だけ待機する Thread.Sleep((int)state); // Invoke()を使って実行を通知する FooEventArgs e = new FooEventArgs(); e.Message = state.ToString(); mainThreadForm.Invoke(OnSubThreadRunning, new object[] { this, e }); } finally { // Invoke()を使って終了を通知する mainThreadForm.Invoke(OnSubThreadFinished, new object[] { this, EventArgs.Empty }); } } } FooEventArgs.cs /// <summary> /// ユーザ定義イベントデータクラス /// </summary> class FooEventArgs : EventArgs { /// <summary>文字列をもたせる</summary> public string Message; } |
引用元: https://qiita.com/shusakuorz/items/86fe767ee0e46fb84831