質問者
Mdi内での多重表示

質問
-
開発環境:Windows XP pro, VS2005
こんばんわ。
Mdi機能を使って開発しております。
Form1を親フォームにしており、子フォームにはForm2とForm3があります。Form1に配置されているメニューバーの form2Menu という項目をクリックすることで、Form1内にForm2を表示するようにしております。
form2Menuのコードとしましては、Form2 form2 = null;
private void form2Menu_Click(object sender, EventArgs e)
{
if ((form2 == null) || form2.IsDisposed)
{
form2 = new form2Form();
form2.MdiParent = this;form2.WindowState = FormWindowState.Maximized;
form2.Show();
}form2Menu.Checked = true;
}としております。
しかし、現状のコードでは、form2Menuをクリックする毎に新しくFrom1内にForm2が表示されてしまいます。
Form2の多重表示をさせないようにしたいのですが、どうすれよろしいでしょうか?ご教授の方宜しくお願いいたします。
すべての返信
-
以下のような関数を一つ作って判断すれば良いと思いますが、示されたコードで多重に開くのは何か他の理由がありそうですね。
public static bool IsExistMdiChild(string chkFormName, Form mdiParent)
{
bool findflg = false;
foreach (Form form in mdiParent.MdiChildren)
{
if (form.Name == chkFormName)
{
findflg = true;
break;
}
}
return findflg;
}
-
親Formにこんなメソッドを用意して呼んでやったらどうでしょうか?
要するにパラメータname("Form2")のインスタンスの存在確認をしてあったらActiveなかったらCreateInstanceです。
各メソッドの内容についてはHELPでご確認ください。public void ShowChildForm(string name)
{
Type formType = Type.GetType(this.GetType().FullName.Replace(this.Name, "") + name);
if (formType != null)
{
Form form;
foreach (Form childForm in this.MdiChildren)
{
if (childForm.GetType() == formType)
{
form = childForm as Form;
if (form != null)
{
form.Activate();
}
return;
}
}
form = Activator.CreateInstance(formType) as Form;
if (form != null)
{
form.WindowState = FormWindowState.Maximized;
form.MdiParent = this;
form.Show();
}
}
} -
タキさんのコードを新規に作成したプロジェクトで試してみましたが、きちんと動作しているように見えます。Form3 という子フォームもあるそうですが、何か抜けてるコードや再現手順がありませんか?
シャノン さんからの引用
何度も「表示/非表示」を繰り返すのでしたら、その都度 new で再生成するのではなく、Hide で一時的に隠しておくのはどうでしょう。とくに明示的に作成と破棄を繰り返す必要が無ければ、そのほうがパフォーマンス的にお勧めですね。WeakReference クラスを使って管理できますし。
//Form1.cs
WeakReference form2 = new WeakReference(null);
private void testToolStripMenuItem_Click(object sender, EventArgs e)
{
if (form2.IsAlive == false)
{
form2.Target = new Form2();
}
Form2 f = (Form2)form2.Target;
f.MdiParent = this;
f.WindowState = FormWindowState.Maximized;
f.Show();
}
//Form2.cs
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
this.Hide();
}
-
自分でも、新規にプロジェクトを作成して試してみたところ、動作しておりました。
ので、にょりさんが指摘してくださった
>何か抜けているコードや再現手順
を気にして見比べてみたところ、//Form1.cs
private void Form1_Load(object sender, EventArgs e)
{
// 子ウィンドウのインスタンスを生成する
Form2 from2 = new romaForm();
// 子ウィンドウを表示する
form2.MdiParent = this;
from2.WindowState = FormWindowState.Maximized;
from2.Show();
// 子ウィンドウのインスタンスを生成する
Form3 from3 = new romaForm();
// 子ウィンドウを表示する
form3.MdiParent = this;
from3.WindowState = FormWindowState.Maximized;
from3.Show();
}上記のように、起動時にForm2とFrom3を表示する様にしてあります。
そして自分自身勘違いしていたところがわかりまして、
from2Menuをクリックすると、一度だけForm2が表示され、それ以上クリックしてもForm2は表示されませんでした。しかし、Form1_Loadメソッド内のForm2もカウントして、起動時にForm2が表示されていたらform2MenuをクリックしてもForm2を表示しないということがしたいのですが、それができない状況です。
にょり さんからの引用
//Form1.cs
WeakReference form2 = new WeakReference(null);
private void testToolStripMenuItem_Click(object sender, EventArgs e)
{
if (form2.IsAlive == false)
{
form2.Target = new Form2();
}
Form2 f = (Form2)form2.Target;
f.MdiParent = this;
f.WindowState = FormWindowState.Maximized;
f.Show();
}
//Form2.cs
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
this.Hide();
}
また、にょりさんのコードで質問なのですが、
from2MenuをクリックしてFrom2を表示させてから、From2の×(閉じる)をクリックしてから、Form2の最大化ボタンをクリックするとForm2のメニューバーが表示されてしまうのですが、それは私のコードに不備があるからでしょうか?
いろいろと質問してしまい申し訳ございません。 -
タキ さんからの引用
上記のように、起動時にForm2とFrom3を表示する様にしてあります。
そして自分自身勘違いしていたところがわかりまして、
from2Menuをクリックすると、一度だけForm2が表示され、それ以上クリックしてもForm2は表示されませんでした。まだ勘違いがあると思いますので、コードを再度確認することをお勧めします。せっかくご提示いただいたコードですが、動作しません。
エラーを自分なりに補って動かしてみましたが、Form2 の宣言が重複しているといった、単純な原因以外は思い浮かびませんでした。
タキ さんからの引用
from2MenuをクリックしてFrom2を表示させてから、From2の×(閉じる)をクリックしてから、Form2の最大化ボタンをクリックするとForm2のメニューバーが表示されてしまうのですが、それは私のコードに不備があるからでしょうか?Form2 の閉じるボタンをクリックすると Form2 が閉じるので操作を継続できませんが・・・。
-
コードをいろいろと修正していて、テスト過程のを載せてしまいました。
すみませんでした。
//Form1.cs
private void Form1_Load(object sender, EventArgs e)
{
// 子ウィンドウのインスタンスを生成する
Form from2 = new Form2();
// 子ウィンドウを表示する
form2.MdiParent = this;
from2.WindowState = FormWindowState.Maximized;
from2.Show();
// 子ウィンドウのインスタンスを生成する
Form from3 = new Form3();
// 子ウィンドウを表示する
form3.MdiParent = this;
from3.WindowState = FormWindowState.Maximized;
from3.Show();
}動いていたコードは以上のようになっております。
エラーを自分なりに補って動かしてみましたが、Form2 の宣言が重複しているといった、単純な原因以外は思い浮かびませんでした。
Form2を、Form1_Load内で表示するようにしているので、form2Menuをクリックすると一度は新しくForm2が表示されてしまうということでしょうか?
Form2 の閉じるボタンをクリックすると Form2 が閉じるので操作を継続できませんが・・・。
Form2の閉じるボタンをクリックした直後は、Form2は閉じられずに、Form2がフォーカスが当たっていないといった状態になってしまいます・・・。
まだコードの再確認の途中ですので、コードの見直しを続けたいと思います。
-
いわゆるSingletonパターンを使用してみるのはどうでしょうか
具体的には、class Form form2 : Form
{
//フォームデザイナの仕様で引数をとらないパブリックコンストラクタは必須
/// <sammary>
/// [使用禁止]新しいForm2を初期化します。
/// </sammary>
public Form2()
{
initializeComponent();
}
/// <sammary>
/// Form2の唯一のインスタンス
/// </sammary>
private Form2 uniqueForm;
/// <sammary>
/// Form2の唯一のインスタンスを取得します。
/// </sammary>
public Form2 UniqueForm
{
get { return Form2; }
}
/// <sammary>
/// Form2の唯一のインスタンスを初期化します。
/// </sammary>
static Form2()
{
uniqueForm = new Form2();
}
}のようにして、new Form2() の代わりに Form2.UniqueForm を呼び出します。
ただし毎回必要な初期化処理はForm2_Load()内で行うようにする必要があります。