# Working with Multiple Forms in Visual Basic .NET: Upgrading to .NET

## Introduction

In Microsoft® Visual Basic® 6.0, if you had a second form (Form2) in your project, then displaying it was as easy as Form2.Show. That code is no longer correct in Visual Basic .NET due to some changes in how forms are handled. For programmers moving from an earlier version of Visual Basic to .NET, these changes can make the simple task of displaying a second form seem very difficult. In this article, I will illustrate how Visual Basic .NET forms differ from previous versions and how you can work with multiple forms within the new model.

## Visual Basic 6.0 vs. Visual Basic .NET

Forms, in either version of Visual Basic, are essentially the same as any other class; they have properties, methods, and events, and you can create multiple instances of them. So, assuming you have a form in your project called Form2, the Visual Basic 6.0 code shown here creates three instances of that form and displays them all:

Dim myFirstForm As Form2
Dim mySecondForm As Form2
Dim myThirdForm As Form2

Set myFirstForm = New Form2
Set mySecondForm = New Form2
Set myThirdForm = New Form2

myFirstForm.Show
mySecondForm.Show
myThirdForm.Show

Now, other than the use of the keyword Set to assign new Form2 instances to your three variables, this code will also work in Visual Basic .NET, and both languages will display three copies of Form2 if this code is run. In this example, Form2 is behaving as a class, and you have to create an instance of a class before you can use it, but a special feature of Visual Basic prior to .NET allows you to work with Forms without creating an instance. This change in behavior in Visual Basic .NET can cause a great deal of confusion. In Visual Basic 6.0 and earlier versions, a special default instance of each form is automatically created for you, and allows you to use the form's name to access this instance. What this means is that the Visual Basic 6.0 code "Form2.Show" has the effect of showing the "default" instance of Form2, but it doesn't work at all in Visual Basic .NET. In .NET there is no default instance; Form2 refers only to the class that represents your form, and this class cannot be used without creating an instance.

That is the key difference between .NET and previous versions of Visual Basic—you need an instance of a form before you can display it or work with any of its controls or properties—but the second part of the problem is that these special default form instances are global to your entire project in Visual Basic 6.0. Taking these two facts together means that (in Visual Basic 6.0 or earlier) you can refer to any form in your project from anywhere in your code and you will always be referring to the same instance of that form. With the button's Click event on one of your forms you could show Form2 with "Form2.Show," and then set the text of a text box on Form2 from code in a module just like this:

Form2.TextBox1.Text = "Fred"

If you try to do the same type of code in Visual Basic .NET, you will run into the error message Reference to a Non-Shared Member Requires an Object Reference, which means that you tried to call a method or use a property of a class instead of an instance. A quick solution to this problem is to create an instance in every case where you are receiving the error message, turning:

Form2.Show()

into:

Dim myForm2 As New Form2()
myForm2.Show()

This will work in many cases, but if you had code somewhere else in your project that accessed that same default instance of Form2 and you fix it in the same way by turning:

Form2.TextBox1.Text = "Fred"

into:

Dim myForm2 As New Form2()
myForm2.TextBox1.Text = "Fred"

then you will have trouble, because this code has created a new instance of Form2; you are not working with the same instance you created earlier. You won't get any errors (there is nothing wrong with the preceding code), but you won't see any change on the instance of Form2 that you called Show() on earlier.

## How the Upgrade Wizard Handles This Problem

If you upgrade a Visual Basic 6.0 project, the Upgrade Wizard adds some special code to each of your forms to provide you with the default instance functionality that you were able to use in earlier versions of Visual Basic. This code, wrapped in a region labeled "Upgrade Support," adds a Shared property that returns an instance of the underlying form:

Private Shared m_vb6FormDefInstance As Form1
Private Shared m_InitializingDefInstance As Boolean
Public Shared Property DefInstance() As Form1
Get
If m_vb6FormDefInstance Is Nothing _
OrElse m_vb6FormDefInstance.IsDisposed Then
m_InitializingDefInstance = True
m_vb6FormDefInstance = New Form1()
m_InitializingDefInstance = False
End If
DefInstance = m_vb6FormDefInstance
End Get
Set(ByVal Value As Form1)
m_vb6FormDefInstance = Value
End Set
End Property

As a shared property, DefInstance is accessible using just the form's name, and the same instance of the form is returned for everyone using this class within a single application. With this code added to your form(s), you can write code that mimics the behavior of the Visual Basic 6.0 examples shown earlier by specifying Form2.DefInstance instead of just Form2.

## Interacting with Other Forms in .NET

If you are coming from earlier versions of Visual Basic it can be difficult to work without default instances of your forms. The following sections illustrate how to handle several specific scenarios and should help you with your own programming tasks.

### Keeping a Reference Around

As mentioned earlier, the most important concept to understand about programming with forms is that you need an instance of a form before you can do anything with it, and if you want to use the same instance in multiple places then you will need to pass a reference to that instance around. For many Visual Basic 6.0 programmers, this is a totally new problem; the default instance provided for each form is available to all the code in your project. There are two main ways to handle your form reference(s): either make it globally available or pass it to each form, class, module, or procedure that requires it.

#### Global data in .NET

