2012-05-25 76 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

相關問題