2

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

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

我似乎无法让它正常工作。我尝试将 html 文件作为内存流加载到另一个线程中,然后将其提供给 webbrowser,我尝试在另一个线程中创建 webbrowser,但由于经典的线程间异常而关闭,尝试 SupendLayout ...

现在,我知道线程规则指出您不能将在另一个线程中创建的控件添加到来自其他线程的控件...我的问题很简单,有没有办法加载一个大的 html 文件在显示的网络浏览器中这样做时不会冻结用户界面?

如果不需要解决我的问题,则无需成为与线程相关的答案,但这是我最后一次也是一种蹩脚的尝试:

    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);
        }
    }

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

4

1 回答 1

1

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

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

  1. 在您的控件( ab)中托管非 UI 线程控件。
  2. 渲染离屏和交换

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

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

祝你好运!

于 2012-06-11T15:46:17.720 回答