我正在用 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/