2016年12月15日木曜日

タスクとUI表示 その1

(長い処理を行いたい場合など)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 件のコメント:

コメントを投稿