<

Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x

How to Pass Data Between Forms in .NET

Published on
17,864 Points
8,264 Views
6 Endorsements
Last Modified:
It seems a simple enough task, yet I see repeated questions asking how to do it: how to pass data between two forms. In this article, I will show you the different mechanisms available for you to do just that. This article is directed towards the .NET novice.

The first thing you should realize about Form in .NET is that they are classes. How do you or I know that they are classes? The code tells you:

C#
public partial class Form1 : Form

Open in new window

VB
Public Class Form1

Open in new window


Take note of the "class" keyword. This is your indicator that forms are classes. "Ok, fine. Forms are classes. So what?" Well, if you think of forms as classes, which they are, then you can begin to realize how to share data between forms. How do you share data between two classes? You create references to two different instances and then share data via each class' public members. The same holds true for forms. You can create public members (or parameterized constructors or static members) to accept external data. Where I think most people get tripped up by this concept is the the scope each reference has.



Variable Scope

What is "scope?" Scope deals with what parts of code a variable is visible (accessible) to. There are typically two types of scope:  global and local. Global scope can mean a variable is accessible to all parts of class, file, or assembly, depending on how you modify the variable's declaration. Local scope usually means a variable that can only be accessed from within the same function or block--blocks are things like for and while loops, if statements, etc. You can think of blocks as anything between curly braces in C# or anything between an opening statement and its matching "End" statement in VB (If/End If for example).

Why is scope relevant to passing data between forms? You are going to need to pay attention to how your instances are scoped in order to be able to effectively pass data between forms. Let's look at an example of variable scope.

C#

public partial class Form1 : Form
{
    private Form2 f2 = new Form2();

    public void MyArbitraryMethod1()
    {
        Form2 f3 = new Form2();

        // I CAN ACCESS f2 AND f3
    }

    public void MyArbitraryMethod2()
    {
        // I CAN ACCESS f2
    }
}

Open in new window



VB

Public Class Form1
    Private f2 As New Form2()

    Public Sub MyArbitraryMethod1()
        Dim f3 As New Form2()

        ' I CAN ACCESS f2 AND f3
    End Sub

    Public Sub MyArbitraryMethod2()
        ' I CAN ACCESS f2
    End Sub
End Class

Open in new window


In the above code samples, f2 has global scope to the class because it is declared at the class level (basically, outside of any function). It can be accessed by any method within the class. f3 has local scope to the function MyArbitraryMethod1 because it is declared at the function level. It can only be accessed within MyArbitraryMethod1. One thing that is not demonstrated above, but that you should be aware of is that f2 and f3 internally cannot access any data from the Form1. We'll see a bit later how to provide this access.

Here's a breakdown of how you could share data given our current example. Since MyArbitraryMethod1 can access both f2 and f3, you could share data between those two forms. In contrast, within function MyArbitraryMethod2 you could not share data between the two forms since within that function, f3 does not exist. In order to share data between the two forms within the MyArbitraryMethod2 method, you would have to widen the scope of f3. "Widening the scope" of a variable just means to increase the areas of code which can access a variable. For this simple example, the only widening route you have is to change f3 from a local variable to a global variable. Had f3 been declared from within an if statement, then f3 would have been accessible only from within the if. In widening its scope, you could either relocate f3 to be local to the function (rather than local to the if block) or you could relocate f3 to be global to the class.

You may have noticed that I didn't mention Form1, the class in which we are writing this code, in the above example. That's because I saved it for this paragraph! Since we are working from within Form1, we can share data between any form we declare from within Form1's code--from anywhere in the code as long as the form object we are sharing data with is in scope. This means the same thing as I described above with regard to declaration of f3. If we are not working in a function which has access to a different form object, then we cannot share data. For our previous example, in MyArbitraryMethod1, we can share data between Form1 objects and f2 or f3, but in MyArbitraryMethod2, we can only share data with f2.



How to Share

