Title: Make two forms open each other in C#
This is sort of a beginner's exercise in making two forms work with each other, although it raises some non-beginner issues.
Beginners often want to have two forms (or more) open each other. Unfortunately this is surprisingly confusing in C#.
The first step is to realize that each form needs some sort of variable that refers to the other so it can make the other form appear. There are only a few places you could put that variable. For example, you could create a third class to hold the variables and then give the class two variables to hold references to the two forms. You could even make the variables static (shared) so you wouldn't need to make an instance of the class.
That approach works and is a handy way to allow other parts of the program (including the two forms) to share data. More generally this allows you to work around C#'s restriction that all data and code must be in a class. But some feel this solution is inelegant.
The approach this example takes is to give each of the two forms a variable that refers to the other. When the main form starts, its Load event handler initializes both variables.
Each of the forms contains a button that display the other form.
The following code shows the second form's code.
// A variable that refers to the instance of Form2.
// Note that it's public.
public Form1 TheForm1;
// Switch to TheForm1.
private void btnForm1_Click(object sender, EventArgs e)
{
this.Hide();
TheForm1.Show();
}
The code first creates a variable named TheForm1 to hold an instance of the Form1 class. Because the first form's Load event handler initializes it, the variable must be declared public.
When you click the form's button, the code hides the current form. Note that this doesn't destroy the form, it just makes it invisible.
The code then displays the first form, which is stored in variable TheForm1.
The following code shows the first form's code.
// A variable that refers to the instance of Form2.
private Form2 TheForm2;
// Initialize the form variables.
private void Form1_Load(object sender, EventArgs e)
{
// Make the Form2.
TheForm2 = new Form2();
// Initialize the Form2's variable.
TheForm2.TheForm1 = this;
// Make both forms stay on top.
this.TopMost = true;
TheForm2.TopMost = true;
}
// Switch to the Form2.
private void btnForm2_Click(object sender, EventArgs e)
{
this.Hide();
TheForm2.Show();
}
Like the second form, this code has a reference to the other form. Because this form is the only one that needs to refer to variable TheForm2, it is declared private.
When the form loads, its Load event handler creates a new Form2 object and saves a reference to it in the TheForm2 variable.
Next the code initializes the new form's TheForm1 variable so it points back to the current form, has type Form1. Now the Form2 can refer back to this Form1.
When the form's show each other, they sometimes end up below other programs on the desktop. To prevent the forms from dropping to the back, an odd feature of Windows, the program sets both forms' TopMost properties to true. That keeps them above all other non-topmost forms.
When the user clicks the first form's button, its Click event handler hides the current form and displays the other form.
That's the basic approach, but there's still one important issue. By default startup form, which is initially Form1, plays an important role in a C# program. When that form is destroyed, the program ends. In this example, if you click the startup form, the startup form hides and displays the second form. Now if you close the second form, the second form goes away but the startup form is still hidden. That means there's no way to end the program. It sits there hidden in the background like a zombie wasting resources.
There are several approaches you can take. The two easiest and most obvious are to close the first form and to prevent the second for from closing. For both approaches you add a Form_Closing event handler to the second form.
To close the first form when the second form closes, simply make the Form_Closing event handler close the second form as in the following code.
private void Form2_FormClosing(object sender,
FormClosingEventArgs e)
{
// Approach 1: Close the startup form.
TheForm1.Close();
}
Now when the second form is about to close, it also closes the first (startup) form so the program ends.
For the second approach, make the Form_Closing event handler set its e.Cancel parameter to true to prevent the second form from closing. Then hide it and display the startup form as before. The following code shows this approach.
private void Form2_FormClosing(object sender,
FormClosingEventArgs e)
{
// Approach 2: Hide this form instead of closing it.
this.Hide();
TheForm1.Show();
e.Cancel = true;
}
Either way the user cannot close the second form without closing the startup form, so you don't get a zombie program.
Finally note that this really isn't a very good user interface design. Beginners often want to have two forms (or even more) that jump to each other like this, but that's confusing to the user. A much better design is to have one main form that displays secondary forms modally. The user opens and closes the secondary forms, but the main form is always visible so the user can find it and use it as a sort of home for the program. When the user closes the main form, the program ends as expected.
Download the example to experiment with it and to see additional details.
|