在WebBrowser中调用脚本,并等待它完成运行(同步)

时间:2013-05-22 12:08:17

标签: c# javascript winforms browser

我正在使用webBrowser.Document.InvokeScript("Function")运行javascript,它位于使用Winforms WebBrowser打开的本地文件中。

问题是,我需要javascript才能继续执行。我该如何等待/倾听?

这是我的C#代码:

    private void Button1_ItemClick_1(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
    {
        webBrowser.Document.InvokeScript("Script_A");
        Method_A();
        DialogResult = System.Windows.Forms.DialogResult.OK;
    }

Javascript代码:

<script>function Script_A() { Script_B(); }</script>

如何在Script_B完成之前确保没有执行Method_A?

2 个答案:

答案 0 :(得分:7)

使用async / await,您可以等到脚本执行而不会阻止UI。

public async void AMethod()
{
    string script =
     @"<script>
        function Script_A() { 
            Script_B(); 
            window.external.Completed(); //call C#: CallbackObject's Completed method
        }
        function Script_B(){
            alert('in script');
        }
    </script>";

    TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

    webBrowser1.ObjectForScripting = new CallbackObject(tcs);
    //Ensure DocumentText is loaded before invoking "InvokeScript",
    //by extension method "SetDocumentTextAsync" (below)
    await webBrowser1.SetDocumentTextAsync(script);
    webBrowser1.Document.InvokeScript("Script_A");

    await tcs.Task;

    MessageBox.Show("Script executed");
}


[ComVisible(true)]
public class CallbackObject
{
    TaskCompletionSource<bool> _tcs = null;

    public CallbackObject(TaskCompletionSource<bool> tcs)
    {
        _tcs = tcs;
    }
    public void Completed()
    {
        _tcs.TrySetResult(true);
    }
}

public static class BrowserExtensions
{
    public static Task SetDocumentTextAsync(this WebBrowser wb, string html)
    {
        TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
        WebBrowserDocumentCompletedEventHandler completedEvent = null;
        completedEvent = (sender, e) =>
        {
            wb.DocumentCompleted -= completedEvent;
            tcs.SetResult(null);
        };
        wb.DocumentCompleted += completedEvent;

        wb.ScriptErrorsSuppressed = true;
        wb.DocumentText = html;

        return tcs.Task;
    }
}

答案 1 :(得分:0)

你需要实现一个回调方法(不要遗忘ComVisible-Attribute)你将使用

从你的脚本调用
window.mymethod();

这样,你实际上需要分开&#39;你的方法。

Here是来自SO的好文章。


here是一个教程:

从WebBrowser中托管的JavaScript调用C#方法

AspDotNetDev,2011年5月6日

此示例演示如何从JavaScript调用C#。它还显示参数可以传递给C#方法。

首先,创建一个Windows窗体应用程序。然后,将WebBrowser控件添加到窗体。然后修改表单的代码,使其如下所示:

 namespace WindowsFormsApplication6
{
    // This first namespace is required for the ComVisible attribute used on the ScriptManager class.
    using System.Runtime.InteropServices;
    using System.Windows.Forms;

    // This is your form.
    public partial class Form1 : Form
    {
        // This nested class must be ComVisible for the JavaScript to be able to call it.
        [ComVisible(true)]
        public class ScriptManager
        {
            // Variable to store the form of type Form1.
            private Form1 mForm;

            // Constructor.
            public ScriptManager(Form1 form)
            {
                // Save the form so it can be referenced later.
                mForm = form;
            }

            // This method can be called from JavaScript.
            public void MethodToCallFromScript()
            {
                // Call a method on the form.
                mForm.DoSomething();
            }

            // This method can also be called from JavaScript.
            public void AnotherMethod(string message)
            {
                MessageBox.Show(message);
            }
        }

        // This method will be called by the other method (MethodToCallFromScript) that gets called by JavaScript.
        public void DoSomething()
        {
            // Indicate success.
            MessageBox.Show("It worked!");
        }

        // Constructor.
        public Form1()
        {
            // Boilerplate code.
            InitializeComponent();

            // Set the WebBrowser to use an instance of the ScriptManager to handle method calls to C#.
            webBrowser1.ObjectForScripting = new ScriptManager(this);

            // Create the webpage.
            webBrowser1.DocumentText = @"<html>
                <head>
                    <title>Test</title>
                </head>
                <body>
                <input type=""button"" value=""Go!"" onclick=""window.external.MethodToCallFromScript();"" />
                    <br />
                    <input type=""button"" value=""Go Again!"" onclick=""window.external.AnotherMethod('Hello');"" />
                </body>
                </html>";
        }
    }
}

请注意,您的应用程序可能是WindowsFormsApplication6以外的命名空间的一部分,但如果您明确遵循上述说明,其余代码应该可以正常工作。我创建了这个提示/技巧,因为有人问我一个问题,他们并不理解我发送给他们的这个样本。这个提示/技巧通过修复我发现的两个错误,添加了未提及的使用语句,并通过大量注释代码,使样本更容易理解。希望你们其他人也会发现这个用途。 许可证