So we have examined when we can share data, but we still haven't covered how. Here's how. I mentioned previously that you can share data by means of public or static members, or by passing data to constructors. Let's take a look at each method.


Public Methods and Constructors

I'm including these as one in the same because you could think of a constructor as being a method--at least with respect to what we're doing here. Let's expand our previous example:

C#
public partial class Form2 : Form
{
    private string _form1Data;

    public Form2(string form1Data)
    {
        InitializeComponent();

        this._form1Data = form1Data;
    }

    public void SomeFunction1()
    {

    }

    public void SomeFunction2(string form1Data)
    {

    }
}

Open in new window


VB
Public Class Form2
    Private _form1Data As String

    Public Sub New(ByVal form1Data As String)
        InitializeComponent()

        Me._form1Data = form1Data
    End Sub

    Public Sub SomeFunction1()

    End Sub

    Public Sub SomeFunction2(ByVal form1Data As String)

    End Sub
End Class

Open in new window


Here, we are looking at Form2's code now. I have included both an example of passing via the constructor and passing via a method. The difference I'd like to make note of is that  we took in Form1 data as a parameter in the constructor. We then saved this data to a private variable within Form2. This private variable has global scope to Form2's code. Both SomeFunction1 and SomeFunction2 could subsequently access this value. There is nothing saying we must save the incoming Form1 data to a private variable. Perhaps you want to perform some calculation on the incoming data and store the result in some other member or field of Form2. This is perfectly fine. For this example, just know that if you pass data via a constructor and you want that data to be accessible to other parts of the class, then you will have to save the data somewhere--here I used the private member variable _form1Data. Now onto the methods.

For SomeFunction1 and SomeFunction2, scope rules are still in effect (and they always will be). SomeFunction1 has no knowledge of the parameter which SomeFunction2 takes. It can have knowledge of it if you save this data to some member variable, but this is a "dumb" knowledge. SomeFunction1 doesn't really know that SomeFunction2 takes a parameter; it just knows that some member variable can be accessed by it, due to scoping. It would be up to SomeFunction2 to assign the incoming Form1 data to the private member variable of the class.

If we have this mechanism to pass data, how do execute it from the other form? Well, since these mechanisms we have created are public members, they can be called from our other form provided we have valid instances. Here's what that could look like:

C#
public partial class Form1 : Form
{
    private string _dataToPass = "Hello World!";

    public void MyArbitraryMethod1()
    {
        Form2 f3 = new Form2();

        f3.SomeFunction2(this._dataToPass);
        f3.Show();
    }

    private void button1_Click(object sender, System.EventArgs e)
    {
        MyArbitraryMethod1();
    }
}

Open in new window


VB
Public Class Form1
    Private _dataToPass As String = "Hello World!"

    Public Sub MyArbitraryMethod1()
        Dim f3 As New Form2()

        f3.SomeFunction2(Me._dataToPass)
        f3.Show()
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        MyArbitraryMethod1()
    End Sub
End Class

Open in new window


In MyArbitraryMethod1, we have created a new instance of a Form2 class. Take note that we are passing a string that is private to the Form1 class. This string does not exist in Form2's code, at the moment. We use one of the public data-passing mechanisms we just covered to share the data, namely passing via a function. In Form2, we can now work with the Form1 data.

C#
public void SomeFunction2(string form1Data)
{
    this.label1.Text = form1Data;
}

Open in new window



VB
Public Sub SomeFunction2(ByVal form1Data As String)
    Me.Label1.Text = form1Data
End Sub

Open in new window


One technicality to be aware of here is that for this demonstration we are passing a string. string in .NET is a reference type, but it behaves like a value type. What does that mean? Well, in Form2, we are working with a copy of the string we passed in from Form1. There are ways to overcome this and actually work with the string declared on Form1. Adding the ref or out keywords in C# and changing the ByVal to ByRef in VB would accomplish this. The point here is that you should be careful with your references when passing data between forms (or any class for that matter) and know whether you are working with a copy of the data or the actual data.

