There are two scenarios possible here:
1. when the user (or you, in your code) closes a given Form: you don't need to retain any of the current information on that Form. Where "information" could mean: what is selected in a Form's various Controls, what is entered in a Form's various TextBoxes, etc.
Great, use Dispose.
Then, you must recreate that Form, when you need it again, as Madonna sang: "Like a virgin, for the very first time."
2. when you want to 'hide a Form, and then, show it again, presumably because you want to retain the information in the Form: just use FormX.Hide(); or FormX.Visible = 'false;
~
As my respected colleague Abhinav S's answer points out, there are a number of ways you could keep track of which Forms are currently "alive;" the technique he proposed is using a Dictionary.
But, keep in mind that, at any moment at run-time in Windows Forms: Application.OpenForms supplies you with a List of (what else ?) currently open Forms (where open means "visible".
Unfortunately, it's not a List that supports operators like 'Contains, or useful Linq operators. You'd have to enumerate Application.OpenForms every time you wanted to see if a given Form Type was open (really, not such a big deal)
~
So, is there another systematic way to keep track of all the open Forms, and their visual state, shown, or hidden: well, I believe a slight variation on Abhinav's Dictionary concept may be useful:
1. define a Dictionary of type <FormInstance, bool>
2. when you dispose of a Form, remove it from the Dictionary.
3. when you create a new instance of a Form: add it to the Dictionary, add a new KeyValuePair, with the Form as Key, and set the boolean Value of the KeyValuePair to 'true if it is visible, and 'false if it is not.
4. when you change the visual state of a Form, but are not disposing it: set the boolean Value of the KeyValuePair of which the Form is the Key to its changed visual state.
How, then, is this Dictionary to be updated to reflect changes in the "state" of the Forms contained as Keys: when a Form is closed, when it's hidden, when it exists, but is hidden, and you, or the user, want to make it visible again ? How to handle adding another new Form, and "registering" it with the Dictionary, and making sure it, too, updates the Dictionary when its "state" changes ?
If the Form that creates the Dictionary (presumably your Main Form) also creates the other Forms being used, then, at the moment they are created, you can wire-up their VisibleChanged, and FormClosed Events to EventHandlers defined in your main Form.
How might this look in code:
private Dictionary<Form, bool> dictActiveForms = new Dictionary<Form, bool>();
private Form changingForm;
private void MainForm_Load(object sender, EventArgs e)
{
Form2 instanceOfForm2 = new Form2();
instanceOfForm2.Text = "the original Form2 instance";
dictActiveForms.Add(instanceOfForm2, true);
instanceOfForm2.Show();
Form2 anotherInstanceOfForm2 = new Form2();
anotherInstanceOfForm2.Text = "the second Form2 instance";
dictActiveForms.Add(anotherInstanceOfForm2, false);
Form3 instanceOfForm3 = new Form3();
instanceOfForm3.Text = "the one-and-only Form3 instance";
dictActiveForms.Add(instanceOfForm3, true);
instanceOfForm3.Show();
wireAllFormEvents();
}
private void wireFormEvents(Form theForm)
{
theForm.VisibleChanged += TheFormOnVisibleChanged;
theForm.Closed += TheFormOnClosed;
}
private void wireAllFormEvents()
{
foreach (Form theForm in dictActiveForms.Keys)
{
wireFormEvents(theForm);
}
}
private void TheFormOnVisibleChanged(object sender, EventArgs eventArgs)
{
changingForm = sender as Form;
dictActiveForms[changingForm] = changingForm.Visible;
}
private void TheFormOnClosed(object sender, EventArgs eventArgs)
{
changingForm = sender as Form;
dictActiveForms.Remove(changingForm);
}
Using this as a basis, let's consider what happens if the user (or you, the programmer, in your code) wants to now make visible the second instance of Type Form2 created above. For demonstration purposes we'll define this in a Button's Click EventHandler:
private void button1_Click(object sender, EventArgs e)
{
foreach (Form theForm in dictActiveForms.Keys)
{
if (theForm.Text == "the second Form2 instance";
{
if (dictActiveForms[theForm] == false) theForm.Visible = true;
break;
}
}
}
How you might add, at run-time, a new Form instance of a Type you want, and "do the right thing" to make it behave like the other "secondary" Forms created here in the Form Load Event:
private void addNewForm(Type formType, string formText, bool isFormVisible)
{
Form newForm = (Form) Activator.CreateInstance(formType);
newForm.Text = formText;
dictActiveForms.Add(newForm, isFormVisible);
wireFormEvents(newForm);
newForm.Visible = isFormVisible;
}
A call to this method could look like this (once again, for demo purposes, we'll put it in a Button's Click EventHandler):
private void button2_Click(object sender, EventArgs e)
{
addNewForm(typeof(Form3), "another instance of Form3", true);
}
Discussion: this is "only one way to fly" when managing multiple Forms created by a Main Form in WinForms, and providing for multiple Forms to be added dynamically (at run-time). The code here is completely tested, but is written-out in fairly elaborate form for educational reasons, only.
In many cases you will know in advance exactly how many secondary Forms your main Form may need, and that doesn't vary, and you can reduce the complexity of the code shown here by simply keeping references around to each secondary Form. And, in many cases, you will not need to allow the user to create multiple new instances of secondary Forms at run-time.
imho, where things get really interesting is where you create multiple independent Forms by modifying the normal behavior of WinForms apps ("running" a single "main" form instance in the Program.cs file) ... but that's another story.
Hope you find some useful "bits" in the code here.
edit ... for anyone wants to play with the working code for what's shown here, compiled against FrameWork 2.0, so, hopefully everyone an use it: [
^].