DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

フォームが一つしか表示されないようにする
VB6と同様にフォームにアクセスできるようにする

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を使用する方法

.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つのフォームにアクセスする場合は、この方法は使えません。

VB.NET
コードを隠すコードを選択
'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のコンストラクタをプライベートに変更すればさらに確実です。具体的なコードは、下の「シングルトンデザインパターンの適用」をご覧ください。
VB.NET
コードを隠すコードを選択
'ただ一つのフォームのインスタンスを保持するフィールド
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
C#
コードを隠すコードを選択
//ただ一つのフォームのインスタンスを保持するフィールド
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枚しか表示されません。

補足:このプロパティはスレッドセーフではありません。スレッドセーフにしたい場合は、下の例を参考にしてください。
VB.NET
コードを隠すコードを選択
'Form2を表示する
Form2.Instance.Show()

'Form2のTextBox1の内容を取得する
'TextBox1は、Publicのように、外部からアクセスできるModifiersである必要がある
MessageBox.Show(Form2.Instance.TextBox1.Text)
C#
コードを隠すコードを選択
//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を使用していませんので、必要であれば付け加えてください。
VB.NET
コードを隠すコードを選択
'基本クラスとして使用できないようにする
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
C#
コードを隠すコードを選択
//基本クラスとして使用できないようにする
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イベントを使用してください。
VB.NET
コードを隠すコードを選択
'フォームを閉じずに隠すようにする
Protected Overrides Sub OnFormClosing(ByVal e As FormClosingEventArgs)
    e.Cancel = True
    Me.Hide()
End Sub
C#
コードを隠すコードを選択
//フォームを閉じずに隠すようにする
protected override void OnFormClosing(FormClosingEventArgs e)
{
    e.Cancel = true;
    this.Hide();
}
  • 履歴:
  • 2007/2/24 My.Formsに関する記述を追加。
  • 2012/3/12 My.Formsの方法は別のスレッドからアクセスする場合は使えない説明を追加。
  • 2015/6/23 「シングルトンデザインパターンの適用」のサンプルで、partialが省略されている注意を追加など。
  • 2016/6/5 使用例を追加。説明の簡略化など。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • .NET Tipsをご利用いただく際は、注意事項をお守りください。