Here is the output you would receive with the above code:
 Data Passed to Form2
Note that the string "Hello World!" doesn't occur anywhere in Form2's code--we passed it in from Form1. Yes, it's that simple!


Public Properties

Behind the scenes, properties in .NET are turned into getter and setter methods. Since the syntax is a bit different from a method, however, I thought I'd have a separate section on properties.

Even though I'm giving you a separate section on properties, in actuality there is not much different in the way you pass data. The only real difference is that instead of making a function call and either immediately working with the value or storing the value for later use, you store the value immediately for later use. Here's an example:

C#

Property Definition
using System.Windows.Forms;

namespace WindowsFormsApplication13
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        public string StringToDisplay
        {
            get { return this.label1.Text; }
            set { this.label1.Text = value; }
        }
    }
}

Open in new window


Sharing Via the Property
using System.Windows.Forms;

namespace WindowsFormsApplication13
{
    public partial class Form1 : Form
    {
        private string _dataToPass = "Hello World!";

        public void MyArbitraryMethod1()
        {
            Form2 f3 = new Form2();

            f3.StringToDisplay = this._dataToPass;
            f3.Show();
        }

        private void button1_Click(object sender, System.EventArgs e)
        {
            MyArbitraryMethod1();
        }
    }
}

Open in new window


VB

Property Definition
Public Class Form2
    Public Sub New()
        InitializeComponent()
    End Sub

    Public Property StringToDisplay() As String
        Get
            Return Me.Label1.Text
        End Get
        Set(ByVal value As String)
            Me.Label1.Text = value
        End Set
    End Property
End Class

Open in new window


Sharing Via the Property
Public Class Form1
    Private _dataToPass As String = "Hello World!"

    Public Sub MyArbitraryMethod1()
        Dim f3 As New Form2()

        f3.StringToDisplay = Me._dataToPass
        f3.Show()
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.MyArbitraryMethod1()
    End Sub
End Class

Open in new window


The result is the same as that displayed in the above image.


Passing a Reference to the Parent Form

Similar to passing data via functions or properties, another way to access data from one form on another would be to pass a reference to the "parent" form itself. In reality, this is the same thing as what we saw in Public Methods and Constructors. The benefit to this approach is that you open up access to all public members of the parent form from within the child form, rather than just a fixed number of data elements. Setting up this approach is simple: do the same thing we saw in Public Methods and Constructors, except that instead of passing a data element of type string (in the above example), change your procedure to accept an element of the type which the parent form is. Here's an example.


C#

Passing the Reference
public partial class Form1 : Form
{
    private string _dataToPass = "Hello World!";

    public void MyArbitraryMethod1()
    {
        Form2 f3 = new Form2(this);

        f3.Show();
    }

    public string StringToDisplay
    {
        get { return this._dataToPass; }
    }

    private void button1_Click(object sender, System.EventArgs e)
    {
        MyArbitraryMethod1();
    }
}

Open in new window


Sharing Via the Form Reference
public partial class Form2 : Form
{
    public Form2(Form1 form1Instance)
    {
        InitializeComponent();

        this.label1.Text = form1Instance.StringToDisplay;
    }
}

Open in new window


VB

Passing the Reference
Public Class Form1
    Private _dataToPass As String = "Hello World!"

    Public Sub MyArbitraryMethod1()
        Dim f3 As New Form2(Me)

        f3.Show()
    End Sub

    Public ReadOnly Property StringToDisplay() As String
        Get
            Return Me._dataToPass
        End Get
    End Property

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        MyArbitraryMethod1()
    End Sub
End Class

Open in new window


Sharing Via the Form Reference
Public Class Form2
    Public Sub New(ByRef form1Instance As Form1)
        InitializeComponent()

        Me.Label1.Text = form1Instance.StringToDisplay
    End Sub
End Class

Open in new window


