Visual Basic 6.0以前のユーザーの多くは、VB.NETになって、Windowsフォームを表示させる方法の違いに戸惑ってしまうのではないでしょうか。VB6では、デザイナでフォームを作成し、コードで
(フォーム名).Show
とするだけでフォームを表示できました。しかも、同じフォームのShowメソッドを何回呼び出しても、フォームは1枚しか表示されません。
これに対して.NETでは、Newでフォームのインスタンスを作成してからShowメソッドを呼び出す必要があります。また、「NewしてShow」を繰り返すと、その数だけフォームが表示されます。
ここでは、VB6のように、簡単にフォームを扱えるようにするための方法を紹介します。
.NET Framework 2.0以降のVB.NETでは、My.Formsを使用するのが簡単です。
例えば、「Form2」という名前のフォームのインスタンスは、「My.Forms.Form2」というプロパティで取得できます。つまり、Form2を表示させたければ、「My.Forms.Form2.Show()」とします。「My.Forms.Form2.Show()」を何回呼び出しても、Form2は1枚しか表示されません。
また、Form2に配置された"TextBox1"のTextを取得したいのであれば、「My.Forms.Form2.TextBox1.Text」とします。
「My.Forms.Form2」をもっと簡単に、「Form2」とだけすることもできます。「Form2.Show()」でForm2が表示されます。
「My.Forms.Form2 = Nothing」とすることにより、Form2を破棄することができます。Form2が閉じていなければ、閉じられます。
My.Formsでアクセスできるフォームは、同じプロジェクト内にあるフォームだけです。
補足:"Form2"という名前のフォームが複数存在するときは、フォーム名の前に名前空間を付け加える必要があります。
ただしMy.Formsはスレッド毎にフォームのインスタンスを作成しますので、別のスレッドからも1つのフォームにアクセスする場合は、この方法は使えません。
'Form2を表示する My.Forms.Form2.Show() '次のようにしても同じ 'Form2.Show() 'Form2のTextBox1の内容を取得する 'TextBox1は、Publicのように、外部からアクセスできるModifiersである必要がある MessageBox.Show(My.Forms.Form2.TextBox1.Text)
正攻法としては、フォームのインスタンスを静的フィールドに保持しておき、静的プロパティでこのフィールドがnullまたは破棄(Dispose)されているときに新しいインスタンスを作成するという方法が考えられます。
以下に、サンプルを示します。Form2というフォームクラスがあるものとし、このクラスに以下のような_instanceフィールドとInstanceプロパティを加えます。
補足:これに加え、Form2クラスをシールクラスとし、Form2のコンストラクタをプライベートに変更すればさらに確実です。具体的なコードは、下の「シングルトンデザインパターンの適用」をご覧ください。
'ただ一つのフォームのインスタンスを保持するフィールド Private Shared _instance As Form2 'ただ一つのフォームにアクセスするためのプロパティ Public Shared ReadOnly Property Instance() As Form2 Get '_instanceがNothingまたは破棄されているときは、 '新しくインスタンスを作成する If _instance Is Nothing OrElse _instance.IsDisposed Then _instance = New Form2 End If Return _instance End Get End Property
//ただ一つのフォームのインスタンスを保持するフィールド private static Form2 _instance; //ただ一つのフォームにアクセスするためのプロパティ public static Form2 Instance { get { //_instanceがnullまたは破棄されているときは、 //新しくインスタンスを作成する if (_instance == null || _instance.IsDisposed) { _instance = new Form2(); } return _instance; } }
Form2のインスタンスにアクセスするには、Form2.Instance静的メソッドを使用します。例えば、Form2をモードレスで表示するには、「Form2.Instance.Show()」とするだけです(名前空間が異なる場合は、適当な名前空間を付加してください)。「Form2.Instance.Show()」を何回呼び出しても、フォームは1枚しか表示されません。
補足:このプロパティはスレッドセーフではありません。スレッドセーフにしたい場合は、下の例を参考にしてください。
'Form2を表示する Form2.Instance.Show() 'Form2のTextBox1の内容を取得する 'TextBox1は、Publicのように、外部からアクセスできるModifiersである必要がある MessageBox.Show(Form2.Instance.TextBox1.Text)
//Form2を表示する Form2.Instance.Show(); //Form2のTextBox1の内容を取得する //TextBox1は、Publicのように、外部からアクセスできるModifiersである必要がある MessageBox.Show(Form2.Instance.TextBox1.Text);
クラスのインスタンスがただ一つであることを保障するためのデザインパターンとして、シングルトン(Singleton)デザインパターンがあります。シングルトンの実装に関しては、次のページが参考になります。
ここでは、「C# でのシングルトンの実装」の「静的な初期化」で紹介されている方法を使用して、インスタンスが一つであるForm2フォームを作成してみましょう。まずForm2クラスをシールクラスとし、Form2のコンストラクタをプライベートに変更し、以下のような_instanceフィールドとInstanceプロパティを加えます。
注意:.NET Framework 2.0以降で、Visual Studioのフォームデザイナが生成したフォームクラスには、partialキーワードが使用されています。以下のコードではpartialを使用していませんので、必要であれば付け加えてください。
'基本クラスとして使用できないようにする Public NotInheritable Class Form2 Inherits System.Windows.Forms.Form 'コンストラクタをPrivateにする Private Sub New() '(省略) End Sub '(省略) 'フォームのインスタンスを保持するフィールド Private Shared _instance As New Form2 'フォームにアクセスするためのプロパティ Public Shared ReadOnly Property Instance() As Form2 Get Return _instance End Get End Property End Class
//基本クラスとして使用できないようにする public sealed class Form2 : System.Windows.Forms.Form { //コンストラクタをPrivateにする private Form2() { //(省略) } //(省略) //フォームのインスタンスを保持するフィールド private static readonly Form2 _instance = new Form2(); //フォームにアクセスするためのプロパティ public static Form2 Instance { get { return _instance; } } }
しかし、これだけではうまく行きません。フォームを閉じてから再びフォームを開こうとすると、エラーが発生します。なぜなら、破棄されたフォームは開くことができないからです。
この問題を解決するには、一つの方法として、フォームが破棄されないように、フォームが閉じられないようにする方法が考えられます。
例えば、Form2クラスに次のようなコードを書き加えると、Form2を閉じようとても閉じずに、代わりに隠すようにできます。
注意:.NET Framework 1.1以前では、FormクラスのFormClosingイベントの代わりに、Closingイベントを使用してください。
'フォームを閉じずに隠すようにする Protected Overrides Sub OnFormClosing(ByVal e As FormClosingEventArgs) e.Cancel = True Me.Hide() End Sub
//フォームを閉じずに隠すようにする protected override void OnFormClosing(FormClosingEventArgs e) { e.Cancel = true; this.Hide(); }
(この記事は、「.NETプログラミング研究 第42号」で紹介したものです。)
注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。