Forms are just Classes

Over and over and over again forums like Stackoverflow see questions about how to access something on a Form, from another Form. These questions have been answered hundreds or thousands of times, but with this post I hope to finally put the question to rest by explaining it so that it “clicks”.

First of all, you are asking the wrong question. The question at its root is actually “How do I access a class property from another class?”. This is because Forms are Just Classes! And buttons, text boxes, datagridviews, etc., are just members of the class.

If you already know how to access properties of one class instance from another, then you can figure the rest out yourself. Stop reading, go fix your problem. And if you have been programming for more than 5 minutes, you should have done such things many times over, even if you don’t realize it.

If you are still reading, here are some examples of how to pass data between forms, with an emphasis on Forms just being classes that happen to allow the operating system to draw them.

Lets define two plain old classes. Box and BoxInfo. Box is for holding Widgets and it has a property to store the number of Widgets it is holding. BoxInfo has a property of type Box. So when we assign a Box instance to BoxInfo, we can get Box’s widget count.

Here is a console application to demonstrate:

using System;
using System.Windows.Forms;

namespace FormsAreClasses
{
    class Program
    {
        static void Main(string[] args)
        {
            Box theBox = new Box();
            theBox.WidgetCount = "42";

            //Create a BoxInfo class instance and assign its "MyBox" property
           // to "theBox" created above.
           BoxInfo theBoxInfo = new BoxInfo();
           theBoxInfo.MyBox = theBox;

           //Demonstrate that we accessed theBox's data
           Console.WriteLine(theBoxInfo.MyBox.WidgetCount);
        }
    }
}

The result looks like this:

FormsAreClassesSH1

But there are a couple of little details I left out… Box and BoxInfo are actually Forms!

using System.Windows.Forms;
namespace FormsAreClasses
{
  public partial class Box : Form
  {
    //Create a TextBox in code instead of drag/drop from toolbox
    public TextBox widgetCountTextBox = new TextBox();

    //Holds how many widgets are in the box.
    //We simply access the TextBox's value.
    //We don't really even need this property, I only added it
    //to hide the fact that we had a TextBox in this class so I could
    //surprise you with "Box" being a Form.
    public string WidgetCount
    {
      get { return widgetCountTextBox.Text; }
      set { widgetCountTextBox.Text = value; }
    }

    public Box()
    {
      InitializeComponent();

      //Adding the textbox to the form since we didn't use
      //the designer.
      this.Controls.Add(widgetCountTextBox);
    }
  }
}
using System;
using System.Drawing;
using System.Windows.Forms;

namespace FormsAreClasses
{
  public partial class BoxInfo : Form
  {
    ///
    /// A public property of type "Box". Box is a Form and
    /// we will maintain a reference to it here.
    ///
    public Box MyBox { get; set; }

    //Create a label to display the number of widgets contained in MyBox
    Label lbl = new Label();

    //A button that will get MyBox's widget count when clicked
    Button btn = new Button();

    public BoxInfo()
    {
      InitializeComponent();

      //Some manual labor to add and position the controls since no
      //designer was used to build the forms.
      btn.Text = "Get Widget Count";
      btn.Width = 200;
      btn.Location = new Point(5, 100);
      this.Controls.Add(btn);

     //Add a click handler to the button
     btn.Click += btn_Click;
     this.Controls.Add(lbl);
    }

    ///
    /// Accesses the reference to Form MyBox to get some data from it,
    /// namely its widget count.
    ///
    void btn_Click(object sender, EventArgs e)
    {
      lbl.Text = MyBox.WidgetCount;

      //This also works because the TextBox is Public
      //lbl.Text = MyBox.widgetCountTextBox.Text;
    }
  }
}

And now we modify the console application just a bit to actually use the forms as forms:

using System;
using System.Windows.Forms;
namespace FormsAreClasses
{
    class Program
    {
        static void Main(string[] args)
        {
            Box theBox = new Box();
            theBox.WidgetCount = "42";

            //Create a BoxInfo class instance and assign its "MyBox" property
            // to "theBox" created above.
            BoxInfo theBoxInfo = new BoxInfo();
            theBoxInfo.MyBox = theBox;

            //Demonstrate that we accessed theBox's data
            Console.WriteLine(theBoxInfo.MyBox.WidgetCount);

            Box thebox = new Box();
            thebox.Show();

            theBoxInfo.MyBox = thebox;
            theBoxInfo.Show();

            Application.Run();
        }
    }
}

Now when I run the program I can type “344” into the Box form’s text box, click the button on BoxInfo form, and see the label display data from Box:

SeeIToldYouFormsAreClasses

This is just one way to pass data around but they all boil down to the same thing. If you want data from another form you must have a reference to that form somehow. Whether you create a new Form() in your first form, or pass a Form instance in the constructor, or provide a property to set (as I have demonstrated here), it all comes down to having reference to the object so you can access its properties. Just like you might do for two classes that aren’t forms.

I hope this helps clear things up. For a slightly different approach and to download and run the sample, see my github repo.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s