ウインドウに親子関係を持たせる

ひとつのウインドウだけで所望の処理が完了できるソフトウェアはそうそうありません。ソフトの主要操作は親ウインドウで実施して、パラメータ設定などは子ウインドウで実施するというのが理想でしょう。

本記事では、親ウインドウから子ウインドウを管理するときのベストプラクティスを紹介します。

ここでは、子ウインドウを FormSub クラスとして Form10, Form20, Form30 を複数生成して親ウインドウから管理します。本記事の最後にまとめのコードを示します。サンプルソースも用意しました。

子ウインドウのオーナを指定する

子ウインドウのオーナーを指定しない場合、親ウインドウを最小化しても子ウインドウは表示されたままです。親ウインドウが最小化したら、それに応じて子ウインドウも最小化するのが自然な動作だと思います。

public partial class Form1 : Form
{

	// 子ウインドウ.
	FormSub Form10;
	FormSub Form20;
	FormSub Form30;

	public Form1()
	{

		InitializeComponent();

		// 子ウインドウを作成する.
		Form10 = new FormSub( "10", Color.Blue ); 
		Form20 = new FormSub( "20", Color.Green ); 
		Form30 = new FormSub( "30", Color.Red ); 

		// 子ウインドウのオーナを自分自身にする.
		Form10.Owner = this;
		Form20.Owner = this;
		Form30.Owner = this;

	}

	private void Form1_Load( object sender, EventArgs e )
	{

	}

	private void button1_Click( object sender, EventArgs e )
	{

		// 子ウインドウを表示する.
		Form10.Visible = true;
		Form20.Visible = true;
		Form30.Visible = true;

	}
}

Owner プロパティを設定すれば、オーナーである親ウインドウが最小化すると同時に子ウインドウも最小化します。また、オーナーを設定すれば、親ウインドウが最背面になり、その前面に子ウインドウが配置されるようになります。

子ウインドウをタスクバーに表示しない

デフォルトの動作では、複数のウインドウを作成すると、それぞれすべてがタスクバーに表示されてしまいます。私の考えでは、親ウインドウに管理された子ウインドウをタスクバーに表示する必要はないと思います。子ウインドウのタスクバー表示をさせないように ShowInTaskBar プロパティを false にします。

public FormSub( String caption, Color background_color )
{
	InitializeComponent();

	// タスクバーに表示しない.
	this.ShowInTaskbar = false;
}

子ウインドウを破棄するのではなく隠す

通常はウインドウ右上に「閉じる」ボタンがあるのが普通です。ユーザ操作により閉じるボタンがクリックされるとウインドウは破棄されてしまいます。ウインドウが破棄されてしまいますと、次回のウインドウ表示は再びウインドウを生成しなくてはなりません。これは管理上とても面倒です。

そこで、閉じるボタンが押されても破棄するのではなく、隠すという動作に変更します。子ウインドウの Closing() イベントにおいて、閉じられた理由をチェックして動作を決定します。

private void FormSub_FormClosing( object sender, FormClosingEventArgs e )
{

	// 閉じようとされた要因を調べる.
	if ( e.CloseReason == CloseReason.UserClosing )
	{

		// 閉じる動作を中断する.
		e.Cancel = true;

		// 閉じるのではなくて隠す.
		this.Visible = false;

	}

}

子ウインドウから親ウインドウにアクセスする

子ウインドウを隠したときに、親ウインドウにフォーカスが戻るとソフトウェアの動作として親切だと思います。

this.Owner を使って下記のコードのように、自分の親ウインドウのメソッドをコールしたり、プロパティにアクセスしたりできます。

private void FormSub_FormClosing( object sender, FormClosingEventArgs e )
{

	// 閉じようとされた要因を調べる.
	if ( e.CloseReason == CloseReason.UserClosing )
	{

		// 閉じる動作を中断する.
		e.Cancel = true;

		// 閉じるのではなくて隠す.
		this.Visible = false;

		// オーナーにフォーカスをあてる.
		this.Owner.Focus();

		// 隠された時間をオーナーのタイトルバーに表示する.
		this.Owner.Text = DateTime.Now.ToString( "HH:mm:ss" );

	}

}

子ウインドウの最大化を抑止する

子ウインドウを最小化することはあっても、最大化するというシチュエーションは想像できません。子ウインドウがスクリーン上で最大化して親ウインドウを覆ってしまうと、意味がわからなくなるからです。Windows ではタイトルバーをダブルクリックすると最大化ボタンがないウインドウでも最大化することが可能です。これを簡単に抑止するには MaxmizeBox プロパティを false にします。このプロパティは最大化ボタンが表示されていなくても効き目があります。

public FormSub( String caption, Color background_color )
{
	InitializeComponent();

	// タイトルバーをダブルクリックしたときに最大化しない.
	this.MaximizeBox = false;
}

まとめのコード

以下に、本記事のまとめのコードを示します。まずはメインのフォームのコード Form1.cs です。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace abc
{
	public partial class Form1 : Form
	{

		// 子ウインドウ.
		FormSub Form10;
		FormSub Form20;
		FormSub Form30;

		public Form1()
		{

			InitializeComponent();

			// 子ウインドウを作成する.
			Form10 = new FormSub( "10", Color.Blue ); 
			Form20 = new FormSub( "20", Color.Green ); 
			Form30 = new FormSub( "30", Color.Red ); 

			// 子ウインドウのオーナを自分自身にする.
			Form10.Owner = this;
			Form20.Owner = this;
			Form30.Owner = this;

		}

		private void Form1_Load( object sender, EventArgs e )
		{

		}

		private void button1_Click( object sender, EventArgs e )
		{

			// 子ウインドウを表示する.
			Form10.Visible = true;
			Form20.Visible = true;
			Form30.Visible = true;

		}
	}
}

つぎに、子ウインドウのコードを示します。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace abc
{
	public partial class FormSub : Form
	{
		public FormSub( String caption, Color background_color )
		{

			InitializeComponent();

			// キャプションをコンストラクタ引数に従って変更する.
			this.Text = caption;

			// ウインドウ色をコンストラクタ引数に従って変更する.
			this.BackColor = background_color;

			// ウインドウの外観を固定サイズツールウインドウにする.
			this.FormBorderStyle = FormBorderStyle.FixedToolWindow;

			// タイトルバーをダブルクリックしたときに最大化しない.
			this.MaximizeBox = false;

			// タスクバーに表示しない.
			this.ShowInTaskbar = false;

		}

		private void FormSub_Load( object sender, EventArgs e )
		{

		}

		private void FormSub_FormClosing( object sender, FormClosingEventArgs e )
		{

			// 閉じようとされた要因を調べる.
			if ( e.CloseReason == CloseReason.UserClosing )
			{

				// 閉じる動作を中断する.
				e.Cancel = true;

				// 閉じるのではなくて隠す.
				this.Visible = false;

				// オーナーにフォーカスをあてる.
				this.Owner.Focus();

				// 隠された時間をオーナーのタイトルバーに表示する.
				this.Owner.Text = DateTime.Now.ToString( "HH:mm:ss" );

			}

		}
	}
}

上記のコードと全く同じサンプルソースを用意しました、よろしければご利用ください。