none
サブフォームの終了を検知する方法について RRS feed

  • 質問

  • <開発環境>
    Windows10 Pro(64bit)
    VisualStudio2017
    Framework 4.6

    <参考>
    https://dobon.net/vb/dotnet/form/formwithinform.html

    上記を参考に、MDIではなくメインフォーム内のパネルに、サブフォームを表示するアプリを作成しています
    ■メインフォーム
    ・パネルと画面遷移用ボタンを複数配置
    ■サブフォーム
    ・サブフォームには「閉じる」などのコントロールボックスは非表示
    ・サブフォーム内で完結する処理を実装

    かなり作りこみを進めた後に、サブフォームの終了イベントが実行されないこと気付き困っております
    ※参考サイトのコメント欄にも「Closing,Closed等のイベントは実行されない」との記述があったのですが見落としていました

    今からMDIに切り替えるのはかなりの時間が必要となるため、何らかの終了を検知する代替方法があればと思い投稿させていただきました

    以上、よろしくお願いいたします
    2020年12月3日 1:43

回答

  • 一応実験。子フォームの ControlBox は false にしてあります。
    閉じられた後の破棄タイミングでの通知なので、代替となりえるかは何とも言えませんが。

    public Form2()  // 子フォームのコンストラクタにてイベントを仕込んでおく
    {
        InitializeComponent();
        VisibleChanged += delegate { if (!Visible) { Debug.WriteLine($"Hide, IsDisposed={IsDisposed}"); } };
        Disposed += delegate { Debug.WriteLine($"Disposed, IsDisposed={IsDisposed}"); } };
        FormClosed += delegate { Debug.WriteLine("FormClosed"); };
        FormClosing += delegate { Debug.WriteLine("FormClosing"); };
        Closing += delegate { Debug.WriteLine("Closing"); };
        Closed += delegate { Debug.WriteLine("Closed"); };
    }

    実行結果:

    // 子フォームの Close メソッドで閉じた場合
    Closing
    FormClosing
    Closed
    FormClosed
    Hide, IsDisposed=False
    Disposed, IsDisposed=False
    
    // 親コントロール(Panel あるいは親Form)が閉じられた場合
    Disposed, IsDisposed=False

    • 回答としてマーク onionsword 2020年12月3日 3:21
    2020年12月3日 2:30

すべての返信

  • ※参考サイトのコメント欄にも「Closing,Closed等のイベントは実行されない」との記述があったのですが見落としていました

    そのコメント欄には、「どちらの場合も、WM_DESTROYは飛んできて、Disposedイベントも走ります。」という表記がありました。

    WndProc で検知するか、Disposed イベントで代用することはできませんか?

    当方で動作確認はしていないため保証はできませんが、必要なイベントが Closing/FormClosing イベント(キャンセル可能な事前通知)ではなく、Closed/FormClosed イベント(閉じた後の事後通知)であるのなら、Disposed による破棄通知が代用品となりえるかもしれません。

    2020年12月3日 2:04
  • その要件で「検知」する必要がありそうには見えないのですが…。

    とりあえず私が.NET Framework 4.8で試した限り(手元のPCには4.8が入っているので4.6向けにビルドしようが動くのは4.8です)、以下のようになっていますね。

    • サブフォームをClose()すればFormClosing/FormClosedは発生する。
    • 親フォームがClose()したときはサブフォームのFormClosing/FormClosedは発生しない。ただしDisposedは発生する。
    • 親フォームのFormClosedイベントでサブフォームをClose()すればサブフォームのFormClosing/FormClosedが発生する。

    いかがでしょうか?

    // ControlBox = falseならそれこそUserControlで十分に見えます。

    2020年12月3日 2:04
  • その要件で「検知」する必要がありそうには見えないのですが…。

    ご回答ありがとうございます

    サブフォーム内でタイマーを利用している画面があり、その画面に遷移するたびにタイマイベントが増えていることで、本現象が発覚しました
    タイマを止める(タイマイベントを解放)ためにはサブフォームの終了検知が必要になるものと考えています

    2020年12月3日 2:27
  • 一応実験。子フォームの ControlBox は false にしてあります。
    閉じられた後の破棄タイミングでの通知なので、代替となりえるかは何とも言えませんが。

    public Form2()  // 子フォームのコンストラクタにてイベントを仕込んでおく
    {
        InitializeComponent();
        VisibleChanged += delegate { if (!Visible) { Debug.WriteLine($"Hide, IsDisposed={IsDisposed}"); } };
        Disposed += delegate { Debug.WriteLine($"Disposed, IsDisposed={IsDisposed}"); } };
        FormClosed += delegate { Debug.WriteLine("FormClosed"); };
        FormClosing += delegate { Debug.WriteLine("FormClosing"); };
        Closing += delegate { Debug.WriteLine("Closing"); };
        Closed += delegate { Debug.WriteLine("Closed"); };
    }

    実行結果:

    // 子フォームの Close メソッドで閉じた場合
    Closing
    FormClosing
    Closed
    FormClosed
    Hide, IsDisposed=False
    Disposed, IsDisposed=False
    
    // 親コントロール(Panel あるいは親Form)が閉じられた場合
    Disposed, IsDisposed=False

    • 回答としてマーク onionsword 2020年12月3日 3:21
    2020年12月3日 2:30
  • 終了時にタイマー処理も含めた何らかのリソースを開放したいなら、Close系のイベントではなくDispose メソッド内で解放したらいかがでしょうか?


    本フォーラムは、ユーザー(開発者)同士で情報交換を行うためのコミュニティです。初めて利用される方は フォーラムでご質問頂くにあたっての注意点 をご覧ください。

    2020年12月3日 2:40
  • 開発言語に記述を忘れておりました、申し訳ありません

    当方VB.netにて開発しております

    返信いただいた内容からサブフォームのVisibleChangedイベントが発生することが分かったので、

    自身のVisble=False時にCloseすれば、サブフォームの終了処理を実行できることが確認できました

    もう少し他への検証が必要ですが、一旦この方向で考えようと思います

    ご協力ありがとうございました

        Private Sub SubForm_VisibleChanged(sender As Object, e As EventArgs) Handles Me.VisibleChanged
            If Me.Visible = False Then
                Me.Close()
            End If
        End Sub
    
    Private Sub SubForm_Closed(sender As Object, e As EventArgs) Handles Me.Closed
      ※サブフォーム終了時の解放処理など
     End Sub
    
    
    

    • 回答としてマーク onionsword 2020年12月3日 3:21
    • 回答としてマークされていない onionsword 2020年12月3日 3:22
    2020年12月3日 3:21