Click here to Skip to main content
Click here to Skip to main content

Simple Singleton Forms

By , 15 Sep 2003
 

Introduction

When I started with VB.NET a few years ago, one of the things I missed was how to deal with forms where you only want one instance open at the same time. I read a lot of articles concerning Singleton forms etc, which was all complicated and the result was not easy to use. At the end I found a very simple way to do this. Maybe too easy !

Solution

The trick is realy very simple. I just make a class with Public Shared variables with as type the Forms itself.

Public Class clsGlobals
#Region "Singleton Forms"
    Public Shared frmStockSelection As frmStockSelection
    Public Shared frmSettings As frmSettings
#End Region
End Class

These public shared variables will be usable eveywhere in your code. You do not create a new instance from this class. Call the variable by using the class name as shown in the next bit of code.

The code to open the Singleton Form is also very simple. The only thing to do is to check if the variable is not nothing, if not create a new instance. You have to use Focus to get your form to the foreground in case an instance was already existing but maybe hidden behind other windows.

If clsGlobals.frmSettings Is Nothing Then
    clsGlobals.frmSettings = New frmSettings
End If
clsGlobals.frmSettings.Show()
clsGlobals.frmSettings.Focus()

One more thing we have to do to make this work, the variable must be set back to nothing in case we close the form. This we can do in the Dispose sub of the form. After Dispose we can safely set the Form to nothing.

'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing Then
        If Not (components Is Nothing) Then
            components.Dispose()
        End If
    End If
    MyBase.Dispose(disposing)
    clsGlobals.frmSettings = Nothing
End Sub

Another option is to keep the Form open in memory. This is very handy for Forms, like a little calculator for example where you don't want to start with a clear form every time.
The way to do this is to avoid the close the form and hide it. e.Cancel = True will stop the form from closing.

