c# - 如何从 C# 主机应用程序执行 Javascript 回调函数

标签 c# javascript callback webbrowser-control

我正在用 C# 创建一个应用程序,为大多数 GUI 托管自定义网页。作为宿主,我想提供一个javascript API,以便嵌入式网页可以访问宿主应用程序提供的一些服务。

我已经能够使用 WebBrowser.ObjectForScripting 属性并实现脚本类来获得此工作的简单案例。这对于同步 javascript 调用非常有用。然而,主机提供的一些操作是长时间运行的,我想提供在操作完成时回调 javascript 的能力。这就是我遇到麻烦的地方。

Javascript:

function onComplete( result )
{
    alert( result );
}

function start()
{
    window.external.LongRunningProcess( 'data', onComplete );
}

C#:

[ComVisible(true)]
public class ScriptObject
{
    public void LongRunningProcess( string data, <???> callback )
    {
        // do work, call the callback
    }
}

javascript 中的“开始”函数启动了整个过程。我遇到的问题是,回调的类型是什么?我应该如何从 C# 中调用它?

如果我使用字符串类型进行回调,它会编译并运行,但从 LongRunningProcess 方法回调实际上包含 onComplete 函数的全部内容(即 'function onComplete( result ) { alert( result ) }' )

如果我使用对象类型,它会作为 COM 对象返回。使用 Microsoft.VisualBasic.Information.TypeName 方法,它返回“JScriptTypeInfo”。但据我所知,这不是真正的类型,MSDN 中也没有真正提及它。

如果我使用 IReflect 接口(interface),它运行时没有错误,但我找不到对象上的任何成员、字段或属性。

解决方法是传递回调函数的字符串名称而不是函数本身(即 window.external.LongRunningProcess( 'data', 'onComplete' ); )。我确实知道如何按名称执行 javascript 函数,但我不想在网页中要求使用该语法,它也不适用于 javascript 中的内联回调定义。

有什么想法吗?

就其值(value)而言,我已经让这个系统与 Chromium Embedded 框架一起工作,但我正在努力将代码移植到 WebBrowser 控件,以避免重新分发 Chromium 的庞大规模。然而,正在开发的 HTML 页面最终将在 Linux/Mac OSX 上运行,其中可能仍会使用 Chromium。

最佳答案

你可以为此使用反射:

[ComVisible(true)]
public class ScriptObject
{
    public void LongRunningProcess(string data, object callback)
    {
        string result = String.Empty;

        // do work, call the callback

        callback.GetType().InvokeMember(
            name: "[DispID=0]",
            invokeAttr: BindingFlags.Instance | BindingFlags.InvokeMethod,
            binder: null,
            target: callback,
            args: new Object[] { result });
    }
}

您也可以尝试动态 方法。如果它能工作的话会更优雅,但我还没有验证过:

[ComVisible(true)]
public class ScriptObject
{
    public void LongRunningProcess(string data, object callback)
    {
        string result = String.Empty;

        // do work, call the callback

        dynamic callbackFunc = callback;
        callbackFunc(result);
    }
}

[更新] dynamic 方法确实非常有效,并且可能是当您拥有 JavaScript 函数对象时从 C# 回调 JavaScript 的最简单方法。 Reflection 和 dynamic 都允许调用匿名 JavaScript 函数。示例:

C#:

public void CallbackTest(object callback)
{
    dynamic callbackFunc = callback;
    callbackFunc("Hello!");
}

JavaScript:

window.external.CallbackTest(function(msg) { alert(msg) })

关于c# - 如何从 C# 主机应用程序执行 Javascript 回调函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21138740/

相关文章:

javascript - jquery $.ajax() 及其成功回调 - 它返回到哪里?

angularjs - $http 回调的执行顺序

c# - 如何在 .NET/Visual Studio 中创建可浏览的类属性

c# - 使用 Outlook 2007 的 C# 加载项将焦点设置到 "new message"表单中的主题字段

javascript - document.getElementById 不适用于 <a> 标签

javascript - Meteor.call() 回调不将值返回到模板

javascript - 使用 javascript 动态嵌入对象

callback - 如何在 Dojo 中的另一个函数(非 AJAX)完成后调用一个函数(非 AJAX)?

c# - 为什么 C# 控制台应用程序可能会调用 `Application.Run()` ?

c# - jet.com 合作伙伴 API - Rest、JSON、RestSharp?