1

我有以下 C# 代码从 .NET Windows Forms WebBrowser 控件中获取 DIV 的 html 元素文本值:

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 方法的第二个异步变体:

[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 方法是否有任何其他实用的异步变体,这些变体将使用除此处介绍的其他方法吗?如果您在此处发布它们,请您也发布您为什么更喜欢主题任务的编码解决方案方法的原因。

谢谢你。

[更新]

这是一个屏幕截图,展示了在 UI 线程的第一个示例/异步变体中访问 WebBrowser 控件。

在此处输入图像描述

[更新]

这是一个屏幕截图,展示了在 UI 线程的第二个示例/异步变体中访问 WebBrowser 控件。

在此处输入图像描述

4

1 回答 1

1

在这两种情况下(Task.Factory.StartNew或者Task.Run),您从 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 回答