VB.NET (WPF) で作成したアプリケーションを起動してから、そのアプリケーション上に配置したボタンをクリックすると子ウィンドウの「お知らせ」が表示される、という機能をテストしていた(テスト中だったので、下図のお知らせのメッセージが変てこりんなのは無視してほしい)。
ところが、「お知らせ」ウィンドウを閉じてから再び表示させようとすると、下記のようなエラーが出た。
Window が閉じた後で、Visibility の設定や、Show、ShowDialog、および WindowInteropHelper.EnsurerHandle の呼び出しを行うことはできません。
「ん??」変だな。コードをチェックしてみても、おかしなところはないように見える。簡単なコードだ。あらかじめ New してグローバル変数に入れておいた子ウィンドウの「お知らせ」を .ShowDialog() で表示して、.Close() で閉じてるだけ。
しかし、調べてみると、どうやら以前 Forms でやってたこのやり方が通用しないらしい。
どうやら WPF では、.Close() すると New したウィンドウが破棄されるので、再び New でウィンドウの実態を得ない限りは .ShowDialog() ができないらしい。
このエラーを回避するには、親ウィンドウから「お知らせ」ウィンドウを開くときは毎回 New で実態を得るようにして、使用後に毎回 .Close() する。
または、New を1回だけにしたい場合(子ウィンドウの実態をグローバル変数に入れておきたい場合)はコードを次のように修正する。
子ウィンドウの閉じるボタンのコード
Me.Visibility = Visibility.Collapsed
子ウィンドウの Closing イベントのコード
e.Cancel = True Me.Visibility = Visibility.Collapsed
.Collapsed のかわりに .Hidden を使っても OK。
しかし、WPF の場合、これではまだ問題がある。
Forms の場合は、親ウィンドウが閉じれば子ウィンドウも強制的に閉じたのでこれでも良かった。子ウィンドウを明示的に閉じなくても、あるいは子ウィンドウの .Closing イベントに e.Cancel = True と書いてあっても、とにかく親ウィンドウが閉じれば子ウィンドウも閉じた。
しかし WPF では、親ウィンドウが閉じても、子ウィンドウが自動的に閉じないので注意が必要だ。つまり今回の場合、下記のことを忘れてはいけない。
- 親ウィンドウが閉じるときには子ウィンドウも明示的に閉じる
- 親ウィンドウが閉じるときには子ウィンドウの .Closing イベントの e.Cancel = True が実行されないようにする
これを忘れると、親ウィンドウが閉じても子ウィンドウが閉じず、プロセスがバックグラウンドプロセスに残ってしまう。
従って、最終的なコードは下記のようになる。
子ウィンドウの Closing イベントのコード
If gParentAppClosing = False Then e.Cancel = True Me.Visibility = Visibility.Collapsed End If
親ウィンドウの Closing イベントのコード
gParentAppClosing = True oChildWindow.Close
※ gParentAppClosing はグローバル変数(デフォルトは False)。