DOBON.NET DOBON.NETプログラミング掲示板過去ログ

【MDI】特定の操作後にアプリが終了できないという悩み

環境/言語:[OS : Windows Vista sp2 / 言語 : C# / .NET Framework : 2.0]
分類:[.NET]

2010/01/05(Tue) 23:59:56 編集(投稿者)
2010/01/05(Tue) 23:58:11 編集(投稿者)

【解決したい問題】
MDIアプリケーションが×(またはAlt+F4)を押しても終了しないことがあり
とても悩んでいます。
開発環境:vs2005 sp1
開発言語:c#

このお正月に、お勉強を兼ねて何かチャレンジしよう!と決めて、
---------------------------------------------------
「MDIアプリケーションを作成する」
http://dobon.net/vb/dotnet/form/mdiapplication.html
---------------------------------------------------
ここに紹介されている内容がとても分かりやすいので、
まずは見よう見まねで、MDIアプリを作ってみました。
 ↓
ビルドしたあとで、いろいろと動かしていると、
あれ?終了できなくなっちゃった・・・。
なんでだろう・・・。と、いろいろ調べてみました。
 ↓
ある操作をしたときだけ、なぜか、×(またはAlt+F4)を押しても
アプリケーションが終了できなくなってしまうことが分かり、
原因の特定と解決もできず悩みこんでしまいました。
過去に、同じような内容で投稿がないのかを
過去ログキーワード検索したのですが、見つけられず
ここに新規スレッドを作ってみました。
ある操作は、下記の手順のときに確実に起きてしまうようです。
(手順2と手順3が入れ替わると起きないようです)
どなたか、アドバイスをいただけるととても嬉しいです。

【特定の操作(最短手順)】
1.子フォームを新規作成(連続して2個作成)する
  親フォームの上部にMenuStripコントロールを配置して、
  「ファイル(&F)」→「新規作成(&N)」のメニューを用意し、
  新規作成クリックで子フォーム作成するようにしてます。
  --------------------------------
  ChildForm frm = new ChildForm();
  frm.MdiParent = this;
  frm.Show();
  --------------------------------
2.2個目に開いた子フォームを「_」アイコンを押して最小化する
3.1個目に開いた子フォームを「_」アイコンを押して最小化する
4.すべて閉じる
  親フォームの上部に配置済みのMenuStripコントロールで、
  「ウィンドウ(&W)」→「すべて閉じる(&X)」のメニューを用意し、
  すべて閉じるクリックで子フォームすべて閉じるようにしてます。
  --------------------------------
  foreach (ChildForm frm in this.MdiChildren)
  {
    frm.Close();
  }
  --------------------------------
5.親フォーム「×」アイコンを押して終了(したいけど、終了できない)
  ※タスクマネージャーでプロセスを強制終了しました。

なにとぞ、よろしくお願いします。
先に表示した MDI 子フォームが最小化されているときに、後に表示した MDI 子フォームを閉じるとそういう状態になるみたいですね。
子フォーム二つ表示>一つ目を最小化>二つ目を閉じる、だけで再現できました。

この状態で MDI 親フォームを閉じようとすると、MDI 親フォームの FormClosing イベントの引数 FormClosingEventArgs の Cancel プロパティの初期値が true に設定されるため、そのままだと閉じなくなるようです。
なので、FormClosing イベントで e.Cancel を明示的に false にしてやれば閉じるようになります。

なぜそうなるのか、またそういう状態にしない方法については私には分かりません。
■No26182に返信(Hongliangさんの記事)

Hongliangさま、レスありがとうございました。

> 子フォーム二つ表示>一つ目を最小化>二つ目を閉じる、だけで再現できました。
→ぅわっ!ほんとだ。
 もっと簡単に再現可能だったのですね。A(^-^;

> この状態で MDI 親フォームを閉じようとすると、MDI 親フォームの FormClosing イベントの引数 FormClosingEventArgs の Cancel プロパティの初期値が true に設定されるため、そのままだと閉じなくなるようです。
> なので、FormClosing イベントで e.Cancel を明示的に false にしてやれば閉じるようになります。
→e.Cancelがポイントだったのですね。
 ここにはまったく気がついていませんでした。
 早速、明示的に false にしたら閉じられるようになりました。
 ありがとうございます。

> なぜそうなるのか、またそういう状態にしない方法については私には分かりません。
→確かに、なぜなんだろう。。。
 きっと理由があってこういう動作に意図的にしているのかな?
 無事に閉じれたので、解決にマークします。
 ありがとうございました。
解決済み!
■No26183に返信(ayami0429さんの記事)
>>なぜそうなるのか、またそういう状態にしない方法については私には分かりません。
> →確かに、なぜなんだろう。。。
>  きっと理由があってこういう動作に意図的にしているのかな?

もしかしたら、リリース時期の都合上修正されなかったのかも。

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=425531
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=245135

.NET Framework 4 ではどうなのだろう?

https://connect.microsoft.com/VisualStudioJapan/feedback/CreateFeedback.aspx
解決済み!
なお、Validation 機構による問題のようなので、FormClosing で e.Cancel を false にした場合、親フォームや子フォーム内の Validating イベントによって閉じられないはずでも問答無用で閉じてしまいます。
■No26184に返信(魔界の仮面弁士さんの記事)

魔界の仮面弁士さま、いつも返信ありがとうございます。v(^-^)v

> もしかしたら、リリース時期の都合上修正されなかったのかも。
>
> https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=425531
> https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=245135
→検索して調べてくれたのですね、ありがとうございます。m(_ _)m
 お恥ずかしいことに私は英語がよく分からなくて、単語を調べながら苦戦してました。A(^-^;)


> .NET Framework 4 ではどうなのだろう?
> https://connect.microsoft.com/VisualStudioJapan/feedback/CreateFeedback.aspx
→ここで、vs2005 sp1 で投稿してたのですが、実ははじめに vs2010 b2 でこの現象が起きてしまい、
 おや?と思い、vs2005 sp1 で同じように試していました。。。ごめんなさい。
 そのとき、.NET Framework 4 を選んでいたので、私の試し方があっているのであれば、
 同じ現象が起きているといえるのかな?(違っていたらすみません)
解決済み!
2010/01/06(Wed) 22:33:48 編集(投稿者)
2010/01/06(Wed) 22:12:21 編集(投稿者)

■No26185に返信(Hongliangさんの記事)

Hongliangさま、返信ありがとうございます。

> なお、Validation 機構による問題のようなので、FormClosing で e.Cancel を false にした場合、親フォームや子フォーム内の Validating イベントによって閉じられないはずでも問答無用で閉じてしまいます。
→確実に閉じたいときにはこれでOKだけど、条件等で本当は終了させたくないような場合には
 安易に e.Cancel を false にするのは危険ということなのかな?
 もう少し色々試してみます。v(^-^)v
  ↓
 自己レスでごめんなさい。
  ↓
 これがスマートな方法になるかは、ちょっぴり不安なのですが、親フォームの FormClosing で、
 子フォームの編集済みフラグを確認して、終了するか、しないかを分岐すると
 どうやらわたしの思い通りの動作ができましたです。m(_ _)m
 ---------------------------------------------------
 foreach (ChildForm frm in this.MdiChildren)
 {
   bool blnModify = frm.GetModify();
   if (blnModify == true)
   {
     // 終了しない
     e.Cancel = true;
     return;
   }
 }
 // 終了する
 e.Cancel = false;
 ---------------------------------------------------
 みなさま、ありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板