Subscribe to Martyr2's Programming Underground        RSS Feed
-----

Passing Data Between Forms in C# or VB.NET

Icon 4 Comments
One of the first obstacles that people new to C# (or VB.NET for that matter) run into is how to get two forms to communicate with one another. How do you get your main form (a parent) to open and pass along data to another form (the child)? This question typically arises when the programmer wants to create a dialog situation where they click a button to launch a dialog form, ask for some settings and close it to return to the main form they were working on. So I wanted to take a minute to talk about the ways you can do that and show you some code to implement one of those ways. Kick back and lets get ready to hack some code on this episode of the Programming Underground!

<Marilyn Manson singing about C "sharp" and cutting himself with it as if it was a razor or something theme music>

The first thing you have to realize when working with the .NET framework is that everything is a class. Forms are no exception. Each form represents a class where you can not only write events to respond to form controls, you can add additional code such as class variables, properties and methods. This gives you, the programmer, the ability to add additional functionality to forms. When you go onto a programming web board asking about passing data between forms you typically get something along the lines of "create a property or method and call it from another form". This is dandy, but what exactly is meant by that?

As I already have mentioned, forms are classes and that means you can add methods or properties to them. Make these items public and then other classes will be able to see them. This means by adding a public property or method to one form, other forms can use those properties/methods to communicate with it. The great thing about this is that you can also control the "interface" of a form and validate the info coming in and what the form is sending back out.

Using properties (the method I will show you in a second) or class methods are a great way to communicate to other forms about the controls that the form contains. If I want the text value of a textbox on the second form, my first form can call the second form's property or method and ask for it. The second form in return can decide what to give back to the first form.

In our example below I have two forms. One is named frmMain and is the parent form. This form will contain a simple label, textbox and a button to call the second form we call frmChild. frmChild has a label, a textbox and a button to close the form and return a dialog result. Below is a screenshot of the two forms...

Attached Image

Then we fill out the textbox on the child form and click ok...

Attached Image

... After clicking the OK button we will then see the text appear back in the parent form.

Attached Image


To see how this works we will start with the child form code first to implement a property we will call "ChildText". We will then use that property from the frmChild form to communicate with the Child Form's textbox. So let's take a look at the child forms code...

// Child Form class definition
public partial class frmChild : Form {
   public frmChild() {
      InitializeComponent();
   }

   // Custom property we are adding to the child form
   // Notice it is public and communicates with the txtChildText control on this form.
   public String ChildText {
      get { return txtChildText.Text; }
      set { txtChildText.Text = value; }
   }

   // Simply ok button to return an OK result back to parent (since this was called with ShowDialog and expects a result)
   private void btnChildOK_Click(object sender, EventArgs e) {
      this.DialogResult = DialogResult.OK;
   }
}



In the code above you will notice that we have put in a custom property we call ChildText. Also notice that is public so that our other forms will see it. When we create an instance of this form, besides having all the properties and methods of a typical form, it will also have this property we can use. This property is interacting with the txtChildText textbox control on the form which no other form can see (it belongs to the frmChild after all). Lastly we have a simply OK button click event to tell the parent form that we are returning a dialog result of "OK".

Now for the parent where we will use the child form. We will create the child form instance, use its ChildText property to give it some data (that it in turn uses to set txtChildText) and then launch the form as a dialog. We can then type something in the box on the child form and click OK to return to the parent form. The parent form can then use the same property (ChildText) to read the data back from the child and set its own textbox.

// Parent form class definition
public partial class frmMain : Form {
   public frmMain() {
            InitializeComponent();
   }

   // Open child form button
   private void btnOpenChild_Click(object sender, EventArgs e) {

      // Create the child form instance, use its new custom property to send it some data.
      frmChild child = new frmChild();
      child.ChildText = "Text Sent From Parent";

      // Now show it as a dialog. If the dialog is returning ok, use the property to read back data
      // and set the txtFormChild control on frmMain with the data typed into txtChildText on frmChild.
      if (child.ShowDialog() == DialogResult.OK) {
         txtFromChild.Text = child.ChildText;
      }
   }
}



As you can see from the code we simply create a new instance of our child form, use the text property we created to send it some data, show the child form with ShowDialog() and everything was returning OK, use the property to set the textbox on the frmMain form.

This method can also be applied to methods of the child form. Declare a method on the child form, make it public so that it can be seen and pass along parameters to help configure the child form before being shown or communicate with after it has been instantiated. I find a property a bit easier since it is essentially two methods in one. One to send data and another to read it back wrapped up in a nice clean name. But you can certainly do either. You can also put the properties/methods back on the parent as well so that your child can ask the parent for data too.

