VB.NET学习笔记:窗体显示及互相传值

测试环境:windows 7和Microsoft Visual Studio 2015

很多文章里都说在Visaul Basic .NET中显示窗体之前必须先实例化,经测试,也可以与旧Visual Basic 6.0 一样不经实例化直接Form1.Show显示窗体。

一、正确显示窗体

新建一个窗体应用程序,再添加一个模块和一个窗体。如图:

在项目属性页进行如下图设置。

在模块添加如下代码:

Module Module1
    Public Sub Main()
        'IF语句,符合条件则显示窗体Form1,这里略过直接显示窗体
        Form1.Show()
    End Sub
End Module

测试项目,发现窗体一闪而过,为什么没有长时间显示窗体呢?
在网友uruseibest的热心帮助下才知道应该使用Form1.ShowDialog()将窗体显示为模式对话框。
修改代码如下:

Module Module1
    Public Sub Main()
        'IF语句,符合条件则显示窗体Form1,这里略过直接显示窗体
        Form1.ShowDialog()
    End Sub
End Module

测试项目,代码执行到 Form1.ShowDialog()这句就不再继续向下执行,直到关闭窗体Form1后才往下执行余下代码。
也可以使用Application.Run(Form1)语句代替rm1.ShowDialog()来将窗体显示为模式对话框。
对于旧Visual Basic 6.0程序员来说还是很容易理解的,但作为面向对象编程的Visaul Basic .NET语言,最好先把窗体类给实例化,再显示窗体。即应该是这样:

Module Module1
    Public Sub Main()
        'IF语句,符合条件则显示窗体Form1,这里略过直接显示窗体
        '声明变量
        Dim frm As Form1
        '实例化窗体
        frm = New Form1
        '显示窗体
        frm.ShowDialog()
    End Sub
End Module

二、窗体间互相传值

分别在两个窗体上添加3个按钮和一个Label控件。如图:

为按钮添加事件代码:

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Form2.Show()
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Form2.Label1.Text = "Form2,你好!"
    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        Form2.Label1.Text = ""
    End Sub
End Class
Public Class Form2
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Form1.Label1.Text = "Form1,感谢你!"
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Form1.Label1.Text = ""
    End Sub
End Class

以上代码是按旧Visual Basic 6.0语言编写的,但并没有出现其他文章里所说不实例化就会报错,代码能够执行并很好完成窗体间相互传值的任务。

后续:经多方阅读后了解到,上述是使用窗体的共享方法Show来显示窗体,用于与VB6兼容,但不推荐使用。即:

Form1.Show()

共享方法可以不用先实例化窗体就进行了显示,这样显示的是默认的窗体实例。在包含窗体的项目中的任何地方都可以使用这个默认窗体。默认的窗体实例只有一个,因此任何指向它的引用实际上使用的都是同一个底层窗体实例。

三、测试实例化后再显示和传值

模块代码修改为:

Module Module1
    Public Sub Main()
        'IF语句,符合条件则显示窗体Form1,这里略过直接显示窗体
        '声明变量
        Dim frm As Form1
        '实例化窗体
        frm = New Form1
        '显示窗体
        frm.ShowDialog()
    End Sub
End Module

窗体代码修改为:

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim frm2 As Form2
        frm2 = New Form2
        frm2.Show()
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Dim frm2 As Form2
        frm2 = New Form2
        frm2.Label1.Text = "Form2,你好!"
    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        Dim frm2 As Form2
        frm2 = New Form2
        frm2.Label1.Text = ""
    End Sub
End Class

测试一下项目,点击Button1可以正确显示窗体 Form2,可是Button2和Button3却无法向Form1传值,是不是也要加一句frm2.Show()?试试看!

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Dim frm2 As Form2
        frm2 = New Form2
        frm2.Label1.Text = "Form2,你好!"
        frm2.Show()
    End Sub

测试项目,可以传值了,只是并不是向原来的Form1传值,而程序反而又蹦出了一个Form1,再点一次按钮又蹦出一个Form1,再点再蹦……,如图:

原来窗体其实是一个类,一个类可以实例化成多个对象,我们两个按钮就生成了两个Form1窗体对象了,看来还是Visual Basic 6.0语言好理解。什么是类?笔者在这里暂不过多解释!
怎么办?在网友uruseibest的博文里发现,可以这样处理:

1、保持窗体引用的全局性

