TIPSWindowsフォームとWPFアプリではタスクバーのアイコンに処理の進捗状況を表示することがよくある。本稿ではこの機能を実装する方法を解説する。7以降ではタスクバーのアイコンに進捗(しんちょく)状態を表示できる。長い処理の途中で画面上に進捗を表示できているのなら、タスクバーのアイコンに表示するのは意外と簡単なのである。4.0以降のWindowsフォームとWPFでタスクバーのアイコンに進捗表示を出す方法を解説する。進捗表示の種類タスクバーのアイコンに表示される進捗表示は、正式には「プログレスインジケーター」と呼ばれる。「進行状況バー」と呼ぶこともあるようだ。プログレスインジケーターには5種類の状態がある(次の画像)。その種類を表す列挙体のメンバー名と意味は、次のようになっている。10)左から順に、None/Normal/Paused/Error/Indeterminate(意味は上記参照)。利用するAPIWindowsフォームには標準の機能としては備わっていない。Pack」を利用する*1。4.0で追加されたTaskbarItemInfoクラス(System.Windows.Shell名前空間)を利用する。Packは、以前はcode.msdn.microsoft.comやarchive.msdn.microsoft.comでソースコードと共に公開されていた。現在は、マイクロソフトからの公開は終了している。有志の手によってソースコードは引き続きメンテされており、そのバイナリはNuGetから入手できる。4.0以上が必要なようである。PackをNuGetから導入しておく(次の画像)。パッケージの管理]ダイアログが出てくる。documentation」と入力して検索する((2))。見つかったパッケージを選ぶと[インストール]ボタンが表示されるので((3))、それをクリックしてインストールする。Shell」の二つのパッケージを順に入れる必要がある。右側の[ライセンス条項の表示]リンク((4))でライセンス条件を確認できるので、利用に先立って確認しておいてほしい。Packをインストールすると、プロジェクトの参照設定に次の三つが追加されているはずだ。確認しておいてほしい(C#のプロジェクトではソリューションエクスプローラーの[参照設定]フォルダー、VBのプロジェクトではプロジェクトのプロパティの[参照]タブ)。Microsoft.WindowsAPICodePackMicrosoft.WindowsAPICodePack.ShellMicrosoft.WindowsAPICodePack.ShellExtensions準備が整ったら、メインのフォーム(=プログラムの起動時に表示されるフォーム)のコードビハインドの冒頭部分に名前空間の指定を追加する(次のコード)。Packを利用するための名前空間を追加する(上:C#、下:VB)そうしたら、メインのフォームが完全に表示された後の好きなタイミングで*2、次に示すようなコードを記述するだけである。Packを使ってプログレスインジケーターを表示する例(上:C#、下:VB)SetProgressStateメソッドとSetProgressValueメソッドを呼び出すだけである。SetProgressStateメソッドには、前述したプログレスインジケーターの5種類の状態のいずれかを指定する。SetProgressValueメソッドは、進捗率の更新があるときだけ呼び出せばよい。この例の引数は、100分の30(=30%)を表している。Packを使ってプログレスインジケーターを元に戻す例(上:C#、下:VB)プログレスインジケーターを元に戻すには、SetProgressStateメソッドを呼び出すだけである。それ以外のフォーム(=メインのフォームから表示した別のフォーム)からプログレスインジケーターを表示することも可能だが、そのときはウィンドウハンドルを引数として渡す必要がある。(どのフォームにおいても)フォームが完全に表示される前に呼び出すと、例外が発生する。フォームのLoadイベントでは例外となり、Shownイベントならば正しく表示される。上のコードは、UIスレッドで呼び出さねばならない(そうしないと例外が発生する)。時間のかかる処理は別スレッドで非同期に動作させるのが普通であるから、UIの表示を更新する部分をUIスレッドに戻して実行するようなコーディングが必要だ。簡単な例を紹介しておこう。次の画像のようなUIを作る。カウントを表示しているラベルの名前は「label1」、[START]ボタンの名前は「button1」とする。7で実行しているところである。非同期処理で10から0までカウントダウンしていく。カウントダウンに合わせて、フォーム上のラベルとプログレスインジケーターの表示を更新する。「button1」ボタンのクリックイベントで、10から0までカウントダウンする処理を非同期に実行させよう。カウントが進むたびに、「label1」ラベルの表示とプログレスインジケーターを更新しよう。4.0のTaskクラス(System.Threading.Tasks名前空間)を使って書くと、次のコードのようになる。Subカウントダウンする非同期処理の例(上:C#、下:VB)これはフォームのコードビハインドに記述している。そのため、UIスレッドで処理を呼び出すには「this.BeginInvoke」メソッドが使える。4.5で導入されたIProgressインターフェース(System名前空間)を利用したりなどと、さまざまな工夫をすることになる。4.0のWPFからは標準でサポートされている。本稿では、WPFの機能を使う。4.0以降)のWindowオブジェクト(System.Windows名前空間)にはTaskbarItemInfoプロパティがあって、これを通じてプログレスインジケーターを操作できる。このプロパティはデフォルトではnullになっている(利用しないときに無用な負荷を与えないためであろう)。そこで、プログレスインジケーターを利用するには、メインのウィンドウが作られたときに、TaskbarItemInfoオブジェクト(System.Windows.Shell名前空間)を生成してウィンドウに設定してやる(次のコード)。この呼び出しはデザイナーで必要です。呼び出しの後で初期化を追加します。Subプログレスインジケーターを利用できるようにする(上:C#、下:VB)太字の部分を追加する。コメントに書いたように、XAMLコードで記述することもできる。したら、TaskbarItemInfoプロパティにオブジェクトをセットした後の好きなタイミングで、次に示すようなコードを記述するだけである。0.3WPFの機能を使ってプログレスインジケーターを表示する例(上:C#、下:VB)ProgressStateプロパティとProgressValueプロパティをセットするだけである。ProgressStateプロパティには、前述したプログレスインジケーターの5種類の状態のいずれかを指定する。ProgressValueプロパティは、進捗率の更新があるときだけセットすればよい。System.Windows.Shell.TaskbarItemProgressState.NoneWPFの機能を使ってプログレスインジケーターを元に戻す例(上:C#、下:VB)ProgressStateプロパティにセットするだけである。上のコードは、UIスレッドで呼び出さねばならない(そうしないと例外が発生する)。時間のかかる処理は別スレッドで非同期に動作させるのが普通であるから、UIの表示を更新する部分をUIスレッドに戻して実行するようなコーディングが必要だ。簡単な例を紹介しておこう。次の画像のようなUIを作る。カウントを表示しているテキストブロックの名前は「textBlock1」、[START]ボタンの名前は「button1」とする。10で実行しているところである。非同期処理で10から0までカウントダウンしていく。カウントダウンに合わせて、ウィンドウ上のテキストブロックとプログレスインジケーターの表示を更新する。「button1」ボタンのクリックイベントで、10から0までカウントダウンする処理を非同期に実行させよう。カウントが進むたびに、「textBlock1」テキストブロックの表示とプログレスインジケーターを更新しよう。2012で導入されたasync/awaitキーワードを使って書くと、次のコードのようになる。Subカウントダウンする非同期処理の例(上:C#、下:VB)これはウィンドウのコードビハインドに記述している。そのため、UIスレッドで処理を呼び出すには「this.Dispatcher.BeginInvoke」メソッドが使える。4.5で導入されたIProgressインターフェース(System名前空間)を利用したりなどと、さまざまな工夫をすることになる。まとめプログレスインジケーターを表示すること自体は簡単である。実際には、非同期処理の途中で行うことになるので、そこがちょっと難しい*3。いえ、非同期処理の途中で画面を更新するコードが書けるならば、プログレスインジケーターの表示を更新するコードも同様である。非同期処理、特にTaskクラスを使う方法については、次の記事などで学んでいただきたい。筆者も「C#によるマルチコアのための非同期/並列処理プログラミング」という書籍を出しているので、参考にしていただければ幸いである。メールマガジンをご購読ください。申し込みページへITmediaはアイティメディア株式会社の登録商標です。