2

私は小さなアプリケーションを設計していますが、これまでのところ、UI が応答するようにスレッドをシンプルかつ効率的に保つことができて幸運でした。

現在、タブ付きの Web ブラウザー コントロールに大きなローカル html ファイルをロードする必要があるという問題に直面しています。これらのページをロードすると、UI がフリーズします。別のスレッドに存在する Web ブラウザーについて話している多くのスレッドを見てきましたが、それらはすべて Web ブラウザーをメイン UI から遠ざけているように見えました。

私はそれを正しく動作させることができないようです。別のスレッドで html ファイルをメモリ ストリームとして読み込んでから、それを Web ブラウザにフィードしようとしました。別のスレッドで Web ブラウザを作成しようとしましたが、従来のスレッド間例外でシャットダウンされ、SupendLayout を試しました...

今、別のスレッドで作成されたコントロールを別のスレッドのコントロールに追加できないというスレッド ルールについて知っています...私の質問は非常に単純です。大きな html ファイルをロードする方法はありますか?そうしている間にUIをフリーズせずに表示されたWebブラウザで?

これが私の問題を解決するために必要でない場合は、スレッド関連の回答である必要はありませんが、これが私の最後の不自由な試みです:

    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. コントロールで非 UI スレッド コントロールをホストします ( ab )。
  2. オフスクリーンでレンダリングしてスワップ

オプション 1 のリンクは、外部アプリ、または別の AppDomain からの WinForms コードを自分の app/AppDomain にホストすることについて説明しています。これを行うために必要な (複雑な?) コードを提供することはできませんが、WebBrowser コントロールを別のスレッド (おそらく別の AppDomain でも) に配置してから、説明されている手法を使用できる可能性があることがわかります。これらのリンクで、このコントロールを自分のコントロールにあるかのように表示します。WebBrowser は実際にはフォームにはありませんが、フォームの領域には、サイズ変更/移動するオーバーレイが含まれます。これを使用して、WinForms アプリで Notepad++ を正常にホストしました。サイズ変更は少し面倒ですが、非常に使いやすいです。HTML ファイルをプレーンな IE (iexplore.exe) でレンダリングして、アプリ内でそのアプリをホストすることから始めることができます。

オプション 2 は RichTextBox で非常にうまく機能しましたが、WebBrowser で同じ成功を収めることはできませんでした。私がしたことは、RichTextBox を使用して非表示の Form コントロールを生成し、データをロードしてレンダリングすることでした。私のメインの目に見えるフォームで、「読み込み中...」または類似の別のRichTextBoxを示しました。bg RichTextBox が終了したら、Rtf フィールドの内容を表示されたコントロールに移動し、瞬く間にレンダリングしました。悲しいことに、WebBrowser はその内部データ (つまり DOM) に対して同じレベルの制御を公開していませんが、mshtml を使用するための研究を私ができたよりもさらに進めることができるかもしれません ( cd )。

幸運を!

于 2012-06-11T15:46:17.720 に答える