連載:Windowsフォーム開発入門【Visual Studio 2010対応】

Windowsフォーム間連携の基礎

初音 玲
2010/12/07
Page1 Page2

 Windowsフォーム・アプリケーションを作成するときに、単一のフォームですべての機能が実装できるとは限らない。使いやすいデザインを目指した結果、メイン・フォームのほかに、設定フォームなどのサブフォームが必要になる場合も多いだろう。

 複数のフォームを使った場合、フォーム間のデザイン上の関連性の考慮も必要だし、フォーム間でどのように情報を共有するかの考慮も必要だ。

デザインの考慮点

 複数フォーム・デザイン上の考慮点は「Windows ユーザー エクスペリエンス ガイドライン」の「ガイドライン」−「ウィンドウ」−「ウィンドウの管理」に記述がある。複数フォームを使うときにポイントになる内容を、何点かピックアップしてみよう。

ウィンドウの初期表示位置

 Windowsフォームの初期表示位置は、一般的に、スクリーンの左上を起点としてだんだんと右下にずらしていく。マルチディスプレイの場合は、使用中のアプリケーション(=アクティブ・アプリケーション)の初期表示位置はアクティブ・スクリーンに、それ以外のアプリケーションはそれぞれが位置するディスプレイに表示するのが一般的だ。

図1 ウィンドウの初期表示位置

 .NETでFormクラス(System.Windows.Forms名前空間)のShowメソッドを使ってWindowsフォームを表示する場合、StartPositionプロパティを「WindowsDefaultLocaltion」にしておけば、図1のようにウィンドウの初期表示位置を左上から右下にずらしながら表示してくれる。

補助ウィンドウの初期表示位置

 設定用のフォームなど、現在のフォームに関連した補助画面(子フォーム)を表示するときには、親フォームの中央に表示する。

 このガイドラインを守るためには、呼び出し元のフォーム(=親フォーム)でShowメソッドやShowDialogメソッド使うときに、それらのメソッドのパラメータに自フォームを指定する。これによって、親子関係を明確にする。また、呼び出される子フォームのStartPositionプロパティには、「CenterParent」を指定する。

ウィンドウのZ順序(Z-order)

 ガイドラインによれば、「親フォームよりも前面に子フォームを表示する」とある。FormクラスのShowメソッドやShowDialogメソッドを使えば、親フォームよりも前面に子フォームが表示される。

Windowsフォーム表示の基本

 Windowsフォームの表示方法には「モーダル表示」と「モードレス表示」がある。モーダル表示は、表示したフォームを閉じるまでは表示元の処理は進まないUI(ユーザー・インターフェイス)となる。一方、モードレス表示は、表示元の処理も進むため、1つのアプリの中で複数のフォームを並行して使用するようなUIとなる。

モーダル表示

 Windowsフォームをモーダル表示するには、New演算子を使って、表示したいフォームのクラス(下記のコードでは「Sub_Form」)からオブジェクトを生成して、そのShowDialogメソッドを実行する。

Private Sub ShowDialog_Button_Click(ByVal sender As Object, _
                                    ByVal e As EventArgs) _
                Handles ShowDialog_Button.Click
  Using _form As New Sub_Form
    _form.ShowDialog(Me)
  End Using
