2012-05-25 43 views
2

我正在设计一个小型应用程序,到目前为止,我已经足够幸运地保持我的线程简单高效,因此ui响应迅速。从另一个线程在webbrowser中加载大型html文件

现在我遇到了一个问题,我需要在标签式浏览器控件中加载大型本地html文件。这些页面的加载冻结了用户界面。我已经看到很多线索都在讨论生活在另一个线程中的web浏览器,但它们都似乎使webbrowser远离主UI。

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

Now ,我知道的线程规则,指出你不能将另一个线程中创建的控件添加到某个其他线程的控件中......我的问题很简单,有没有什么办法可以加载一个大的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); 
     } 
    } 

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

+0

你用t.SetApartmentState(ApartmentState.MTA)检查; ? –

+0

是的,我收到一个错误,说它应该是STA,因为webbrowser是一个ActiveX控件。仍然没有快乐。 – ChG

+0

渲染UI仅在主线程上。您可以在后台线程上创建HTML或FlowDocument或...但一旦它开始呈现您无法控制的回调。我所做的是检查大小,并提出一个消息框“你确定”。如果它是支持虚拟化的UI控件,那么一切都很好。不幸的是,浏览器控件不支持虚拟化。我所做的是,如果选项卡未激活,则不加载该选项卡。在MVVM下,它的工作原理是不同的。我希望你能得到更好的答案。 – Paparazzi

回答

1

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

也就是说,有两个选项可能适合你 - 我只和他们玩过一点,并没有分配时间进入生产能力状态。因此,也许认为这是一个部分解决方案:/

  1. 主机非UI在你的控制(ab)线程控制。
  2. 渲染关闭屏幕和交换

在备选方案1,关于托管的外部应用程序的链接会谈,或WinForms的代码从另一个AppDomain中,融入你的应用程序/ AppDomain中。虽然我无法向您提供执行此操作所需的(复杂的)代码,但我确实发现您可能会在不同的线程上使用WebBrowser控件(甚至可能在不同的AppDomain中),然后使用所描述的技术在这些链接中显示此控件,如果它在您的控制之下。 WebBrowser实际上并不在您的表单上,而是您的表单的某个区域会有一个覆盖层,可以调整/移动它。我已经使用它在WinForms应用程序中成功托管Notepad ++,调整大小稍微笨重但非常实用。您可以先尝试在纯IE(iexplore.exe)中呈现您的HTML文件并在您的应用程序内托管该应用程序,一旦您完成该工作,就可以使用更易控制的ActiveX包装控件(WebBrowser)进行尝试。

选项2对RichTextBox工作得非常好,但我无法让WebBrowser以相同的成功响应。我所做的是使用RichTextBox生成一个隐藏的Form控件,加载我的数据并让它呈现。在我的主要可见窗体上,我展示了另一个RichTextBox,它表示“加载...”或类似。当RichTextBox完成后,我会将Rtf字段的内容移动到显示的控件中,并在眨眼之间进行渲染。令人遗憾的是,WebBrowser并没有对其内部数据(即DOM)进行相同级别的控制,但是您可能能够在使用mshtml的研究中获得比我所能够进一步研究的更多(c,d)。

祝你好运!

+1

非常感谢您的回答。我会尝试第一个选项。 – ChG

相关问题