1

.NET Windows Forms WebBrowser コントロールから DIV の html 要素テキスト値を取得する次の C# コードがあります。

private void cmdGetText_Click(object sender, EventArgs e)
{
    string codeString = string.Format("$('#testTextBlock').text();");
    object value = this.webBrowser1.Document.InvokeScript("eval", new[] { codeString });
    MessageBox.Show(value != null ? value.ToString() : "N/A", "#testTextBlock.text()");
}

private void myTestForm_Load(object sender, EventArgs e)
{
    webBrowser1.DocumentText =
        @"<!DOCTYPE html><html>
            <head>
                <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'></script>
            </head>  
            <body>
                <div id='testTextBlock'>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</div>
            </body>
            </html>";  
}

それはうまくいきます。同期的に動作します。

cmdGetText_Click メソッドの最初の非同期バリエーションを次に示します。

private async void cmdGetText_Click(object sender, EventArgs e)
{
    string codeString = string.Format("$('#testTextBlock').text();");

    object value = await Task.Factory.StartNew<object>(() =>
    {
        return this.Invoke(
                new Func<object>(() =>
                {
                    return 
                       this.webBrowser1.Document
                        .InvokeScript("eval", new[] { codeString });
                }));
    });

    MessageBox.Show(value != null ? value.ToString() : "N/A", "#myTestText.text()");
}

cmdGetText_Click メソッドの 2 番目の非同期バリエーションは次のとおりです。

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public partial class myTestForm : Form {
...

private async void cmdGetText_Click(object sender, EventArgs e)
{
    webBrowser1.ObjectForScripting = this;
    string codeString = string.Format("window.external.SetValue($('#testTextBlock').text());");

    await Task.Run(() =>
    {
        this.Invoke((MethodInvoker)(()=>{this.webBrowser1.Document.InvokeScript("eval", new[] { codeString });})); 
    });
}

public void SetValue(string value)
{
    MessageBox.Show(value != null ? value.ToString() : "N/A", "#myTestText.text()");
}

質問: 元の cmdGetText_Click メソッドの実用的な非同期バリエーション、ここで提示された以外のいくつかのアプローチを使用するバリエーションはありますか? ここに投稿する場合は、対象タスクのコーディング ソリューションのアプローチを好む理由も投稿してください。

ありがとうございました。

[アップデート]

これは、WebBrowser コントロールが UI スレッドからの最初のサンプル/非同期バリアントでアクセスされることを示すスクリーンショットです。

ここに画像の説明を入力

[アップデート]

これは、UI スレッドからの 2 番目のサンプル/非同期バリアントで WebBrowser コントロールにアクセスすることを示すスクリーンショットです。

ここに画像の説明を入力

4

1 に答える 1

1

どちらの場合も ( または のいずれTask.Factory.StartNewTask.Run)、UI スレッドからプール スレッドで新しいタスクを開始し、 を介して UI スレッドを同期的にコールバックしますControl.Invoke

基本的に、スレッド切り替えやスレッド間マーシャリングのオーバーヘッドなしで、同じ「非同期」呼び出しを実行できます。

await Task.Factory.StartNew(
    () => {
        this.webBrowser1.Document.InvokeScript(...);
    },
    CancellationToken.None,
    TaskCreationOptions.None,
    TaskScheduler.FromCurrentSynchronizationContext());

次のようにすることもできます。

await Task.Yield();
this.webBrowser1.Document.InvokeScript(...);

または、なしawaitで、次のように:

this.webBrowser1.BeginInvoke(new Action( ()=> 
    this.webBrowser1.Document.InvokeScript(...) ));

どちらの場合も、上記の構成要素の有用性には疑問があります。それらはすべて、オリジナルと同じように、UI スレッド メッセージ ループの将来の反復でコールバックを実行するだけawait Task.Run( () => this.Invoke(...) )です。

[更新]プール スレッドで実行時間の長い操作を開始し、作業を継続しながら UI を非同期的に更新する場合、コードは次のようになります。

private async void button_Click(object sender, EventArgs e)
{
    try
    {
        // start and await the background task
        var words = new String[] { "fire", "water", "air" };

        await Task.Run(() =>
        {
            // do some CPU-bound work, e.g. find synonyms of words
            foreach (var word in words)
            {
                // do the next piece of work and get the result
                var synonyms = FindSynonyms(word);

                // queue an async UI update
                var wordArg = word;
                var synonymsArg = String.Join(",", synonyms);

                this.webBrowser.BeginInvoke(new Action(() =>
                {
                    this.webBrowser.Document.InvokeScript("updateSynonyms",
                        new object[] { wordArg, synonymsArg });
                }));
            }
        });
    }
    catch (Exception ex)
    {
        // catch all exceptions inside this "async void" event handler
        MessageBox.Show(ex.Message);
    }
}
于 2014-01-14T14:42:42.740 に答える