c# - 将 Webbrowser 与 Control.invoke 结合使用

标签 c# browser backgroundworker invoke

我正在开发一个用于网络抓取的 Windows 应用程序。为此,我使用 Webbrowser 控件 - 我不能使用 webrequest/webclient/webresponse 类,因为网页是使用 javascript 动态加载的。
该应用程序运行良好,但由于我进行了大量处理,因此不必要地加载了 UI。我间歇性地收到“无响应”消息。所以我所做的是:

1. 在UI线程上创建webbrowser
2. 将长时间运行的进程放在后台线程
3. 每当我需要获取页面文档时,我都会使用 Control.Invoke。
4.通过调用后台线程返回页面的文档

在回调函数中,我可以看到页面的文档被提取得很好。但是,未正确评估返回给后台工作人员的文档 (HtmlDocument)。当我单步执行调试器时,我收到“函数评估超时消息...”。我玩弄了语法并不断收到无效的强制转换异常或跨线程消息传递异常。
以下是我对回调/委托(delegate)进行编码的方式:

private delegate HtmlDocument RefreshDelegate(); 
private HtmlDocument RefreshBrowser()
    {
        WebBrowser br1 = ((WebBrowser)this.Controls["br1"]); //get webbrowser, "br1"
        br1.Refresh(); //refresh browser
        return br1.Document; //is retrieved correctly
   }


现在是处理“返回的”HTMLDocument 的后台工作程序中的代码:

WebBrowser br1 = ((WebBrowser)this.Controls["br1"]); //get the browser
HtmlDocument document = (HtmlDocument)br1.Invoke(new RefreshDelegate(this.RefreshBrowser));  //not evaluated 
//do stuff with document


遇到调试器消息:“函数评估已禁用,因为先前的函数评估超时。您必须继续执行以重新启用函数评估。”。这是解决这个问题的正确方法吗?正如我所说,我无法使用 webrequest 等获取 javascript 内容,我也无法在 UI 上运行 htmldocument 解析,因为这会导致糟糕的用户体验。此外,碰巧我需要创建几个网络浏览器实例。如果这不是最好的方法,我也对其他图书馆开放。谢谢。

最佳答案

发生这种情况是因为您在工作线程或调试器线程中调用的 WebBrowser 方法实际上并未在该线程上运行。 WebBrowser 是一个单元线程 COM 组件,COM 自动将来自 worker 的调用编码回 UI 线程。这在调试器中效果不佳,因为 UI 线程已被调试器卡住。

对此您无能为力,实际上让这些调用在 UI 线程上运行仍然会让您面临 UI 卡住。唯一的解决方法是在浏览器自己的 STA 线程上完全关闭浏览器。你不能看它,不应该是我想象的问题。检查this answer获取您需要的代码。

关于c# - 将 Webbrowser 与 Control.invoke 结合使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5464547/

相关文章:

c# - ASP.Net MVC3中如何实现打印

c# - ICQ UIN 的正则表达式

browser - 如何缩写 Chrome、Safari 和 Opera?

javascript - 在基于 iframe 的网站中,当用户单击一个 iframe 中的链接后,如何在新窗口中加载所有 iframe?

url - URL 中的奇怪字符

c# - BackgroundWorker 的 IsBusy 是否与 "IsAlive"相同?

.net - 如何取消长时间运行的数据库操作?

c# - 当我的应用程序不会迁移时,我应该关心文化吗?

c# - 通过 C# 调用的 Python 在无限循环中不返回值

c# - BackgroundWorker 和 foreach 循环