Roy Osherove

View Original

Winform Singleton pattern example

Stefano describes how he implements the Singleton design pattern for a form object in a winform application.

I disagree. The main points of a Singleton:

  • No new instances of the Singleton class can be created
  • There should be one existing instance for use which cannot be destroyed

To do this in a winform the steps should be:

  • Make the constructor private (so that no one create a new instance)
  • Add a private shared _instance variable of type Form1
  • Add a public shared and readonly property that exposes the variable, called "Instance"
  • Use this property to run the application

Here's an example(VB.NET):

Public Class Form1

    Inherits System.Windows.Forms.Form

    Private Shared _instance As New Form1

 

    Public Shared ReadOnly Property Instance() As Form1

        Get

            Return _instance

        End Get

    End Property

 

   

    Private Sub New()

        MyBase.New()

        'This call is required by the Windows Form Designer.

        InitializeComponent()

 

        'Add any initialization after the InitializeComponent() call

    End Sub

End Class

 

 Module Module1

 

    Public Sub Main ()

        Application.Run(Form1.Instance)

    End Sub

 

End Module

 

Update

Stuart adds a very important comment which I did not think of (That's what happens when you talk about stuff you never actually had to implement before I guess):

Forms are a slightly more complex animal than other classes in that a form instance can be destroyed at will by the end user.  When a form is closed, its controls and its base class are disposed.  This is not desired behavior in a singleton class because once an object has been disposed, it can no longer be accessed (or, in the case of a form, displayed).  To see this undesired behavior in action, simply attempt to launch Roy's singleton form twice in succession and observe the System.ObjectDisposedException that gets thrown.

Solving this problem is easy, though.  Simply override OnClosing(), cancel the close, and hide the form instead.

   Protected Overrides Sub OnClosing(ByVal e As System.ComponentModel.CancelEventArgs)
      e.Cancel = True
      Me.Hide()
   End Sub

Now when the user closes the form, the form merely hides instead of disposing and everything works as expected (until you start trying to use singleton forms as MDI children, but that's the subject of a different post).