Opening form instances in C#

Creating a new form in C# is fairly simple, thanks to the Form class. But what about referencing an existing one? Step through this sample code and see how it's done.

Much of the time in the real world, we don’t want to open a new instance of a form—we want to open a specific instance that already contains information. In my previous article, I introduced a simple example where this information is represented by the text phrase the user has loaded into the label control in an instance of the Form class. The code for that basic implementation appears in Listing A. Now it's time to see how you go about opening an existing instance. Let’s get started and work through the general pattern in C# .NET for recalling a specific instance of a Form class.

Do you need a refresher on C# forms?
Check out the first part of this article where the concepts are introduced and explained.

Recalling a specific form instance
Let’s say we want to use the button on the Form2 instance to get back to our instance of Form1. Here’s where we start to run into the limitations of creating a new instance of a Form class. To demonstrate, add the symmetric code to the click event of the button on the Form2 instance to show an instance of Form1:
private void btnForm1_Click(object sender, System.EventArgs e) {
Form1 form1 = new Form1();

Figure A shows the code in action. Next, fire up the project. Enter a phrase in the textbox in Form1, such as I think therefore I exist! Click the button to load it into the label. Now click the button to show the instance of Form2. On Form2, click the button to show an instance of Form1. No matter how many times you do this, all you’ll get is a new instance of Form1—meaning the text that was loaded into the label by the user will not be displayed.

Figure A

Oftentimes, of course, there will be a lot more information in a Windows form instance than just a single phrase, input by the user or gathered in some other way. So how can we return to the current instance of Form1 and keep its information intact?

Obviously, what we need is a variable we can access that points to the specific instance of the Form1 we want to display. One way to do this is to use a public, static variable to hold the reference to the instance. (The difference between static and instance class members, such as variables, is that static members do not have to be instantiated.)

To do this, declare a public, static variable of type Form1 just below the Form1 class declaration. I’ve named the variable staticVar:
public class Form1 : System.Windows.Forms.Form
public static Form1 staticVar = null;

By the way, there’s no reason to place this variable in the Form1 module—as long as it is public and static, you can put it wherever you’d like. If you have multiple public, static variables, it may be a good idea to create a class in a separate class module just for them. Also note that I’ve initialized the variable using the null keyword so that it explicitly does not contain a form reference.

When it's time to display the Form2 instance, use the this keyword to store a reference to the current Form1 instance in the staticVar variable:
staticVar = this;

Here’s the full revised code for the click event that displays the instance of Form2:
private void btnForm2_Click(object sender, System.EventArgs e) {
staticVar = this;
Form2 form2 = new Form2();

Now it’s easy to open the desired instance of Form1 from Form2 just by using the reference stored in the Form1.staticVar variable. Here’s the revised Form2 click event:
private void btnForm1_Click(object sender, System.EventArgs e) {

Run the project again. Enter some text in the Form1 textbox, such as the phrase This time I’ll get back to my instance! Click the button to hide it and show Form2. When you click the Show Form1 button on Form2, the instance of Form1 with your input will be displayed, as shown in Figure B.

Figure B

As it is, this works just fine. However, extensive use of public variables violates canons of good programming practice (specifically, the variables aren't encapsulated). In addition, it is probably excessively consumptive of resources. A somewhat better solution is to store the form instance reference as a property of one of the classes.

Let’s add a property to the Form2 class that stores a reference to an instance of a Form class. (Note that I’m creating the property using the more general Form class rather than the specific Form1, so a reference to an instance of any class derived from the Form class can be stored in the property, not just a Form1 instance.)

You can use the C# Property Wizard, which you access from the Class View window, to jump-start you in creating the property, but it is easy enough to create it by hand in the Form2 class module.

Here’s the property added to the Form2 class module (it can go anywhere in the body of the class):
private Form m_InstanceRef = null;
public Form InstanceRef{
get {
return m_InstanceRef;
set {
m_InstanceRef = value;
} }

Note the use of a private variable to store the value within the class instance, get and set accessors, and the value keyword to set a new property value.

Next, the click event in Form1 that invokes Form2 needs to be modified to use the property rather than a public variable. We'll do this by assigning a reference to this (the current form instance) to the property:
private void btnForm2_Click(object sender, System.EventArgs e) {
Form2 form2 = new Form2();
form2.InstanceRef = this;

Finally, the property is used in Form2 to invoke the correct instance of Form1 (Figure C). No qualifier is needed preceding the property since it is a member of the current instance:
private void btnForm1_Click(object sender, System.EventArgs e) {

Figure C

As you can see, properties work well for communicating form instances between the various modules in a Windows form application and provide a more encapsulated approach than using a public, static variable.

A form foundation
This two-part article has described the main pattern for Windows form interoperability in C#, but obviously as you get going, you’ll find wrinkles that depend on the particular needs of your projects. For one thing, you may have situations involving structures such as arrays or collections that point to multiple forms—and you'll need to pick the right reference from the various instances referenced in the structure. But the general approach we've introduced here should help get you get off to a good start.

Editor's Picks