投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/2/15 01:01:46
> この場合DocumentCompletedの箇所にifなどを使用して
Yes です。実装手順は If でも Case でも AddHandler でも キューでも何でも良いですが。

> (3) と (5) の処理を 記述しないといけないのでしょうか?
もしも WebBrowser / HTMLDocument が、同期的に処理する仕様であったのならば
Click イベントに書いても良かったのですが、HTML 解析は非同期で行われるため、
別イベントで処理する必要があります。
イベントを処理できない言語ならば仕方ありませんが、VB はそうではありませんよね。


>>ループ待機は避けた方が良いと思いますよ。
>というのはなぜなのでしょうか?
たとえば「CheckBox がチェックされたら、ラベルの背景色を青にする」というアプリがあるとします。
さらに、「ボタンを押した後でのみ、この CheckBox 切り替えが行われる」という仕様だとしましょう。

この場合ループ待機を用いて
Private Sub Button1_Click(ByVal sender As ObjectByVal e As EventArgs) Handles Button1.Click
  Do Until CheckBox1.Checked
    Application.DoEvents()
  Loop
  Label1.BackColor = Color.Blue
End Sub
というコードを書くことはできますが……通常、こういう事はしませんよね? Checked の変化を監視するよりも
CheckBox1 の CheckedChanged イベントを利用する方が自然だと思いますが、それと同じことです。


しかし、ループ待機を行うことの問題点はもっと別の所にあります。
たとえば上記のテストコードを実行してみると分かりますが、CheckBox1.Checked が True に
ならないとループが終了しません。そのため、ボタンを押した後でチェックせずにいた場合、
フォームを閉じようとしてもアプリが終了しないという問題を引き起こします。

さとさんのコードも同様で、もし、ネットワーク障害によってページ遷移に長い時間がかかったり、
HTML解析がなかなか終わらない場合、ループ処理も長い時間がかかることになり、それと似たような
問題を引き起こします。また、処理すべきメッセージがないときに DoEvents を繰り返し呼ぶことは、
不用意に CPU 負荷を高める結果となります(シングルコア CPU の時には、特に顕著になります)。

間に Sleep をはさむ事で、CPU 負荷を軽減する事はできますが、十分な対策ではありませんし、
Sleep している間は、肝心の HTML 解析処理さえも停止することになってしまいます。
また、Sleep によってマウスやキーボード操作等のメッセージ処理も阻害されてしまうため、
アプリケーション処理にもたつきを生じさせる要因となりえます。

そして何よりも、本来処理すべきでは無い箇所で DoEvents を呼ぶ事は、イベントの再入が
発生するなどの再現性の低い不具合(後から原因を突き止めにくいバグ実装)を引き起こす
原因ともなりえます。不用意に DoEvents を繰り返し呼ぶことは、できる限り避けるべきかと。


> 読み込み完了するまで待機をさせるサンプルコード
イベント駆動型のコーディングを行いましょう。
待機中はイベントの発生を待つだけで、それ以外も「何もしない」ようにします。イベントを使えば
「現在の状況を繰り返し繰り返し問い合わせ続ける」ことをしなくても済むはずです。

もし、どうしてもループで処理する必要がある場合には、Sleep を呼ぶのではなく、
MsgWaitForMultipleObjects を使うようにします(今回は不要と思いますが)。