• Welcome to TechPowerUp Forums, Guest! Please check out our forum guidelines for info related to our community.
  • The forums have been upgraded with support for dark mode. By default it will follow the setting on your system/browser. You may override it by scrolling to the end of the page and clicking the gears icon.

Sample C# Code : Fun with Generics for single form instances

Kreij

Senior Monkey Moderator
Joined
Feb 6, 2007
Messages
13,817 (2.07/day)
Location
Cheeseland (Wisconsin, USA)
Ok, if you read my post on Single instance forms (if you haven't read that post its HERE), you are probably thinking, "Kreij, I have a launcher bar with ten buttons that open ten forms. That would be a buttload of redundant coding !! Isn't there a better way ?"

Well there sure is a better way. Use Generics.
Generics let you create classes and methods that take variable Types.

Variable type classes are declared like this ... class Class1<T>
Where the "T" will be replaced by the type you instantiate the class with (ie. string, int, Form, etc).
It can also take qualifiers for the class types (ie. Form, new() )

So the class declaration "class Class1<T> where T : Form, new()" tells the compiler that the "T" must be of a "Form" type that has its own constructor (the new())

So what do you do ...

First create a class that will handle generic forms

Code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication2
{
    class Class1<T> where T : Form, new()
    {
        private static T mInst;

        public Class1()
        {
            // Here i am just stuffing our single form instance code
            //  into the class constructor
            if (mInst == null)
            {
                mInst = new T();
                mInst.Show();
            }
            else
            {
                mInst.WindowState = FormWindowState.Normal;
                mInst.Focus();
            }
        }

        // You need this method for when a form closes
        public void letGo()
        {
            mInst = null;
        }
    }
}

Now instead of having to modify each form's codefile to make sure it handles singular instances, all you have to do is call the generic class and it will make sure the single instance is managed and call the form constructor for you.

In the following example, I have created a form (Form1) that has 2 buttons (button1 and button2).
Each button opens another form (Form2 and Form3).
I did not include the code for Form2 and Form3 as they are just empty forms with no controls or anything. This is just proof of concept coding ;)

Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // create an instance of class1 that will create a Form2 instance
            Class1<Form2> temp = new Class1<Form2>();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            // create an instance of class1 that will create a Form3 instance
            Class1<Form3> temp = new Class1<Form3>();
        }
    }
}

As you can see, from your main form you do not have to instantiate the other forms or call any methods or properties on the forms to get the same functionality as my initial post on single form instances. You just have to create an instance of the generic class for any form you want to make.

I gotta admin, C# has some pretty slick features ...

Comments or questions are welcome :)

Edit :

Oops, I forgot about a little clean up ...

In your form code files that the generic class calls you still must have a way of nulling out the "mInst" value so that the generic class can recreate the form if you have closed it.

So, without ado, here is the OnClose call for "Form2" ...

Code:
protected override void OnClosed(EventArgs e)
        {
            Class1<Form2> temp = new Class1<Form2>();
            temp.letGo();
            base.OnClosed(e);
        }
 
Last edited:
Ok, I found an even better way of doing this ...

Instead of putting the single form instance code in the generic class constructor, we will make the constructor private and use a public static method (CreateInst) to instantiate the form. We will also make the letGo() method static.

Like so ...

Code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication2
{
    class Class1<T> where T : Form, new()
    {
        private static T mInst;

        public Class1()
        {
        }

        public static void CreateInst()
        {
            if (mInst == null)
            {
                mInst = new T();
                mInst.Show();
            }
            else
            {
                mInst.WindowState = FormWindowState.Normal;
                mInst.Focus();
            }
        }

        public static void letGo()
        {
            mInst = null;
        }
    }
}

Now we do not have to use the "new" method to use this class's methods at all.
So to create a single instance form you can just use ..

Code:
private void button1_Click(object sender, EventArgs e)
        {
            Class1<Form2>.CreateInst();
        }

To clean up we also only need one extra line instead of two.

Code:
        protected override void OnClosed(EventArgs e)
        {
            Class1<Form2>.letGo();
            base.OnClosed(e);
        }

Sorry about that. I wasn't happy with the original.
No wonder it takes me so long to write code, I am forever trying to make it more compact and efficient. :)
 
Wait.. so this makes a form...?

Theres a non Visual studio C# compiler?

Nifty.

Would be awesome to see a C# program void of microsofts .net crap.
 
No, this is using VC# Express from Microsoft.
 
Hi

I tested this code in my App and it show the form without troubles. But when I close and try to open (show) it again, it does not work. I May not use the OnClosed method the right way. I put this method in my child form and called it from my Form1_FormClosed(...) method.

Would you please help me with this?

IB
 
If you .Close() a form, it can't be retreived. You have to create a new instance and start from the beginning. If you .Show() and .Hide(), the original object is still there--just not visible. Probably you'd be better off reinstantiating the Form/object that was closed for the sake of reducing the memory footprint. The quickest way to do that is to save all the variables in a parent scope for recalling. Taking the time to code that also has the added benefit of making it easier to code save/load functions for users to begin where they left off. So, for instance, if they closed a form, then the whole app, they could start the app and then the form and be exactly where they left it.


@op: They aren't "generics." What you are doing is "strongly typing." You probably know that now seeing how hold this thread is. XD
 
Back
Top