How to Pass Data Between Forms in .NET
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#
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#
VB
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#
VB
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. SinceMyArbitraryMethod1 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 f3from a local variable to a global variable. Had f3 been declared from within an ifstatement, 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 ifblock) 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 withinForm1'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#
VB
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. BothSomeFunction1 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#
VB
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 inForm2'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#
VB
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 theref 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:
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
Sharing Via the Property
VB
Property Definition
Sharing Via the Property
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
Sharing Via the Form Reference
VB
Passing the Reference
Sharing Via the Form Reference
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
Sharing Via the Static Member
VB
Creating the Second Form
Sharing Via the Static Member
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 Form1from 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!
No comments
Post a Comment