从另一个线程在webbrowser中加载大型html文件

时间:2012-05-25 00:35:19

标签: c# .net winforms browser webbrowser-control

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

现在我遇到了一个问题,我需要在选项卡式webbrowser控件中加载大型本地html文件。这些页面的加载会冻结ui。我已经看到很多线程都在谈论生活在另一个线程中的web浏览器,但是所有这些线程似乎都将web浏览器保留在主ui之外。

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

现在,我知道线程规则,声明你不能将另一个线程中创建的控件添加到来自其他线程的控件...我的问题很简单,有没有办法加载一个在显示的webbrowser中没有冻结ui的大型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);
        }
    }

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

1 个答案:

答案 0 :(得分:1)

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

也就是说,有两个选项可能会对你有用 - 我只和他们一起玩了一些,并没有分配时间进入生产能力状态。所以也许可以认为这是一个部分解决方案:/

  1. 在您的控件中托管非UI线程控件(ab)。
  2. 在屏幕外渲染并交换
  3. 在选项1中,链接讨论了将外部应用程序或来自其他AppDomain的WinForms代码托管到您的app / AppDomain中。虽然我无法为您提供(复杂的?)代码要求这样做,但我确实看到您可以在不同的线程上(甚至可能在不同的AppDomain中)使用WebBrowser控件,然后使用所描述的技术在这些链接中显示此控件 - 如果它在您的控件上。 WebBrowser实际上不在您的表单上,而是表单的某个区域会有一个重叠/随其移动的叠加层。我用它来成功地在WinForms应用程序中托管Notepad ++,调整大小有点笨重但非常实用。您可以首先尝试在纯IE(iexplore.exe)中呈现HTML文件并在应用程序中托管该应用程序,然后一旦开始工作,请使用更可控的ActiveX包装器控件(WebBrowser)进行尝试。

    选项2对我来说非常适合使用RichTextBox,但是我无法让WebBrowser以同样的成功做出响应。我所做的是使用RichTextBox生成一个隐藏的Form控件,加载我的数据并让它渲染。在我的主要可见表单上,我展示了另一个说“正在加载......”或类似的RichTextBox。当bg RichTextBox完成时,我会将Rtf字段的内容移动到显示的控件中,并在眨眼间呈现。遗憾的是,WebBrowser没有对其内部数据(即DOM)进行相同级别的控制,但是你可能能够在研究中使用mshtml而不是我能够(c,{{3 }})。

    祝你好运!