【发布时间】:2012-05-25 00:35:19
【问题描述】:
我正在设计一个小型应用程序,到目前为止,我很幸运能够保持我的线程简单高效,因此 UI 是响应式的。
现在我面临一个问题,我需要在选项卡式 Web 浏览器控件中加载大型本地 html 文件。这些页面的加载会冻结用户界面。我看到很多线程都在谈论生活在另一个线程中的网络浏览器,但所有这些似乎都将网络浏览器排除在主用户界面之外。
我似乎无法让它正常工作。我尝试将 html 文件作为内存流加载到另一个线程中,然后将其提供给 webbrowser,我尝试在另一个线程中创建 webbrowser,但由于经典的线程间异常而关闭,尝试 SupendLayout...
现在,我知道线程规则指出您不能将在另一个线程中创建的控件添加到来自其他线程的控件...我的问题很简单,有没有办法加载显示的网络浏览器中的大型 html 文件,而这样做时不会冻结 ui?
如果这不是解决我的问题所必需的,则无需成为与线程相关的答案,但这是我最后一次也是一种蹩脚的尝试:
public void openHtml(string input, bool isHtml = true, string tabTitle = "")
{
if (!this.loading)
{
this.loading = true;
ManualResetEvent resetEvent = new ManualResetEvent(false);
Panel panel = new Panel();
TabPage tab = new TabPage();
WebBrowser browser = null;
Thread t = new Thread(() =>
{
browser = new WebBrowser();
browser.CreateControl();
browser.SuspendLayout();
resetEvent.Set();
if (isHtml)
browser.DocumentText = input;
else
browser.Navigate(input);
Application.Run();
});
t.IsBackground = true;
t.SetApartmentState(ApartmentState.STA);
t.Start();
resetEvent.WaitOne();
panel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
panel.Controls.Add(browser);
panel.Dock = DockStyle.Fill;
browser.ObjectForScripting = new JsScriptInterface(this, browser);
browser.Dock = DockStyle.Fill;
tab.Controls.Add(panel);
tab.Text = tabTitle;
this.tabs.TabPages.Add(tab);
}
}
任何帮助将不胜感激。谢谢
【问题讨论】:
-
你检查过 t.SetApartmentState(ApartmentState.MTA); ?
-
是的,我收到一条错误消息,指出它应该是 STA,因为 webbrowser 是一个 ActiveX 控件。仍然没有快乐。
-
只在主线程上渲染 UI。您可以在后台线程上创建 HTML 或 FlowDocument 或 ...,但一旦开始呈现,您就无法控制回调。我所做的是检查尺寸并显示一个消息框“你确定”。如果它是一个支持虚拟化的 UI 控件,那么一切都很好。不幸的是,浏览器控件不支持虚拟化。我要做的是,如果选项卡未处于活动状态,则不加载该选项卡。在 MVVM 下它的工作方式不同。我希望你能得到更好的答案。
-
@ChG 你可以使用方法调用器。
-
@Blam 谢谢你的回答,我很害怕这个。这有点令人沮丧,因为在我的一次尝试中,我在另一个线程中创建了 webbrowser,它确实非常顺利地加载和渲染页面而没有冻结 ui...当它被添加到它的父控件时发生异常加载结束(触发 javascript onload 事件时)。
标签: c# .net winforms browser webbrowser-control