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

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

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

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

Q&A

解決済

2回答

3732閲覧

C# 別スレッドからWindowsフォームにアクセスしたい

umeshiba

総合スコア7

C#

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

0グッド

0クリップ

投稿2017/02/27 07:58

前提:
・Windowsフォームに3つWebBrowserがある
・このWebBrowserを非同期に操作したい(目的)
・非同期の処理はtaskを使って実行する

行ったこと:
・Windowsフォームを操作する処理を関数化する(どのWebBrowserを操作するのかは引数で指定する)
・上記の関数を複数のtaskを使用して呼び出す
→エラーが出る「指定されたキャストは有効ではありません。」

グーグルさん:
「Windowsフォームのコンテンツには別スレッドから直接アクセスできない。
呼び出し元と違うスレッドならデリゲートを作ってそこから経由してアクセスしてね」

以下質問です。

調べて以下のようにしてみたところ「メソッド名が必要です」とエラーが出てしまいます。
いくつかの調べたサイトでは、delegateを宣言する時は全てvoidだったのですが、voidではないとダメなのでしょうか?
だけどvoidだと値を読み取って渡すということができないような。と考えていたら混乱してしまいました。
ご教授頂けたら幸いです。

以下ソースコードです。
public partial class Form1 : Form
{
public delegate void GetElementsDelegate(HtmlElementCollection objHtmlElementCollection);

private async void button1_Click(object sender, EventArgs e) { for (intI = 0; intI <= 2; intI++) { //【引数によって使用するWebBrowserを制御する】 WebBrowser WebBrowserTemporary = null; if (intI == 0) { WebBrowserTemporary = this.WebBrowser0; } else if (intI == 1) { WebBrowserTemporary = this.webBrowser1; } else if (intI == 2) { WebBrowserTemporary = this.webBrowser2; } else { return; } //タスクを複数起動する Task.Factory.StartNew(() => { LoadSart(WebBrowserTemporary); }); } } private void LoadSart(WebBrowser WebBrowserTemporary) { WebBrowserTemporary.Navigate("URL"); HtmlElementCollection oHtmlElementCollection; //ここでエラーが出る(遷移先のURLを読み込みたい) oHtmlElementCollection = Invoke(new GetElementsDelegate(GetElements(WebBrowserTemporary))) ; } public HtmlElementCollection GetElements(WebBrowser aoWebbrowser) { return aoWebbrowser.Document.GetElementsByTagName("section"); ; }

}

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

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

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

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

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

guest

回答2

0

ベストアンサー

こんにちは。

WebBrowserはたいへん複雑なコンポーネントなので、それを異なるスレッドから制御するのは厳しいと思います。例えば、HtmlElementCollectionを受け取ったとしても、それはUIスレットが所有していますから、変化しないことが確実なタイミングでないとアクセスできません。(まさに更新している時にアクセスすると何が起こるか分かりません。非常に危険なアクセスになります。)
HtmlElementCollectionの更新前と更新後に何かのコールバックが呼ばれるなら、そこで排他制御処理を入れることができると思いますが、昔触った時はそのようなコールバックはなかったような記憶が有ります。
別スレッドから制御したいという要求はあまりないコンポーネントですので、今も他のスレッドから制御するために必要なI/Fは用意されていない可能性が高いと感じます。

3つ異なるプロセスを起動してそれぞれで制御し、そのWebBrowser用のウィンドウを何か1つのウィンドウ上に乗せてしまうような構造の方が確実な気がします。Windows自体は確か別プロセスのウィンドウを1つのウィンドウへ貼り付けるような機能をサポートしていたと思います。(親ウィンドウに別のプロセスのウィンドウを指定できた記憶があります。違っていたらごめんなさい。)

投稿2017/02/27 09:45

Chironian

総合スコア23272

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

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

0

TaskScheduler.FromCurrentSynchronizationContext();
これがUIスレッドで、このUIスレッドを使って、更新処理をすればいいと思います。

参考:http://d.hatena.ne.jp/lironi5/20130621/p1

Taskは、Task<Result>という感じで返り値が持てるので、そういうふうに作れば作れると思います。

delegate云々は過去の話ですね。

投稿2017/02/27 08:09

編集2017/02/27 09:14
kiichi54321

総合スコア1984

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問