End Sub
private void ShowDialog_Button_Click(object sender, EventArgs e)
{
  using (Sub_Form _form = new Sub_Form())
  {
    _form.ShowDialog(this);
  }
}
リスト1 モーダル表示するコード例(上:VB、下:C#)

 モーダル表示は、現在使用しているフォームに必要な副次的な情報を入力したり、操作に伴う処理内容を確認してから処理を継続したいときの確認メッセージを表示したりするときに使用する。

 ShowDialogメソッドを実行すれば子フォームに制御が移り、閉じればShowDialogメソッドの次の行に制御が戻ってくる。サブルーチン的な動きになるため、プログラムの動きも理解しやすい。

モードレス表示

 Windowsフォームをモードレス表示するには、表示したいフォームのクラスからオブジェクトを生成して、そのShowメソッドを実行する。これは、先ほどのShowDialogメソッドの実行と同じ手順である。

 ただし、リスト2に示すように、リスト1のShowDialogメソッドをShowメソッドに変えただけでは、Showメソッドでフォームを表示した直後にUsingブロックが終了しているので、_form変数に設定したフォーム・オブジェクトが破棄され、表示したフォームが自動的に終了してしまう。

Private Sub Show_Button_Click(ByVal sender As Object, _
                              ByVal e As EventArgs) _
                Handles Show_Button.Click
  Using _form As New Sub_Form
    _form.Show(Me)
  End Using
End Sub
private void Show_Button_Click(object sender, EventArgs e)
{
  using (Sub_Form _form = new Sub_Form())
  {
    _form.Show(this);
  }
}
リスト2 モードレス表示の失敗コード例(上:VB、下:C#)

 このような事態を回避するためには、リスト3のように、フォーム・オブジェクト変数を工夫する。なお、Showメソッドで表示したフォームを閉じるには、そのフォーム・オブジェクトのCloseメソッドを呼び出せばよい。

Public Class Main_Form

  Private SubFormList As New List(Of Sub_Form)

  Private Sub ShowList_Button_Click(ByVal sender As Object, _
                                    ByVal e As EventArgs) _
                  Handles ShowList_Button.Click
    Dim _form As New Sub_Form
    _form.Show(Me)
    SubFormList.Add(_form)
  End Sub

  Private Sub Main_Form_FormClosing(ByVal sender As Object, _
                                ByVal e As FormClosingEventArgs) _
                  Handles Me.FormClosing
    For Each _form As Sub_Form In SubFormList
      _form.Close()
      _form = Nothing
    Next
  End Sub
End Class
namespace WindowsMultiFormCs
{
  public partial class Main_Form : Form
  {
    private List<Sub_Form> SubFormList = new List<Sub_Form>() ;

    public Main_Form()
    {
      InitializeComponent();
    }

    private void ShowList_button_Click(object sender, EventArgs e)
    {
      Sub_Form _form = new Sub_Form();
      _form.Show(this);
      SubFormList.Add(_form);
    }

    private void Me_FormClosing(object sender, FormClosingEventArgs e)
    {
      foreach (Sub_Form _form in SubFormList)
      {
        _form.Close();
        _form.Dispose();
      }
    }
  }
}
リスト3 モードレス表示するコード例(上:VB、下:C#)

 リスト3の特徴は、モードレス表示したフォーム・オブジェクトをListジェネリック・クラス(「SubFormList」変数)で管理しているところだ。

 もし、リスト4で示すように、Listジェネリック・クラスでフォーム・オブジェクトを管理せず、オブジェクト変数で管理したらどうなるだろうか。

Public Class Main_Form

  Private SubForm As Sub_Form
  Private Sub Dangling_Button_Click(ByVal sender As Object, _
                                    ByVal e As EventArgs) _
                  Handles Dangling_Button.Click
    SubForm = New Sub_Form
    SubForm.Show()
  End Sub

  ……省略……
End Class
namespace WindowsMultiFormCs
{
  public partial class Main_Form : Form
  {
    private Sub_Form SubForm;

    ……省略……

    private void Dangling_Button_Click(object sender, EventArgs e)
    {
      SubForm = new Sub_Form();
      SubForm.Show(this);
    }

    ……省略……
  }
}
リスト4 ダングリング・ポインタが発生する問題コード(上:VB、下:C#)

 Dangling_Button_Clickメソッドが実行されると、SubForm変数にSub_Formクラスのオブジェクトが設定され、そのShowメソッドによりモードレス表示される。

 再度、Dangling_Button_Clickメソッドが実行されると、SubForm変数が新しいオブジェクトへ書き換えられて、2つ目のフォームがモードレス表示される。もちろん、この状態でSubFormオブジェクトのCloseメソッドを実行しても、2つ目のフォームしか閉じることができない。

 このとき1つ目に表示したフォームのオブジェクト変数値はどこに行ってしまうのだろうか。SubForm変数が書き換えられたとしても1つ目のフォームが閉じたりはしないので、メモリ上のどこかにオブジェクトは存在しているが、そのオブジェクトに対して親フォームからの操作手段はなくなっている。このような中ぶらりんの状態を「ダンブリング」といい、品質上問題がある状態の1つだと考えられている。

 以上がWindowsフォームの基本的な表示方法だ。次のページでは、親フォームと子フォームの間で、値を受け渡す方法について説明する。


 INDEX
  [連載]Windowsフォーム開発入門【Visual Studio 2010対応】
  Windowsフォーム間連携の基礎
  1.Windowsフォーム表示の基本
    2.子フォームに値を渡す方法/子フォームから値を取得する方法/親フォームに値を設定する方法

インデックス・ページヘ  「Windowsフォーム開発入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH