質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

1回答

4729閲覧

C# WebBrowserのサイト読み込みを別スレッドにしたい

退会済みユーザー

退会済みユーザー

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2016/08/28 14:00

C#のWinFormでWebBrowserオブジェクトでサイトを読み込んで、htmlを解析してlinkのURLをFormのListViewに表示させるフォームを作っています。

以下のようにサイトの読み込みが完了したらDocumentCompleted()が実行されるようになっています。

C#

1public partial class Form_main : Form { 2 private WebBrowser wb = new WebBrowser(); 3 private ListView listView1 = new ListView(); 4 5 public main() { 6 InitializeComponent(); 7 8 // サイト読み込みが完了したらwebBrowser_DocumentCompletedを実行する 9 wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser_DocumentCompleted); 10 } 11 12 // サイト読み込み完了後の処理 13 private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { 14 // HtmlAgilityPackを使ってhtmlをパース 15 string html = in_wb.Document.Body.OuterHtml; 16 HtmlAgilityPack.HtmlDocument hDoc = new HtmlAgilityPack.HtmlDocument(); 17 hDoc.LoadHtml(html); 18 19 // aタグのhrefをlistView1にリスト化する 20 foreach (HtmlAgilityPack.HtmlNode node in hDoc.DocumentNode.SelectNodes("//a/@href")) { 21 string url = node.Attributes["href"].Value; 22 ListView1.items.Add(url); 23 } 24 } 25} 26コード

しかしサイトが読み込み完了するまでListViewは更新されませんし、フォームのGUI自体が固まって操作ができません。
そこでWebBrowserでのサイト読み込み処理を別スレッドにして読み込む度にListViewにlinkのURLを追加していきたいのですが、どのような処理にすれば良いのでしょうか?

await/asyncまたはthreadクラスを使うようなのですがなかなか理解できる解説サイトが見つからずこちらで質問させて頂きました。

ちなみにWebBrowserのスレッドはバックグラウンドで行いたいです。
Formを閉じたらWebBrowserのスレッドが途中でも終了を待たずに閉じる、などが可能であればいいです。

お手数ですがどうぞよろしくお願い致します。

開発環境:
Windows10 64bit VisualStudio2015 .NetFramework4.0以上

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

Windows Forms の WebBrowser は UI スレッドのみから操作可能なコントロールであるため他のスレッドから操作することはできません。スレッドを STAThread として作成することで UI スレッドとすることができますがオススメしません。

今回のように HTML を取得するのが目的であれば WebBrowser コントールを使用せずに C# で直接 HTML を読み込んだほうがシンプルに解決できると思うのですがどうでしょうか。

要件で .NET 4.0 とあったので async/await を使用できませんでしたが、.NET 4.5 以上であればこれらを使うことでかなり簡潔に書くことができます。

lang

1using HtmlAgilityPack; 2 3public partial class Form_main : Form 4{ 5 // ページの取得(バックグラウンド) 6 protected void FetchDocumentAsync(string uri) 7 { 8 using (var wc = new WebClient()) 9 { 10 wc.DownloadStringCompleted += (_, e) => 11 { 12 if (e.Error != null) 13 { 14 throw e.Error; 15 } 16 if (DocumentLoaded != null) 17 { 18 var doc = new HtmlDocument(); 19 doc.LoadHtml(e.Result); 20 21 // UI スレッドへのアクセス 22 Invoke(new Action(() => DocumentLoaded(this, new DocumentEventArgs(doc)))); 23 } 24 }; 25 wc.DownloadStringAsync(uri); 26 } 27 } 28 29 private IEnumerable<HtmlNode> CreateNodes(HtmlDocument doc, string xpath) 30 { 31 return doc.DocumentNode.SelectNodes(xpath); 32 } 33 34 public Form_main() 35 { 36 InitializeComponent(); 37 this.DocumentLoaded += LoadList; 38 39 // 適当な場所で 40 FetchDocumentAsync("https://www.google.com"); 41 } 42 43 // 使用例 44 public void LoadList(object sender, DocumentEventArgs e) 45 { 46 foreach (var uri in CreateNodes(e.Document, "//a/@href").Select(x => x.Attributes["href"].Value)) 47 { 48 this.listView1.Items.Add(uri); 49 } 50 } 51 52 public event EventHandler<DocumentEventArgs> DocumentLoaded; 53} 54 55public class DocumentEventArgs : EventArgs 56{ 57 public HtmlDocument Document { get; private set; } 58 59 public DocumentEventArgs(HtmlDocument doc) 60 { 61 this.Document = doc; 62 } 63}

投稿2016/08/30 15:59

編集2016/08/30 16:09
chitoku

総合スコア1610

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問