A third method you may hear is to make the controls of the child form public themselves and communicate with them directly. I strongly recommend against this because it opens the form controls up to being corrupted unintentionally. This is basically the same thing as creating a global variable (which most programmers know is bad programming style if you can help it). It also doesn't provide you the same level of control of what data comes in and out of the form. Just like it doesn't provide you the same level of control by making private class members public.

By exposing controls through the form's interface using properties and methods, we can validate, regulate and control how the form communicates and thus keep it free from rogue program elements from messing with the form's data without warning.

Now you don't have to use this method for each and every single control. You can make a more generic method or property that make take complex data types and sets multiple controls on the child form at once. By making the property/method generic enough you can use it to set virtually any control on the form. Think about what you can do with this by also putting these properties/methods into an abstract form class and inheriting all your forms from it. Just an idea for you.

I hope you have found this little tip some use and help you create forms that communicate between one another. The theories and code here can be applied to VB.NET as well (with some subtle syntax changes of course). Since both languages treat forms as classes, you can easily add the properties/methods to them for general form to form communication.

Thanks for reading! :)

If you want more blog entries like this, check out the official blog over on The Coders Lexicon. There you will find more code, more guides and more resources for programmers of all skill levels!

4 Comments On This Entry

Page 1 of 1

CharlieMay Icon

27 February 2010 - 08:01 PM
Martyr,
I've learned a lot from your examples, not to mention your answers in various posts. One of the things I've never gotten anyone to explain to me is the downfall of using the default instance. So I'll ask you, what is exactly wrong with using something like the following:

on frmChild;
me.TextBoxOnfrmChild.Text = frmParent.TextBoxOnfrmParent.Text?
2

Martyr2 Icon

28 February 2010 - 09:31 AM
I am glad you asked CharlieMay and I am glad you have learned a lot from my examples. First of all I want to say that what you are describing is not going to work by default in C#. VB.NET on the other hand makes it work on default simply because it makes controls on a form a "Friend" by default which I find a bit odd and frankly a bit unnecessary.

What you are describing is exactly what I was talking about when I was talking about the third method of communication where form controls were made public. By reaching in through a form and accessing the control directly you are using the control much like a public variable. In fact, VB.NET (with its friend modifier) is making this possible but in C# it simply doesn't work (you have to tell C# to make the control a friend/public). As you may have heard from many wise programmers that public variable use is bad because it leaves a variable, or in this case a control, open to the elements... that is anything could come along and change it without you necessarily knowing. Making the control/variable private protects it from unintended changes.

By making the controls private you are enforcing what is known as "encapsulation" (aka data hiding) and keeping the variable tucked into the class without being exposed. This means that the only way to access the control is through a property or method we create and we can control. We can run validation on the data before it reaches our textbox, we can determine its length or if the control should even be set, we can reject numbers or format it into a zip code. We control that data, not leaving the variable out there to be changed by some other class that comes down the line later.

Your code also introduces the problem of being "tightly coupled". What if you got rid of the TextBoxOnfrmParent control from that form? You would have to go everywhere in your program and change it. While if you did it through a property or method, you could change how that property or method worked once (change the form control or redirect the data) without affecting the rest of your program code. You always want to strive for loose coupling because it makes programs more robust and easily maintainable.

So as you can see I am a bit surprised that VB.NET would take it upon itself to make a control a friend like that by default and allow it to be directly accessed through the class. I think it is a bit of a mistake in my opinion.

But in short the problem with your example is that frmParent.TextBoxOnfrmParent is being unnecessarily exposed to the world and another class could come along and change it without exactly you knowing it. For most applications this isn't going to be a huge concern, but keep in mind that as you grow out your application and put in some more complex coding you want to keep variables/controls tucked away into their classes and not hanging out for modification. You also don't want to find yourself in a situation where multiple forms are dependent (coupled) to the control itself just in case later you change that control's name, how it works or how it is exposed. You want to be able to change one property or method instead of hopping around your program looking for everywhere it is being used directly.

Hopefully I have made things clear enough and thanks again for asking the question. :)
1

rkrk Icon

17 March 2010 - 07:45 AM
Hello Martyr2,

Took the pains of registering on "dreamincode" just to thank you for your wonderful post .And really really THANKS a lot . This happened to be the kind of things for which i'd found a workaround (basically creating a singleton to store data that had to be passed around which could be referenced from anywhere in the code). But it bothered me constantly for around 2 months where it kept showing in the TODO section during compilation. Today, i've found a decently acceptable solution in your post (considering my solution to be indecently acceptabe :-) ) .
Thanks once again.

-Rahul aka rkrk
0

Martyr2 Icon

17 March 2010 - 10:55 PM
I appreciate you taking the time to sign up with us and provide me some wonderful compliments. I am also happy to hear that my post had helped you become a better programmer and some day when you are rich and famous as a rockstar programmer, you will be kind enough to give me a shout out "to the little guy". :)
1
Page 1 of 1