Private Sub frm_Closing(ByVal sender As Object, _
  ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
    Me.Hide()
    e.Cancel = True
End Sub

Maybe the purist readers will not 100% agree with this approach, but for me it works very well. 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Peter Verijke
Founder Computech bvba
Belgium Belgium
Member
I´m a freelance ICT consultant and Technical Project Manager for the last 15 years already.
Before that, I was a Software Developer for the Pharmaceutical and Petrochemical industry.
I developed a very wide knowledge in the ICT world due to my intrest.
This includes Networking (Lan, Wan), Routing Switching Bridging, etc...
Windows environment, which has no secrets for me.
Developing: To many languages to mension here.
Of course, the latest one on the list is dot net.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralAlso check this out (MDI forms)!memberSire40414 Dec '04 - 8:56 
http://www.codeproject.com/csharp/SingletonForms.asp

 
--------------------
No one is perfect.
Welll, there was this guy... but we killed him.

GeneralSingletonsmemberAdam Byrne22 Sep '03 - 23:11 
The simplest way (1 liner) I've found to make a class a singleton in .NET is to provide a public static (shared in VB.NET I think) readonly attribute that is initiated to a new instance of the class. As far as I know, due to the way the CLR works, the class won't be instanciated 'till the first call to this variable.
 
Oh yeah, you also have to make sure that any constructors are private to prevent anyone else from instanciating your class.
 
I've never used VB.NET so forgive any weirdness...
 
Public Class SingletonForm Inherits Form
    ...
   Public Shared ReadOnly Instance = New SingletonForm()
    ...
End Class
 
-adam
GeneralRe: Singletonsmemberashleyb18 Jan '04 - 11:33 
Hi Adam
 
I tried the same in C3 but when I close the client form & try to re-open it, I always get a message 'cannot access a disposed object - nameofform',
which is why I was searching on this subject. The context is in an MDI application: I am applying a singleton pattern to forms that should not have more than one instance open (eg: the login form).
 
Any ideas?
 
Thanks
GeneralRe: SingletonsmemberAdam Byrne19 Jan '04 - 6:31 
Hello Ashley,
 
How's it going? This behaviour is caused by the chain of events that is started when you close a form. Clicking the little "X" in the top-right corner of a window causes the OnClosing event to be fired, and then when the form is closed, it is Dispose()d of. You don't really want this to happen, because since you are only ever going to have one instance of your window class (because it is a singleton), you shouldn't dispose of it until the end of the application's life.
 
A way to do this would be to:
 
  • Create your singleton form by making the constructors private and adding the following static attribute
     
    public static readonly MyFormClassName Instance = new MyFormClassName()
  • Override the OnClosing method of your form like this:
    protected override void OnClosing(CancelEventArgs e)
    {
        e.Cancel = true;
        this.Hide();
    }
     
    so now your form, instead of closing, just hides itself.
  •  
    Now when your application exits, the form should be disposed of automatically, rather than when it is closed. Don't forget that when you show the window again, it will be in the same state as when it was last hidden, i.e. it's not like creating a new instance with clean, fresh, empty controls etc.
     
    I'm sure there's other ways to achieve this, but this is the first one that came to mind. I hope it helps.
     
    -adam
    GeneralRe: Singletonsmemberashleyb19 Jan '04 - 8:18 
    Thanks Adam
     
    I had hidden my forms as a temporary solution, but it doesn't seem very efficient to leave forms open that may not be used again. I thought there might be some cleanup I should be undertaking on the disposal of the form.
    GeneralRe: SingletonsmemberAdam Byrne20 Jan '04 - 0:20 
    Yeah, it's not very efficient at all. Your best bet would probably be to leave the form classes as they are (don't singletonify them) and just keep track of their instanciation.
     
    Hmm... Actually, what you could do is add a static property to the form class that is used to get the single instance of the form. This property would test the IsDisposed attribute of the class. Here's a thread-safe "Singleton" form...
     
    	public class Singleton : System.Windows.Forms.Form
    	{
    		private System.ComponentModel.Container components = null;
     
    		static Singleton instance = null;
    		static readonly object padlock = new object();
     
    		public static Singleton Instance
    		{
    			get
    			{
    				if (instance == null || instance.IsDisposed)
    				{
    					lock (padlock)
    					{
    						if (instance == null || instance.IsDisposed)
    							instance = new Singleton();
    					}
    				}
    				return instance;
    			}
    		}
     
    		private Singleton()
    		{
    			InitializeComponent();
    		}
     
    		protected override void Dispose( bool disposing )
    		{
    			if( disposing )
    			{
    				if(components != null)
    				{
    					components.Dispose();
    				}
    			}
    			base.Dispose( disposing );
    		}
     
    
    		#region Windows Form Designer generated code
     
    		private void InitializeComponent()
    		{
    			this.components = new System.ComponentModel.Container();
    			this.Size = new System.Drawing.Size(300,300);
    			this.Text = "Singleton";
    		}
     
    		#endregion
    	}
    
     
    But, you see, it's not really a Singleton, because if the current instance is disposed, it will be reinstanciated when you access it. If you make sure you refer to the instance only with Singleton.Instance, you'd get away with it. But if you do something like:
     
    Singleton s1 = Singleton.Instance;
    s1.Dispose();
     
    Singleton s2 = Singleton.Instance;
    // now you have two seperate objects on the heap: s1, and s2
    
     
    you have two Singleton objects, which sort of defeats the purpose (even though only more than one instance can exist iff only one of the instances is not disposed and the rest are disposed, so only one useful object exists).
     
    So, with a form like the above, if you refer to the instance only by Singleton.Instance, you should be laughing.
     
    For more information on implementing thread-safe Singleton classes, go to http://www.yoda.arachsys.com/csharp/singleton.html[^]
     
    Hope this helps.
     
    -adam
    GeneralRe: Singletonsmemberashleyb20 Jan '04 - 9:23 
    Thanks for your help, Adam. That's great.: -D
    AnswerRe: Singletonsmembervdewisme6 May '09 - 23:11 
    Hi!
     
    Not sure this tip could be used in C#.
     
    Actually, I don't know why to use this code in VB .Net. When you go to the WinForms project properties, you can make it a single instance application.
     
    In C#, it is recommended to use a mutex :
     
    http://www.yoda.arachsys.com/csharp/faq/#one.application.instance[]
     
    but I'm searching for the best solution to make the unique instance visible when the user tries to launch it again....
    GeneralRe: SingletonsmemberPeter Verijke7 May '09 - 11:00 
    This is not to make an application single instance, but to make a form singleton.
    Hence you will only have one instance of this form.
    GeneralRe: Singletonsmembervdewisme7 May '09 - 21:46 
    Oh OK! Laugh | :laugh: Sorry, I did not understand the aim...
     
    But in this case, why don't use the Singleton pattern ? :
    - private constructor
    - private static instance
    - public static accessor to this instance, which constructs the static instance
     
    That is :
     
    Private Shared _instance as frmStockSelection
     
    Public Shared ReadOnly Property Instance As frmStockSelection
    Get
    If _instance Is Nothing OrElse _instance.IsDisposed Then
    _instance = New frmStockSelection
    End If
    Return _instance
    End Get
    End Property
     
    Private Sub New()
    ...
    End Sub
     
    You can then be sure that only one instance exists at this time, because you prevent instantiating.
     
    Sorry if I don't understand your explanation goal again...
     
    Thanks

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Permalink | Advertise | Privacy | Mobile
    Web03 | 2.6.130523.1 | Last Updated 16 Sep 2003
    Article Copyright 2003 by Peter Verijke
    Everything else Copyright © CodeProject, 1999-2013
    Terms of Use
    Layout: fixed | fluid