読者です 読者をやめる 読者になる 読者になる

Windows 8 Developers

Windowsストアアプリ開発とかその他もろもろのブログ。

※参加自由なWindows8開発コミュニティをFacebookグループでやってます。
https://www.facebook.com/groups/win8.developers/

その他、技術情報リンク集を下記にまとめています。
http://windows8-developers.hatenablog.com/entry/2013/02/20/155410


【C#】タスクの実行とキャンセル、バックグラウンドからのUI更新

並列処理というか非同期処理って重要ですよね。

そこで今回はUI更新を伴うトグルボタン的なものを書いてみました。

 

■概要

①ボタンを押すと、ボタンテキストの更新を開始します

②ボタンテキストにはTask内のループカウンタを表示します

③テキスト更新中(Task実行中)にボタンを押すと、ボタンテキストの更新(Task)を停止します

 

■ポイント

①CancellationTokenSource (Taskのキャンセルに利用)

②SynchronizationContext (Task実行中にUIを更新するために利用)

 

        privateint counter_ =0;
       
privateTask task_ =null;
       
privateCancellationTokenSource tokenSource_ =null;

       
// タスク終了時に実行する処理
       
private async TaskEndTask(int n)
       
{
           
Debug.WriteLine("EndTask:    counter = {0}", n);
       
}

       
// タスクの実行・停止を行うボタンのハンドラ
       
private async void StartButton_Click_1(object sender,RoutedEventArgs e)
       
{
           
if(task_ !=null)
           
{
                tokenSource_
.Cancel();
                task_
=null;
                await
EndTask(counter_);
           
}
           
else
           
{
               
var context =SynchronizationContext.Current;// バックグラウンドからUIの更新要求を行うためのContext取得
                tokenSource_
=newCancellationTokenSource();// 外部からTaskへキャンセル要求を発行するために必要

               
// タスクの開始
                task_
=Task.Factory.StartNew(
                    async
(_)=>
                   
{
                        counter_
=0;

                       
while(true)
                       
{
                           
// キャンセル要求の確認
                           
if(tokenSource_.IsCancellationRequested)
                           
{
                                context
.Post(state =>
                                   
{
                                       
StartButton.Text="キャンセルされたよ!";
                                   
},
                                   
null);
                           
}
                           
// Taskのキャンセル要求を検出したとき、例外を生成してTaskを終了する
                            tokenSource_
.Token.ThrowIfCancellationRequested();

                           
// SynchronizationContextを利用したUI更新
                            context
.Post(state =>
                               
{
                                   
StartButton.Text= counter_.ToString();
                               
},
                               
null);

                            counter_
++;

                           
// 表示テキストの変更を目視できるようにループ間隔を制御
                            await
Task.Delay(TimeSpan.FromMilliseconds(30));
                       
}
                   
}
                   
, tokenSource_.Token// このタスクをキャンセルするCancellationToken
               
);
           
}
       
}