Earlier I mentioned that global variables are not available in Visual Basic .NET, and now I'm going to tell you how to make something global. How will you ever trust me after this? Actually, I am not being dishonest in either case; global variables are not allowed in Visual Basic .NET, but you can achieve similar functionality using Shared (called static in C#) class members. A Shared class member, as used by the Visual Basic Upgrade Wizard when it adds the DefInstance property to your forms, is available without creating an instance of a class and, if it is a property, its value is shared across your entire application. You could therefore create a class like this:

Public Class myForms
Private Shared m_CustomerForm As CustomerForm
Public Shared Property CustomerForm() As CustomerForm
Get
Return m_CustomerForm
End Get
Set(ByVal Value As CustomerForm)
m_CustomerForm = Value
End Set
End Property
End Class

When you first create an instance of your form you could store it into this class:

Dim myNewCust As New CustomerForm()
myNewCust.Show()
myForms.CustomerForm = myNewCust

After the CustomerForm property has been populated with an instance of your form, you could then use this class to access that same instance from anywhere in your code:

Module DoingStuffWithForms
Sub DoExcitingThings()
myForms.CustomerForm.Text = _
DateTime.Now().ToLongTimeString
End Sub
End Module

Storing your form in this manner comes as close to Visual Basic 6.0's Global variables as you are going to get. The next level of variable scope below this level is class (module, class or form, actually) scope, where a variable is declared within a class and is available to any code in that class, and below that is procedure scope, where a variable is local to a single routine.

As an alternative to making your form global, you could instead keep a reference to the form as a variable in your form or class and then pass that reference to any code that needs access to your form. If you had a form (called Form1 in this example) and you wanted to open a second form (Form2) when a button was clicked, and then do some calculations on this new form in response to another button being clicked, your code could be written within Form1, like this:

Public Class Form1
Inherits System.Windows.Forms.Form
Dim myForm2 As Form2

Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
myForm2 = New Form2()
myForm2.Show()
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
Calculations.CompoundInterestCalc(myForm2)
End Sub
End Class

Public Class Log
Private Shared m_LogForm As Form2
Public Shared Property LogForm() As Form2
Get
Return m_LogForm
End Get
Set(ByVal Value As Form2)
m_LogForm = Value
End Set
End Property

Public Shared Sub WriteToLogWindow(ByVal Message As String)
Dim sb As New _
sb.Append(Environment.NewLine)
sb.Append(Message)
End Sub
End Class

### Getting Information into and out of Forms

Thus far in this article I have covered how to obtain and keep track of a form instance, but I haven't discussed how you would get information into and out of form. If you have a form instance, and if your code and your form are from the same project, you can access the controls on a Form directly, but I don't think that is the best idea. Instead of working with the text boxes, buttons, and other controls on your form, I suggest creating properties that are explicitly made Public and allow you to set and retrieve the values you wish to access. Follow me through a quick example if you wish to try out this method of working with a form:

1. Create a new Windows Application project in Visual Basic .NET.
2. One form, Form1, will be created automatically. Add another by right-clicking your project in the Solution Explorer and selecting Add Windows Form. Accept the default name of Form2.vb and click OK.
3. Add two buttons to Form1, leave them with their default names of Button1 and Button2, and reposition them enough so that they are not overlapping.
4. Add a single text box to Form2, leaving it with the default name of TextBox1.
5. Now add this code to Form2 (by right-clicking Form2 in the Solution Explorer and selecting View Code) immediately before "End Class."
Public Property CustomerName() As String
Get
Return TextBox1.Text
End Get
Set(ByVal Value As String)
TextBox1.Text = Value
End Set
End Property

To do this:

1. View the code for Form1 and add the following line after "Inherits System.Windows.Forms.Form":
Dim myForm2 As New Form2()
2. Double-Click Button1 on Form1 to access the button's Click event handler and enter this code:
myForm2.CustomerName = "Fred"
myForm2.Show()
3. Double-Click Button2 on Form1 and enter this code:
MessageBox.Show(myForm2.CustomerName)
myForm2.CustomerName = "Joe"
4. Run the project (F5), and then click Button1 and Button2 to see the code in action.

Having a CustomerName property might not seem like a big deviation from accessing the text box on Form2 directly, but you gain a few benefits from interacting with your forms in this way. The main benefit is abstraction; you don't have to know anything about the controls on Form2 (there might not even be a text box on it), just set and retrieve the CustomerName property. Having this layer of abstraction allows Form2 to change its implementation without any effect on the rest of your code, making future modifications much easier. In our example, the property-based version wasn't any easier to use, but if you are dealing with a more complex user interface, the code behind your properties could handle all the details while the code to use the form stayed very simple. Of course, one final benefit of this model is less tangible but certainly has value to many developers: Using properties instead of directly accessing the controls is much more elegant and results in code that is easier to understand.

## Conclusion

Visual Basic .NET gets rid of the "default instance" used by forms in earlier versions, and that change can cause a great deal of confusion to those trying to learn how to program in .NET. You need an instance of a form before you can access its properties, methods, or any of its controls, and you need that instance stored in such a way that it is available throughout your code. The .NET system for handling forms is more consistent and more powerful than the system in Visual Basic 6.0, but even changes for the better can cause confusion for those trying to make the transition.

For additional information, see the Visual Studio .NET product documentation topics: Upgrading from Visual Basic 6.0 and Forms Changes in Visual Basic .NET.

• 本文已收录于以下专栏：

举报原因： 您举报文章：Working with Multiple Forms in Visual Basic .NET: Upgrading to .NET 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)