在访问窗体之前,最好进行窗体实例化,如果在项目中有多处代码访问同一窗体,可以把它的同一实例指针传递给这些代码,即把窗体实例指针保存在全局变量中。
模块代码再次修改:

Module Module1
    '声明一个全局变量
    Public frm1 As Form1
    Public Sub Main()
        'IF语句,符合条件则显示窗体Form1,这里略过直接显示窗体
        frm1 = New Form1
        frm1.ShowDialog()
    End Sub
End Module

窗体Form1代码修改为:

Public Class Form1
    Private frm2 As Form2

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        '加载窗体时实例化
        frm2 = New Form2
    End Sub
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        frm2.Show()
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        frm2.Label1.Text = "Form2,你好!"
        frm2.Show()
    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        frm2.Label1.Text = ""
        frm2.Show()
    End Sub
End Class

窗体Form2代码修改为:

Public Class Form2
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        frm1.Label1.Text = "Form1,感谢你!"
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        frm1.Label1.Text = ""
    End Sub
End Class

OK,现在可以正确传值了,测试结果如图:

2、重写窗体构造函数

什么是重写?就是不要原来的无参数构造函数了,改成自己写的带参数构造函数。
回到Form2窗体的代码窗口,输入:Public Sub new,按回车,即可添加如下代码:

Public Sub New()

        ' 此调用是设计器所必需的。
        InitializeComponent()

        ' 在 InitializeComponent() 调用之后添加任何初始化。

    End Sub

这个是窗体默认的无参数构造函数,现在我们重写一个有参数的构造函数。如下代码:

Private Frm1 As Form1
    Public Sub New(ByVal frm As Form1)
        MyBase.New()
       ' 此调用是设计器所必需的。
        InitializeComponent()

        ' 在 InitializeComponent() 调用之后添加任何初始化。
        Me.Frm1 = frm
    End Sub

这里传入的参数是一个对象,即Form1窗体,当然你也可以把参数改成字符串等其他数据类型。
现在,就可以通过重写的构造函数把Form1对象传入Form2中,在Form2中直接使用变量Frm1就是Form1窗体啦。
然后到Form1代码窗口,修改实例化Form2的代码为:

Frm2 = New Form2(Me)

原来是不带参数的,因为上面已经修改了Form2的构造函数,所以此时实例化Form2时不再调用默认构造函数,而是需要我们指明参数再实例化。
这里的Me指的就是Form1当前的实例,也就是把当前Form1的实例通过Form2的构造函数传递给Form2类。
完整代码如下:
模块代码:

Module Module1
    '声明一个全局变量
    Public frm1 As Form1
    Public Sub Main()
        'IF语句,符合条件则显示窗体Form1,这里略过直接显示窗体
        frm1 = New Form1
        frm1.ShowDialog()
    End Sub
End Module

Form1代码:

Public Class Form1
    Private frm2 As Form2
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        '加载窗体时实例化
        Frm2 = New Form2(Me)
    End Sub
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        frm2.Show()
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        frm2.Label1.Text = "Form2,你好!"
        frm2.Show()
    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        frm2.Label1.Text = ""
        frm2.Show()
    End Sub
End Class

Form2代码:

Public Class Form2
    Private Frm1 As Form1
    Public Sub New(ByVal frm As Form1)
        MyBase.New()
        ' 此调用是设计器所必需的。
        InitializeComponent()

        ' 在 InitializeComponent() 调用之后添加任何初始化。
        Me.Frm1 = frm
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Frm1.Label1.Text = "Form1,感谢你!"
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Frm1.Label1.Text = ""
    End Sub
End Class

经测试,正确实现相互传值。
还有说使用委托机制,笔者没有测试,感兴趣的你也可以查阅相关博文了解了解。

四、迷惑

不用实例化就可以很方便的调用窗体和向窗体传值,为什么Visaul Basic .NET要如此多事,非要整个实例化才显得更高大上吗?就因为是面向对象编程?那为什么还可以象旧Visual Basic 6.0 那样不实例化调用窗体呢?

更多阅读:再谈WinForm窗体间相互传值(单值、多值)——属性、委托和事件

本文参考了以下博文:
1、vb.net 教程 3-2 窗体编程之窗体 5
2、vb.net 教程 3-2 窗体编程之窗体 4
3、如何在窗体之间通讯的几种方法 ? VB.NET方案
4、vb.net的多窗体操作

(0)

相关推荐