Throwing out some WinForms candy to all the kiddies: Singleton Forms...

A large number of people constantly ask about having their form pop up in the same place over and over again and they usually want the same values to be there as well. If you use something like the ShowDialog() command on the same form over and over again, then everything works out fine, since closing the form doesn't dispose the form. However, if you tried the same thing just using the Show() command, then you'd get messed. Why? Because closing a non-dialog form really closes it. The stuff gets disposed and you can't recreate it. So what in the heck do you do?

Well, the answer is in the Closing event. If you tell the CancelEventArgs that you don't want to close, and you simply hide yourself then everything will be cool. This doesn't hurt the rest of the application either, because normally the ApplicationContext.MainForm points to the Form you started your application with. As soon as that MainForm exits, then the rest of the app will come down as well, regardless of what you say to the CancelEventArgs bad guy.

Now, let's develop this into a Singleton type experience, since after all, it would suck to have to keep an instance laying around now wouldn't it.

using System;
using System.ComponentModel;
using System.Windows.Forms;

public class SingletonForm : Form {
    // Storage for our singleton
    private static SingletonForm singleton = null;
   

    // Bah, Designer support, so we can't prevent others
    // from making our form by making this private.  Foo!
    public SingletonForm() {
    }

    // A single singleton instance with anti-close support   
    public static SingletonForm Current {
        get {
            if ( singleton == null ) {
                singleton = new SingletonForm();
                singleton.Closing +=
                    new CancelEventHandler(singleton.KeepAlive);
            }
           
            return singleton;
        }
    }
   
    // Create loose singletons that have the same KeepAlive
    // properties.
    public static SingletonForm LooseSingleton() {
        SingletonForm looseSingleton = new SingletonForm();
        looseSingleton.Closing +=
            new CancelEventHandler(looseSingleton.KeepAlive);
        return looseSingleton;
    }
   
    // KeepAlive is only hooked for the singleton instance
    private void KeepAlive(
        object sender, CancelEventArgs e ) {
       
        e.Cancel = true;
        this.Hide();
    }
}

PS > Whidbey has a better cancellation event that determines the reason for something being cancelled. Interacting with this extra information can help you better determine if you should exit or not. For instance, they tell you if the system is shutting down, if you are being cancelled by the TaskManager or whether a user is closing the form.

Published Friday, July 09, 2004 4:00 PM by Justin Rogers
Filed under: ,

Comments

Monday, July 12, 2004 6:07 AM by Chris Bell

# re: Throwing out some WinForms candy to all the kiddies: Singleton Forms...

Great, I've been looking for something like this for a while. A couple of things, doesn't the KeepAlive method need a call to Hide()? And what is the LooseSingleton method for? Seems like it creates non-singleton instances of the form, which seems a bit odd...
Monday, July 12, 2004 6:37 AM by Justin Rogers

# re: Throwing out some WinForms candy to all the kiddies: Singleton Forms...

Woops, added the Hide, I was being rushed to a dinner when I was typing that in. I didn't even compile the source to make sure it worked.

As for the LooseSingleton, there is a reason for that. Often times you need multiple instances of the same form, but you still want them to keep their resources allocated. You might have a common dialog for instance, that keeps some state based on different code paths. The LooseSingleton allows you to grab a form and attach it to a field local and use the field local as the singleton, while still giving the ability to have multiple field locals each as it's own singleton.

Perhaps a Hashtable of names instances with an indexer would better demonstrate this process?
Monday, July 12, 2004 8:41 AM by Chris Bell

# re: Throwing out some WinForms candy to all the kiddies: Singleton Forms...

Thanks for the explanation, makes sense now!
Friday, July 23, 2004 3:34 AM by Asheesh

# re: Throwing out some WinForms candy to all the kiddies: Singleton Forms...

Nice article but one question.
Shouldn't we make the constructor private, so as to prevent others from instantiating an object of this class? We anyways are creating a singleton object in the current method.

Please let me know if I'm missing something.

Thanks,
Asheesh
Friday, July 23, 2004 11:48 AM by Justin Rogers

# re: Throwing out some WinForms candy to all the kiddies: Singleton Forms...

You can't make the constructor private, else you can't make the form designable. You can make the constructor private at the end if you wish.

This is what I call a loose singleton pattern because you control the singleton nature. Really the main purpose of the singleton property and method is to control form closure so that the form's are reusable.
Tuesday, July 27, 2004 1:22 AM by Asheesh

# re: Throwing out some WinForms candy to all the kiddies: Singleton Forms...

Thanks for the explanation! Makes sense now.

Leave a Comment

(required) 
(required) 
(optional)
(required)