从另一个线程在网络浏览器中加载大型 html 文件

本文关键字:加载 大型 html 文件 浏览器 另一个 线程 网络 | 更新日期: 2023-09-27 18:35:12

我正在设计一个小应用程序,到目前为止,我很幸运地保持了线程的简单高效,因此 UI 是响应式的。

现在我遇到了一个问题,我需要在选项卡式 Web 浏览器控件中加载大型本地 html 文件。加载这些页面会冻结 UI。我见过许多线程在谈论生活在另一个线程中的网络浏览器,但所有这些线程似乎都将网络浏览器排除在主 UI 之外。

我似乎无法让它正常工作。我尝试在另一个线程中加载 html 文件作为内存流,然后将其馈送到网络浏览器,我尝试在另一个线程中创建网络浏览器,但由于经典线程间异常而关闭,尝试了 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);
        }
    }

任何帮助将不胜感激。谢谢

从另一个线程在网络浏览器中加载大型 html 文件

我过去遇到过类似的问题,可以告诉你没有"真正的"解决方案。 如您所知,问题是 UI 代码必须使用相同的线程,并且不太好的线程代码位于您无法控制的控件(即 WebBrowser)中。 除非有人编写一个更好的 WebBrowser 控件,并具有适当的线程,并且不会挂起 UI(不太可能),否则我们不会有一个很棒的解决方案。

也就是说,有 2 个选项可能适合您 - 我只玩了一点,还没有分配时间进入生产能力状态。 所以也许认为这是一个部分解决方案:/

  1. 在控件中托管非 UI 线程化控件 (a、b)。
  2. 屏幕外渲染并交换

在选项 1 中,链接讨论如何将外部应用程序或来自另一个应用程序域的 WinForms 代码托管到您的应用程序/应用程序域中。 虽然我无法为您提供执行此操作所需的(复杂?)代码,但我确实认为您可以在不同的线程(甚至可能在不同的 AppDomain 中)上拥有 WebBrowser 控件,然后使用这些链接中描述的技术将此控件显示为在您的控件上。 Web浏览器实际上并不在您的表单上,而是表单的一个区域将具有一个覆盖层,该覆盖层将随之调整大小/移动。 我已经使用它在WinForms应用程序中成功托管Notepad++,调整大小有点笨拙,但非常有用。 你可以首先尝试在普通IE(iexplore.exe)中呈现你的HTML文件,并在你的应用中托管该应用,一旦你开始工作,就可以尝试使用更可控的ActiveX包装器控件(WebBrowser)。

选项 2 在 RichTextBox 上对我来说效果很好,但我无法让 WebBrowser 以同样的成功响应。 我所做的是使用 RichTextBox 生成一个隐藏的 Form 控件,加载我的数据并让它呈现。 在我的主要可见窗体上,我显示了另一个富文本框,上面写着"正在加载..."。或类似。 当 bg RichTextBox 完成后,我会将 Rtf 字段的内容移动到显示的控件中,并在眨眼间呈现。 可悲的是,WebBrowser并没有公开对其内部数据(即DOM)相同级别的控制,但是您可能能够在研究中比我更深入地使用mshtml(c,d)。

祝你好运!