【发布时间】:2018-08-12 07:20:45
【问题描述】:
我面临的问题是,在处理WebBrowser 控件时(无论它是否可见),它会导致 UI 在导航时冻结一小段时间,当必须按顺序打开多个 URL 时,这会变得非常明显且不可靠。
我目前正在使用 Noseratio's NavigateAsync 扩展方法以静默方式和异步方式导航到多个 URL:(请随意跳过阅读代码并继续提问)
public static async Task<string> NavigateAsync(this WebBrowser webBrowser, string url, CancellationToken token)
{
var tcs = new TaskCompletionSource<bool>();
WebBrowserDocumentCompletedEventHandler handler = (s, arg) => tcs.TrySetResult(true);
using (token.Register(() => { webBrowser.Stop(); tcs.TrySetCanceled(); }, true))
{
webBrowser.DocumentCompleted += handler;
try
{
webBrowser.Navigate(url);
await tcs.Task; // wait for DocumentCompleted
}
finally
{
webBrowser.DocumentCompleted -= handler;
}
}
var documentElement = webBrowser.Document.GetElementsByTagName("html")[0];
var html = documentElement.OuterHtml;
while (true)
{
await Task.Delay(POLL_DELAY, token);
if (webBrowser.IsBusy)
continue;
var htmlNow = documentElement.OuterHtml;
if (html == htmlNow) break;
html = htmlNow;
}
token.ThrowIfCancellationRequested();
return html;
}
但即使是最简单的代码如下:
WebBrowser wb = new WebBrowser() { ScriptErrorsSuppressed = true };
wb.Navigate("https://www.google.com/");
..还是一样的效果。
这是一个快速的demo video,用最简单的代码显示问题。
我还尝试让 WebBrowser 在不同的 STA 线程上运行,但仍然没有成功。
那么,有没有办法在处理WebBrowser 时避免冻结?
在您建议将其替换为 HttpClient 或 WebClient 与 HTMLAgilityPack 之前,请注意我使用 WebBrowser 是为了获取显示的文本,其格式尽可能接近它在浏览器(即尽可能接近手动选择和复制文本)。我尝试(或在线找到)不使用浏览器的每个解决方案都无法实现这一点,即使 the one that produced the closest result 也不够好。
【问题讨论】:
-
嗯,这根本不是一个常见的抱怨,WebBrowser 只是本机代码的包装器,它在引擎盖下有大量线程。 GetElementsByTagName() 调用在大文档上肯定会很昂贵,因为它检索 everything。使用分析器查看费用的去向,也可以分析本机代码。并暂时禁用反恶意软件,因为它在做任何互联网事情时都会起作用。并考虑在 STA 工作线程上执行所有这些操作,因为您不关心视图。
-
@HansPassant 我相信
GetElementsByTagName不是导致问题的原因。请检查上面写着“但即使是最简单的代码,如下所示..”的部分。. -
如果没有其他帮助 - 您可以在单独的 UI 线程中运行该代码,这样它(希望)不会冻结您的主 UI 线程。
-
@HansPassant 这似乎是一个不常见的投诉,因为我没有发现很多关于这个特定问题的问题,但我在两台不同的 PC 上进行了尝试并且具有相同的行为。也许人们大多使用停靠在窗口中的 WebBrowser,所以页面加载时发生的事情并不重要?无论如何,这是一个30sec demo video。
-
@Evk 感谢您的建议。我已经尝试过了,问题中提到了。
标签: c# .net winforms asynchronous webbrowser-control