26

私の目標

メインの処理スレッド(非GUI)を使用し、必要に応じて独自のバックグラウンドスレッドでGUIをスピンオフできるようにし、メインの非GUIスレッドを引き続き機能させたいと考えています。言い換えれば、メインの非GUIスレッドをGUIスレッドの所有者にし、その逆はしたくないということです。これがWindowsフォーム(?)でも可能かどうかはわかりません

バックグラウンド

IComponentコントローラーがアセンブリを動的にロードし、単一のメソッドで共通のインターフェイスを実装するクラスをインスタンス化して実行するコンポーネントベースのシステムがありますDoStuff()

ロードされるコンポーネントは、xml構成ファイルを介して、およびのさまざまな実装を含む新しいアセンブリを追加することによって構成されますIComponent。コンポーネントは、メインアプリケーションにユーティリティ機能を提供します。メインプログラムがそれを実行している間、たとえば原子力発電所を制御している間、コンポーネントは(独自のスレッドで)ユーティリティタスクを実行している可能性があります。たとえば、データベースのクリーニング、電子メールの送信、プリンターでの面白いジョークの印刷などです。私が望んでいるのは、これらのコンポーネントの1つがGUIを表示できるようにすることです。たとえば、前述の電子メール送信コンポーネントのステータス情報を表示できます。

システム全体の寿命は次のようになります

  1. アプリケーションが起動します。
  2. ロードするコンポーネントの構成ファイルを確認してください。それらをロードします。
  3. コンポーネントごとに、実行DoStuff()して初期化し、独自のスレッドで独自の生活を送るようにします。
  4. 主なアプリケーションを続けてください-仕事の王様、永遠に。

コンポーネントがでGUIを起動した場合、まだポイント3を正常に実行できていませんDoStuff()。GUIが閉じられるまで停止するだけです。そして、GUIが閉じられるまで、プログラムはポイント4に進みません。

これらのコンポーネントが独自のWindowsフォームGUIを起動できるようになっていると便利です。

問題

コンポーネントがGUIを起動しようとするとDoStuff()(コードの正確な行はコンポーネントの実行時です)、コンポーネント、つまりシステムはGUIが閉じられるまでその行Application.Run(theForm)で「ハング」します。Application.Run()さて、起動したばかりのGUIは、期待どおりに正常に機能します。

コンポーネントの例。1つはGUIとは何の関係もありませんが、2つ目はピンクのふわふわのウサギが入ったかわいいウィンドウを起動します。

public class MyComponent1: IComponent
{
    public string DoStuff(...) { // write something to the database  }
}

public class MyComponent2: IComponent
{
    public void DoStuff()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form());

        // I want the thread to immediately return after the GUI 
        // is fired up, so that my main thread can continue to work.
    }
}

私は運が悪かったのでこれを試しました。独自のスレッドでGUIを起動しようとしても、GUIが閉じられるまで実行は停止します。

public void DoStuff()
{
    new Thread(ThreadedInitialize).Start()
}

private void ThreadedInitialize()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form());
}

GUIをスピンオフして、後で戻ることは可能Application.Run()ですか?

4

3 に答える 3

13

Application.Runメソッドは、1つ(または複数)のフォームを表示し、すべてのフォームが閉じられるまで実行される標準のメッセージループを開始します。すべてのフォームを閉じるか、アプリケーションを強制的にシャットダウンする場合を除いて、そのメソッドからの復帰を強制することはできません。

ただし、 ApplicationContext(新しいForm()の代わりに)をApplication.Runメソッドに渡すことができ、 ApplicationContextを使用して一度に複数のフォームを起動できます。アプリケーションは、それらがすべて閉じられたときにのみ終了します。ここを参照してください:http://msdn.microsoft.com/en-us/library/system.windows.forms.application.run.aspx

また、非モーダルで表示するフォームは引き続きメインフォームと一緒に実行されるため、互いにブロックされない複数のウィンドウを使用できます。これが実際にあなたが達成しようとしていることだと思います。

于 2008-08-05T21:45:17.663 に答える
0

十分にハックすれば可能だと思いますが、お勧めできません。

「Windows」(画面に表示される) は、プロセスと高度に結合されています。つまり、GUI を表示する各プロセスには、ウィンドウの作成と管理に関連するすべてのメッセージ (「ボタンをクリックした」、「アプリを閉じた」、「画面を再描画した」など) を処理するメッセージ ループがあることが期待されます。 ' 等々。

このため、メッセージ ループがある場合は、プロセスの存続期間中は利用できる必要があると多かれ少なかれ想定されています。たとえば、ウィンドウが「終了」メッセージを送信する場合があります。画面に何も表示されていなくても、それを処理するためにメッセージ ループを使用できるようにする必要があります。

あなたの最善の策は、次のようにすることです:

あなたの「メインアプリ」である、決して表示されない偽のフォームを作成します Application.Run を呼び出し、この偽のフォームを渡します。別のスレッドで作業を行い、Gui の処理が必要な場合はメイン スレッドでイベントを発生させます。

于 2008-08-05T23:22:00.743 に答える
0

これが正しいかどうかはわかりませんが、フォームを新しくして newForm.Show() を呼び出すだけで、コンソール アプリケーションからウィンドウ フォームを実行したことを覚えています。フォームはブロックされるべきではありません。

もちろん、コンポーネントは、作成したフォームへの参照を維持する責任があります。

于 2009-05-23T21:57:11.120 に答える