Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从C#主机应用程序执行Javascript回调函数_C#_Javascript_Callback_Webbrowser Control - Fatal编程技术网

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

如何从C#主机应用程序执行Javascript回调函数,c#,javascript,callback,webbrowser-control,C#,Javascript,Callback,Webbrowser Control,我正在用C#创建一个应用程序,为大多数GUI托管自定义网页。作为主机,我希望提供一个javascript API,以便嵌入式web页面能够访问主机应用程序提供的一些服务 我已经能够通过使用WebBrowser.ObjectForScript属性和实现脚本类获得这项工作的简单案例。这对于同步javascript调用非常有效。但是,主机提供的一些操作是长时间运行的,我希望提供在操作完成时回调javascript的功能。这就是我遇到麻烦的地方 Javascript: function onComple

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

我已经能够通过使用WebBrowser.ObjectForScript属性和实现脚本类获得这项工作的简单案例。这对于同步javascript调用非常有效。但是,主机提供的一些操作是长时间运行的,我希望提供在操作完成时回调javascript的功能。这就是我遇到麻烦的地方

Javascript:

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

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

[ComVisible(true)]
公共类脚本对象
{
公共void LongRunningProcess(字符串数据,回调)
{
//做工作,打电话回叫
}
}
javascript中的“start”函数启动了整个过程。我遇到的问题是,回调的类型是什么?从C#我该怎么称呼它

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

如果我使用对象类型,它将作为COM对象返回。使用Microsoft.VisualBasic.Information.TypeName方法,它返回“JScript类型信息”。但据我所知,这不是一个真正的类型,也没有任何真正提到它通过所有的MSDN

如果我使用DirectReflect接口,它运行时不会出错,但在对象上找不到任何成员、字段或属性

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

有什么想法吗


值得一提的是,我已经让这个系统与Chromium嵌入式框架一起工作,但我正在将代码移植到WebBrowser控件,以避免Chromium重新分发的巨大规模。但是,正在开发的HTML页面最终将在Linux/Mac OSX上运行,在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 });
    }
}
您也可以尝试
dynamic
方法。如果能用的话会更优雅,但我还没有证实:

[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);
    }
}
[UPDATE]当您有一个JavaScript函数对象时,
动态
方法确实非常有效,并且可能是从C#调用JavaScript的最简单方法。反射和
dynamic
都允许调用匿名JavaScript函数。例如:

C#:

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

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

正如
@Frogmouth
在这里指出的那样,您可以将回调函数名传递给
LongRunningProcedure

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

function start()
{
    window.external.LongRunningProcess( 'data', 'onComplete' );
}
LongRunningProcedure
完成时,使用
.InvokeScript
,如下所示:

    public void LongRunningProcess(string data, string callbackFunctionName)
    {
        // do work, call the callback

        string codeStrig = string.Format("{0}('{1}')", callbackFunctionName, "{{ Your result value here}}");
        webBrowser1.Document.InvokeScript("eval", new [] { codeStrig});  
    }

我不是C语言的程序员。。。也许这并不能解决您的问题,但我的同事使用一个库来解释C#中的JS(我不记得是C#还是.net)可能对您没有用处,但您尝试查看:。或者您可以像字符串
window.external.LongRunningProcess('data','onComplete')一样传递
callback
eval
在这里显得多余。如果回调函数是通过名称传递的(而不是作为对象,如OP的问题中所述),那么下面的操作将不需要
eval
webBrowser1.Document.InvokeScript(callbackFunctionName,new object[]{result})
。虽然,
eval
在需要向页面()中注入新的JavaScript代码时可能很有用。因为我的目标是.NET2.0,所以我不能使用dynamic,但很高兴知道它是有效的。您是如何知道神奇的“[DispID=0]”字符串的?有关于这个的文档吗?我从COM荣耀时代就知道了,但我只是搜索了一下,找不到任何官方来源。但也有很多非官方的。记录了
Type.InvokeMember
DispId[…]
语法。通过使用类型为“dynamic”的参数等“dynamic callback”,可以更好地避免“dynamic callbackbunc=callback;”行。我发现了一个奇怪的问题,即如果回调没有任何参数,它就不起作用,因此在您的示例中,“callbackFunc()”就不起作用。知道为什么吗?@Martynas确实
callbackFunc()
不起作用。我目前对此没有任何解释,但有一个非常简单的解决方法,可以这样称呼它:
callbackFunc(Type.Missing)
    public void LongRunningProcess(string data, string callbackFunctionName)
    {
        // do work, call the callback

        string codeStrig = string.Format("{0}('{1}')", callbackFunctionName, "{{ Your result value here}}");
        webBrowser1.Document.InvokeScript("eval", new [] { codeStrig});  
    }