(長い処理を行いたい場合など)Worker threadとUI threadの関係はやや面倒で、
- 描画はUI threadで行う
- UI threadで長い処理を行うと描画が固まる
- 長時間処理はworker threadで行えば画面固まらない
- でも描画はUI threadで行わないといけない
ということで、background workerだったり、invokeで描画させたりなど、昔から面倒だった訳ですが、最近?はasync/awaitが非同期処理の流行りのようです。
実験的に作ったアプリは
- 長時間処理用と仮定したtaskを生成する
- 上記taskから描画表示を行う
という処理を、async/awaitとinvokeを使って書いてみます。
formのデザイン画面には
- taskを開始するボタン
- 状態を表示するUIとしてtextbox
を配置します。
textboxでは、taskから1秒ごとに時間を表示させます。
taskが終了したらUI threadで"終了した"表示を行います。
表示部分のポイントは
textBox_dispTime.Invoke(new Action(() => { textBox_dispTime.Text = DateTime.Now.ToString(); }));
の部分で、
UI部品.Invoke(デリゲート);
という感じの模様。
これでtask側からtextBox_dispを操作する事ができました。
taskについてのポイントは
- await Task.Run(() => workThread()); として、awaitキーワードをつけたTask.Run()する
- awaitキーワードを使うメソッドには"async"キーワードを付ける
となり、動作としては、
- UIスレッドはawaitで待ち
- task側からUI(textBox)を操作
- workThread()が終了すると、その次のメソッド(UIスレッドからtextboxに"終了"を書く)実行
という感じでした。
ソースコード
using System.Threading;
namespace TestAwait01
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// awaitキーワードを使うメソッドはasyncキーワードをつけておく
private async void button_TaskStart_Click(object sender, EventArgs e)
{
await Task.Run(() => workThread()); // workThreadの処理をtaskで実行
textBox_dispTime.Text = "終了";
}
// threadとして実行するメソッド
private void workThread()
{
for(int i = 0; i < 10; i++) {
// textBox_dispTime.Text = DateTime.Now.ToString(); // コレは表示されない
textBox_dispTime.Invoke(new Action(() => { textBox_dispTime.Text = DateTime.Now.ToString(); }));
Thread.Sleep(1000);
}
}
}
0 件のコメント:
コメントを投稿