Notice that we pass a Form1 reference to Form2 by way of the this (Me in VB) keyword. Because Form2 now has a reference to a valid instance of a Form1 object, Form2 has access to Form1's public members, including fields, properties, and methods.


Static Members

This could be considered an extension to the previous two methods (excluding constructors), but it is different enough to warrant its own section. Static ("shared" in VB) members are those that do not need a valid instance in order to be referenced. If you have ever called MessageBox.Show(), then you have used a static member. Think about it. Did you have to create a new MessageBox object in order to call Show(), or did you just call it? Any time you call a method, assign to or read from a property, or assign directly to certain variables by using the syntax

[ClassName].[MemberName]

you are referring to static members. This access convention is why it's a bad idea to give properties the same name as their encasing class.

The thing to be aware of when dealing with static members is that only one occurrence of the member exists for every instance of a particular class. I'll discuss this while we examine our next example.

C#

Creating the Second Form
public partial class Form1 : Form
{
    public static string _dataToPass = "Hello World!";

    public void MyArbitraryMethod1()
    {
        Form2 f3 = new Form2();

        f3.Show();
    }

    private void button1_Click(object sender, System.EventArgs e)
    {
        MyArbitraryMethod1();
    }
}

Open in new window


Sharing Via the Static Member
public partial class Form2 : Form
{
    public Form2()
    {
        InitializeComponent();

        this.label1.Text = Form1._dataToPass;
    }
}

Open in new window



VB

Creating the Second Form
Public Class Form1
    Public Shared _dataToPass As String = "Hello World!"

    Public Sub MyArbitraryMethod1()
        Dim f3 As New Form2()

        f3.Show()
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        MyArbitraryMethod1()
    End Sub
End Class

Open in new window


Sharing Via the Static Member
Public Class Form2
    Public Sub New()
        InitializeComponent()

        Me.Label1.Text = Form1._dataToPass
    End Sub
End Class

Open in new window


Have you noticed the difference here? Whereas in the last two examples Form1's data was pushed to Form2 from directly within Form1, here we are pulling the data from Form1 from within Form2. This is due to the nature of static members and how you access them via the class name rather than an instance name. Now is probably a good time as any to talk about the negative of this approach:

It is generally a bad idea to use static (shared) members to share data between two instances. Any time you change a static value, every instance of the class will see this change. It is very easy to introduce bugs via this mechanism and it should be used judiciously.

The result of the above code is the same as the image above.



Summary


Congratulations if you've made it this far. I realize there was quite a bit of reading to get to this point. You should have a decent understanding of what mechanisms exist for you to share data among your forms. Keep in mind that you can share public data between forms provided there is some scope relationship between the forms--meaning one form is accessible to the other (or both forms are accessible to each other). You can also share data by implementing static members. Static members will be shared between all instances of the class, so a change to a static member in one instance will be seen by all instances. Another caveat of static members is that even private static members will be shared among instances--they just won't be accessible by objects of a different type. In the grand scheme of things, just remember that .NET treats forms as classes, and that you share data between forms the way you share data between any class. Don't sweat it if you get tripped up on your initial attempts at implementing these concepts in your code--you can always come to EE to share your frustrations!
6
Comment
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
2 Comments
 

Expert Comment

by:KonstFom
I think it`s a bad style. What about MVC?! You need only change model and views(form1, form2 ,...) show this changes
0
 
LVL 75

Author Comment

by:käµfm³d 👽
@KonstFom

The intent of the article was to be more of a "beginner's introduction", and it was born out of countless questions I've seen asked on the site regarding sending data from one form to another. Certainly MVC is a viable option, but it is not an intuitive designer pattern for beginners. Aside from that, some smaller projects might not benefit from the overhead of implementing the MVC pattern. Moreover, you could also implement an MVP pattern to accomplish the same (I believe). In short, I would say, "right tool for the job."

Thanks for reading!
0

Featured Post

Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

Join & Write a Comment

This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month