5

C#.NETでのフォームのモダリティに問題があります。メインフォーム#0があるとしましょう(下の画像を参照)。このフォームは、ユーザーがさまざまな操作を実行できるメインのアプリケーションフォームを表します。ただし、タスクをサポートする追加のメインアプリケーション機能を実行するために、追加の非モーダルフォームを開く必要がある場合があります。これが画像のフォーム#1であるとしましょう。この#1フォームでは、いくつかの追加のモーダルフォームが互いに重なり合って開かれる可能性があり(画像の#2フォーム)、最後に、長い操作の進行状況とステータスを示す進行状況ダイアログが表示されます。数分から数時間。問題は、すべてのモーダルフォーム(画像の#2)を閉じるまで、メインフォーム#0が応答しないことです。この状況では、メインフォーム#0が機能する必要があります。でも、フォーム#2で非モーダルフォームを開くと、モーダル#2フォームと新しく作成された非モーダルフォームの両方で操作できます。メインフォーム#0とフォーム#1とそのすべての子フォームの間で同じ動作が必要です。出来ますか?それとも私は何か間違ったことをしていますか?何らかの回避策があるかもしれませんが、ShowDialogのすべての呼び出しをShowに変更したくありません...

画像http://img225.imageshack.us/img225/1075/modalnonmodalproblem.png

4

5 に答える 5

12

モーダルフォームは、「モーダル」の意味を正確に実行し、アプリ内の他のすべてのウィンドウを無効にします。それはかなり重要です、あなたのプログラムはやや危険な状態にあります。ダイアログが閉じるのを待っているコードのチャンクがあります。これらの他のウィンドウが無効にされていない場合、本当に悪いことが起こる可能性があります。ユーザーがモーダルダイアログを再開できるように、コードは2回ネストされます。または、ダイアログの所有者ウィンドウを閉じることもできますが、突然消えます。

これらは、ループ内でApplication.DoEvents()を呼び出した場合に発生する問題の正確な種類です。これは、他のウィンドウを無効にせずにフォームをモーダルに動作させる1つの方法です。例えば:

    Form2 mDialog;

    private void button1_Click(object sender, EventArgs e) {
        mDialog = new Form2();
        mDialog.FormClosed += (o, ea) => mDialog = null;
        mDialog.Show(this);
        while (mDialog != null) Application.DoEvents();
    }

これは危険です。

トラブルを避けるために設計された方法でモーダルフォームを使用するのが確かに最善です。モーダルフォームが必要ない場合は、モーダルにしないでください。Show()メソッドを使用してください。FormClosingイベントをサブスクライブして、終了間近であることを確認します。

    private void button1_Click(object sender, EventArgs e) {
        var frm = new Form2();
        frm.FormClosing += new FormClosingEventHandler(frm_FormClosing);
        frm.Show();
    }

    void frm_FormClosing(object sender, FormClosingEventArgs e) {
        var frm = sender as Form2;
        // Do something with <frm>
        //...
    }
于 2010-05-14T17:26:01.433 に答える
3

最初に頭に浮かぶのは、このようなものです。フォーム2を起動するときにフォーム1を無効にしてから、フォーム1に2番目のフォームのクローズイベントを処理させて、フォーム1を再度有効にすることができます。表示ダイアログを使用してモーダル2を開くことはありません。

ここで、ユーザーの観点からすると、これは非常に面倒になることを覚えておいてください。MDIアプリケーションを実行して、すべてのウィンドウを1つのコンテナー内に収めることを検討するかもしれません。

于 2010-05-14T14:26:19.890 に答える
0

同じプロセススペースにあるモーダルダイアログが閉じられるまで、メインフォームは応答しません。そのための回避策はありません。

于 2010-05-14T14:28:52.867 に答える
0

Form# 0IsMdiContainerプロパティをtrueに設定するMDIアプリケーションを使用できるように見えます。

次に、同様のことを行うことができます。

public partial class Form0 {
    public Form0 {
        InitializeComponent();
        this.IsMdiContainer = true; // This will allow the Form #0 to be responsive while other forms are opened.
    }

    private void button1_Click(object sender, EventArgs e) {
        Form1 newForm1 = new Form1();
        newForm1.Parent = this;
        newForm1.Show();
    }
}

質問で述べたようにShowDialog()を使用すると、すべてのフォームがModal=trueになります。

定義上、モーダル形式は次のとおりです。

フォームがモーダルで表示される場合、モーダルフォーム上のオブジェクトを除いて、入力(キーボードまたはマウスクリック)は発生しません。プログラムは、別のフォームへの入力が発生する前に、モーダルフォームを非表示または閉じる必要があります(通常はユーザーの操作に応じて)。モーダルで表示されるフォームは、通常、アプリケーションのダイアログボックスとして使用されます。

このプロパティ[(Modal)]を使用して、メソッドまたはプロパティから取得したフォームがモーダルに表示されているかどうかを判断できます。

したがって、モーダルフォームは、ユーザーからの即時の支援/対話が必要な場合にのみ使用されます。そうでなければ、モーダルフォームを使用すると、おそらく間違った方向に向かっていると思われます。

メインフォームをMDIコンテナにしたくない場合は、マルチスレッドを使用することが、単純なBackgroundWorkerクラスを介した1つのソリューションであり、達成したいことの鍵となります。したがって、私にはデザインの匂いのように見えます...

  • メインフォームをレスポンシブにするなど、何をしたいのか。
  • あなたは何をしなければなりませんか?

あなたがしなければならないことを説明することで、私たちはあなたを完全に正しい方向、または少なくともおそらくより良い方向に導くことができるかもしれません。

于 2010-05-14T17:47:09.330 に答える
-2

実際、答えは非常に簡単です。試す

newForm.showDialog();

これにより、新しいフォームが開きますが、親のフォームにはアクセスできません。

于 2012-08-05T16:27:44.523 に答える