WPFのProgressBarはBackgroundWorkerで更新せよ!


やあ子供たち。今年ももう終わりだな。今年もいろいろあったね。しかし青色LED白色LEDのまわりを青い塗料をまぶした透明プラスチックとかで覆ったんじゃだめだったのかな。ずっと昔からあった蛍光灯とかだって白しかなかったよ。青い蛍光灯を作ったらこれまたノーベル賞がもらえるのかな?なので青色LEDの偉大さは奥が深そうで素人には本当のところは理解できないんじゃないかなんて考えたりしてます。(なんて答えは波長だよね。光の波長。(上図))
さて、、
今日はC#WPFのお話だよ。WPFではProgressBarをUIエディタで設置して、コードビハインドからValueプロパティの値を更新するのだけどいっこうに表示が変化しないということがあっていろんな人が困っているようだった。おじさんもとあるアプリを作っていてどうしてもプログレスバーを更新したい!なんて思ったりしていただけに、いろいろ調べた結果、
今回BackgroundWorkerというものが比較的手っ取り早く実現できたので、その一部始終をメモしておくぞ。ちなみに今回おじさんが参考にしたページはずばりここだよ。
●なぜ、ProgressBarのValueプロパティ値を変えても表示が更新されないのか
どうやらUIスレッドからプログレスバーに更新をかけてもプログレスバー自体は更新されてるのだろうけど表示の更新がされないようです。問題の本質はプログレスバーにあるというよりは、WPFでUIスレッド上から描画更新を強制的にさせる手段がないというところにありそう。問題というよりかはそういう設計ポリシーなのかとも。WPF的に。
●どうすればよいのか
そこでどうやらワーカースレッド(メインUIスレッドとは別のスレッド)を自分で新規に作り、そこからUIスレッドに向けて、状況更新発生しました的な通知を送るやり方がいけてるっぽいということで、プログレスバー出してる間に本来進めたい「時間のかかる処理」を、まるごと別スレッドにて行うようにまずしなくてはならない。しかし、そうするにしてもいろいろとやり方があるようで、何よりもUIスレッドからワーカースレッドに必要な情報を引数として渡すにはどうしたらよいかみたいな話もある。
●では実際にお手軽にやるにはどうすればよいのか
いくつか方法があるようだが、
ここではBackgroundWorkerを使う。
●BackgroundWorkerの使い方

  1. まずVisualStudioのUIエディタ上に、BackgroundWorkerコンポーネントがあるからそれを使おうねという説明も見かけるがそれはWPF環境ではどうやら当てはまらないというオチがあるので気を付けたい。WPFでは、コードビハインドで明示的にBackgroundWorkerのインスタンス管理をしなくてはならない。(VS2013ExpressEd現在)
  2. インスタンスの作成するにあたりそれを保持するメンバ変数を定義します。
  3. 次に、newを使って、インスタンスを作成します。
  4. 次に、イベントハンドラというものを、上述インスタンスに対し、定義してやります。
  5. それぞれのイベントハンドラの中身をインプリメントします。とくにこの中の、DoWorkイベントハンドラというものに、ProgressBarを進めてるさ中に裏でやらせたい重い処理そのものを記述します。そのためには、UIスレッドから必要な情報をワーカースレッドに渡してあげる必要がありますが、それは、メインUIスレッド側で、スレッドを起動させるためのメソッド、RunWorkerAsync()の引数として与えた情報を、受け取り側のワーカースレッドでは、同イベントハンドラで受け取れるDoWorkEventArgs引数のArgument引数(object型)、これを適切な型(自分がRunWorkerAsyncの引数として渡した型)に復元キャストしてやることで、受け取ることができます。
  6. 上記DoWorkの中で、例えばループがあって、1ループ終わるあるいは始まるたびに、プログレスバーに更新をかけたい場合は、その箇所で、BackgroundWorkerのインスタンスのメソッドReportProgress()関数を呼んであげます。
  7. すると、上述イベントハンドラのこれまた一つである、ProgressChanged()というイベントハンドラに処理が飛んできます。このハンドラが実行されるスレッドはもとのメインUIスレッドなので、ここで、プログレスバーの更新をします。

●ワーカースレッドのデバッグについて
これも基本事項ぽいが、ワーカースレッドで動いてる処理はブレークポイントを仕掛けてもそこで止まってくれないのだが、VSでツール>オプション>デバッグで、「マイコードのみを有効にする」にチェックを入れると、ワーカースレッドでもブレークポイントで止まるようになるぞ。(※ただし、アンマネージドコードのデバッグに支障をきたす場合もあるとの情報ありなので設定しっぱなしに注意!)


以上がざっと簡単な流れになります。詳しくは上記リンクを見て見てください。
グッド・ラック!!