はい、 Application.DoEvents() はこの問題を解決します。核となる問題は、WebBrowser がその中核部分で高度にスレッド化されたコンポーネントであることです。その Navigate() メソッドを呼び出すことができ、コードをブロックすることなく処理を開始します。メソッドはすぐに戻ります。
ただし、問題は、ある時点で DocumentCompleted イベントを実行する必要があることです。これは、ブラウザ オブジェクトを作成したスレッドで実行されることが保証されています。それを行うのは難しいです。あなたのスレッドは何か他のことをしているかもしれません。ループに座って、ReadyState プロパティをテストするように。このループを中断してイベント ハンドラを実行するメカニズムはありません。
したがって、ReadyState プロパティが変更されず、DocumentCompleted イベントが発生しないことがわかります。これはデッドロックと呼ばれ、スレッド化されたコードの非常に一般的な呪いです。DoEvents の使用はバックドアであり、「メッセージ ループをポンピング」します。これにより、ブラウザがスレッドに割り込んでイベントを発生させることができます。これにより、ReadyState プロパティが更新され、ループから抜け出すことができます。
ただし、DoEvents には大きな問題があります。選択的ではなく、イベントの発生を許可するメッセージの処理に限定されません。また、プログラムをクラッシュさせる種類の他の通知もディスパッチします。ユーザーが遅い Web サイトにいらいらして、フォームを閉じるように。これにより、ブラウザ オブジェクトが破棄されますが、ループは停止しません。破棄されたブラウザーの ReadyState プロパティをテストしています。カブーム!
これを別の方法で行う必要があります。ループ内で UI スレッドをブロックまたはハングアップすることは決して合法ではありません。デッドロックが発生しやすくなります。実際、これはSTA スレッドに関する Microsoft のガイドラインによって禁止されています。回避策は簡単です。待機ループの後のコードを DocumentCompleted イベント ハンドラーに移動します。イベントが特定の Web ページの完了を通知するか、ユーザーが結果に興味を示さなくなったことを知るために、いくつかの状態変数をクラスに追加する必要がある場合があります。