** Henry 手记- VB.net WinForm 中的 FORM 初探(二) **
韩睿 (2002.9.25)
二、怎么样切换两个窗体?
在上一节中,我们认识到 vb.net 窗体的新特性,也知道了怎么样 show 出一个窗体了。那么面对一个这样的需求(也是真实的提得较多的问题)。怎么样实现两个窗口间的切换。即:
窗体一: Form1, 上面有个 button1
窗体一: Form2, 上面有个 button2
点击 button1 ,会 show 出 Form2 ;点击 button2 ,会 show 出 Form1 。
如果在 vb6 中,我们还真不用费工夫写文章来讨论了 //hehe 。上一节中我们讨论的是 Visual Basic .NET 与 Visual Basic6 在窗体处理机制上的关键区别 —— 你只有先创建窗体实例,然后才可以显示窗体外观、访问窗体属性及其控件。
这节中讨论的是另一个区别: Visual Basic 6.0 项目自动创建的默认窗体实例都能被当成全局变量使用,也就是说,项目中的任何代码都能直接引用窗体,并且每次被引用的都是该窗体的同一个实例。 Vb.net 呢?是不能这样做了。
我们先来做个小实验,来加深类与对象的概念。
你在一个窗体 frmMain 里,放四个按钮,在每个按钮的 click 事件里写上:
dim frm1 as new form1
frm1.show
那么,你将会看到四个一模一样的 form1 。
明白了吧?但此 form1 非彼 form1 ,都是 form1 类的一个个实例化的内容。
所以我们不能指望在调用的时候,命名一个局部的 frm1 就能一直都对 form1 的实例进行控制,这是不可能的。
也就是说,在 button1 的 click 事件中写:
dim frm2 as new form2
frm2.show
me.hide
在 button2 的 click 事件中写:
dim frm1 as new form1
frm1.show
me.hide
是有问题的,你发现问题在哪了吗?就在于 click 事件中写的都是局部变量,每一次都会新生成一个 Form 的实例,而 hide 起来的那个 form 的实例却再也 show 不回来了。如果不在 form 的 closing (关闭时触发)或其它类似事件中做任何处理,该程序的进程是不会停止的,这是由于做为主线程的第一个 form1 是被 hide 起来了,它还在运行着,进程当然不会终止喽。
解决方法有很多,比如
在 module 中定义 Form 的全局变量
用 share 变量模拟 vb6 中窗体切换的实现
一个一个说明一下吧,希望对朋友们有所启发:
在 module 中定义 Form 的全局变量
给程序工程加一个模块,用于存放公用变量,及启动控制用:
'Module1.vb
Module Module1
Public F1 As New Form1() ‘定义Form1的公用变量实例
Public F2 As New Form2() ‘定义Form1的公用变量实例
Sub Main()
Application.Run(F1) ‘这句话表明程序启动了modele后,会接下来启动f1,即form1的一个实例
End Sub
End Module
'Form1.vb
Class Form1
...
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
F2.Show() '利用公用变量
F1.hide()
End Sub
End Class
'Form2.vb
Class Form2
...
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
F1.Show()
F2.Hide()
End Sub
End Class
同时请在:解决方案管理器-〉windowsapplication1.sln -〉右点鼠标 -〉属性 -〉通用属性->常规->启动对象 -〉改为Module1
上面最后一句话的意思是让程序在启动时先执行 Module1 中的代码。初始化两个 Form 的公用变量,进程入口在它的 sub main ,用于启动 F1 ( Form1 的实例)。用这个方法,我们可以完成很多窗体间控件控制(比如 Form1 上的操作结果显示到 Form2 的文本框中去)和数据传递。在这里要注意的是,只有关闭了 F1 窗体,程序才会被终止。我们可以做一些处理,比如在 Form 的 closing 事件里加入 end 等等。
但在 vb.net 中其实是不赞成使用公用变量的,一是由于生存期的管理,二是引用时的混乱问题。那么我们还有没有其它的解决方法?
- 用 share 变量模拟 vb6 中窗体切换的实现
其实有个最简单但是极有用的方法,不知道您想到了吗?就是利用 vb.net 自带的升级向导工具进行升级呀! ( 尽管很多人骂这个工具不行,但有的工作它还是可以做得很好的 )
我就这样做了,先在 vb6 中写了两个 Form ,
Form1:
Private Sub Command1_Click()
Form2.Show
Me.Hide
End Sub
Private Sub Form_Unload(Cancel As Integer)
End ’ 关闭 Form1 ,程序结束
End Sub
Fomr2:
Private Sub Command2_Click()
Form1.Show
Me.Hide
End Sub
Private Sub Form_Unload(Cancel As Integer)
Form1.Show 关闭 Form2 ,唤出 Form1
End Sub
升级后,多了一组用 Region 折起来的“升级支持”
Form1:
Region " 升级支持 "
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
m_vb6FormDefInstance = Value
End Set
End Property
End Region
Private Sub Command1_Click( ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Command1.Click
Form2.DefInstance.Show()
Me .Hide()
End Sub
Private Sub Form1_Closed( ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase .Closed
End
End Sub
在 Form2 中,除了升级支持外的代码是:
Private Sub Command2_Click( ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Command1.Click
Form1.DefInstance.Show()
Me .Hide()
End Sub
Private Sub Form2_Closed( ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase .Closed
Form1.DefInstance.Show()
End Sub
在上面的代码中,要注意的是是用 Form1.DefInstance.Show() 来 show 出 Form1 的一个实例。 DefInstance 是 Shared 的属性,它能以 “ 窗体名 .DefInstance” 的形式直接访问。它所在项目中的任何代码访问它都将得到同一个窗体实例。
这样,我们就能模拟 vb6 完成的项目对窗体的直接引用了,只不过在代码中以 Form1.DefInstance 代替 Form1 而已。如果要设置窗体上的一个 label 的内容,现在是这样用了: Form1.DefInstance.Label1.text=”Henry”
我们完全可以 copy 下“升级支持”这一段代码,然后注意我上两段写的内容,就可以不用升级工具,而自己动手写了。
----
声明:本文版权与解释权归韩睿所有,如需转载,请保留完整的内容及此声明。
QQ: 18349592