在WebBrowser控件上页面导航后尝试执行JavaScript时出错

Ral*_*lfE 4 javascript browser silverlight windows-phone-7

我在WP7应用程序中使用WebBrowser控件并设置IsScriptEnabled为true.然后,当尝试通过InvokeScriptWebBrowser 调用脚本时,我看到一个奇怪的行为:脚本在第一页上正确执行.然后我导航到另一个页面,Navigate()并尝试执行我收到以下错误消息的脚本:

"发生了未知错误.错误:80020006".

IsScriptEnabled在导航到下一页之前我试图设置为true - 没有运气.等待完成文档加载状态也没有帮助.

所有HTML文件都存储在独立存储中并正确显示.只有脚本交互不起作用.

有任何想法吗?

que*_*atl 5

--edit/quetz:如果您在页面上没有运行javascripts时遇到问题:请务必查看我在http://social.msdn.microsoft.com/Forums/en上发布的主题的调查结果-AU/jscript/thread/bac9f056-e0de-449e-a1b6-36e745fa59c6 - 也许你的问题与一些不幸的时间或属性设定器排序有关.事实证明,如果您在XAML中对URL进行硬编码,那么您必须确保在该XAML中,在SOURCE属性之前设置IsScriptEnabled,否则您将有很多失败取决于您的页面具有哪种doctype.这同样适用于在代码中设置Source或Navigate',但这在那里非常明显.另一方面,乍一看,绑定似乎无论如何都能正常工作. - /编辑

很长一段时间以来你的帖子都过去了,但是如果你的记忆中仍有问题,那么它可能对你有所帮助.

让我们先思考一下:

也许页面还没有加载?你说所有的页面都是ISO,因此它们会在眨眼之间加载,但仍需要一些时间.你只指出了Navigate()方法,这对我来说有点奇怪,因为当InvokeScript()时,最重要的是,在接收Navigated 事件之后或之后调用它.虽然您可能已正确实现它,并且您可能使用Navigate()错误地键入了Navigated事件 - 但根据您编写的内容,您也可能尝试执行以下操作:

void myfuntion()
{
    webbrowser.Navigate("pages/index.html");
    webbrowser.InvokeScript("myjsfunc");
}
Run Code Online (Sandbox Code Playgroud)

这几乎不会奏效.实现它的正确方法是:

...
    //elsewhere
    webbrowser.Navigated += wb_Navigated;
...

void myfuntion()
{
    webbrowser.Navigate("pages/index.html"); // or webbrowser.Source = ...
}

void wb_Navigated(object sender, NavigationEventArgs e)
{
    webbrowser.InvokeScript("myjsfunc");
}
Run Code Online (Sandbox Code Playgroud)

只有这样你才能确定页面已加载.没有它,你几乎可以保证失败.

但是,在这种情况下,您可能会获得0x80020101的 hresult.

至少在7.0,7.1和7.5版本的sdk版本中,当JS引擎遇到符号时,会使用该版本.许多其他情况也会报告此错误,但这是最常见的.每当您尝试调用包含未定义名称的enything时,您将看到0x80020101.例如,InvokeScript("eval","askdjaslkdsajdla")会抛出它,假设这个变量不是为了欺骗示例而创建的:)

我正在写这个,因为如果你没有对Navigated作出反应并过早地拨打电话,那么内存页面可能仍然是旧内容的旧页面,因此你尝试参考的名字可能是失踪.

但是,如果你真的看到80020006(这是名称发现但是来自OLE层),那么我认为问题出在其他地方.然后,我们必须深入挖掘..

每当您尝试在Navigated-event-handler期间调用InvokeScript时,您可能会成为webbrowser中非常随机(至少从我的经验)错误的受害者.简单地说:有时,尽管收到"导航"通知,但WebBrowser实际上还没有处于完全准备/渲染/ wtf状态.

我不确切知道什么时候,我认为它与页面大小,脚本大小/时间或外部链接资源的数量有关.

当发生这种情况时,您将观察除0x80020101以外的ComException,并且我几乎可以肯定它将是80020006.简单的InvokeScripts("eval","mom")可以执行并正确运行,但它越复杂,机会越小.例如,当它发生时,直接引用body元素或其子元素的所有脚本在解析该元素时将立即失败.如果你使用像jQuery这样的库 - 你可能没有事件明确声明了body的引用 - 如果库接触它,它将以相同的方式失败,具有相同的异常.奇怪的是,document.head不受问题的影响,你可以毫无问题地引用它.根据我的观察,在这种情况下只有身体是有问题的.

实际上,在写完之后 - 我看到你的情况可能就是这样,因为你试图修改'document.body.style.fontSize'..

无论如何,没有即时的方法来解决问题,因为问题出现在webbrowser的内部时间中,并且恰好报告"导航"太快了.我确定它在Web浏览器中是一个可怕的错误,也许它们将在未来的某个版本中修复.在此之前,处理它的唯一方法是...延迟调用,直到浏览器真正完成解析页面.

换句话说:如果你试图在browser.Navigated处理程序中正确调用InvokeScript,你可能会得到一个不同于 0x80020101 的异常(这意味着你给InvokeScript的js代码形成不好).如果你遇到这样的错误(可能是80020006),那么检查你是否可以通过invokescript"触摸"document.body.如果你得到不同的错误,那么事实并非如此.但是,如果你得到相同的错误,那么很可能就是这种情况,而问题是你或者webbrowser不幸的时机.您必须中止尝试,启动125..500毫秒的计时器,从处理程序返回,以便允许浏览器继续其内部作业,然后,当计时器过去时 - 重试原始呼叫并祈祷.在延迟注意期间,您还必须以相同的方式监听异常,因为您可能会再次获得相同的错误,并且再次(...).

从我的实验来看,在这种情况下,500毫秒总是足够的,但它对于用户体验来说是丑陋的.125是非常不明显的,但随后 - 有时它太快了,必须完成2-3次重试.

但是,无论发生什么 - 一旦你导航,接收导航,然后成功触摸document.body - timingerror将永远不会再发生,对于该页面.一旦内部浏览器的齿轮运行,InvokeScript将像魅力一样工作,直到你加载下一页..;)

根据我的经验,如果你可以控制页面的原始来源,你也可以尝试一些更简单的解决方法 - 在你的页面,身体的某个地方,地方:

<script type="text/javascript"> window.external.notify('somestringyouwillknow');  </script>
Run Code Online (Sandbox Code Playgroud)

并在您的C#或XAML代码中,附加到WebBrowser.ScriptNofity事件.每当你加载那个页面时,它都会调用ScriptNotify并为你提供你在那里写的字符串.它肯定会在Navigated事件之后到达,并且如果你发现了这样的ScriptNotify通知 - 显然JS引擎已经加载并且主体至少被部分解析,并且可能还会初始化和触摸document.body.