Henry手记-VB.net WinForm中的FORM初探(一)
韩睿(2002.9.25)
经常有网友在我主持的版面上发贴子或写信直接来问我,为什么vb.net和vb6差了这么多。当然,问得最多的就是关于窗体的调用,这也是一个与vb6相比,vb.net具有的变化最大的特征—面向对象(限于篇幅,有关面向对象的基本内容请参看面向对象的书籍)。当有朋友大喊vb.net怎么这么这么……(此处删去两字)时,我只得劝他再忍一下,再深入一点,痛过之后的快意会让他理解更美的世界。
一起开始我们今天的历程吧。对于从vb学起,没有经过C++与Java考验的朋友来说,可能会稍微麻烦一点,有问题请跟我联系吧。
一、为什么我的FormShow不出来了?
是不是微软忙晕了?忘了有人有用两个form的需求?当然不可能,if是忘了,那微软就真是疲软了。
曾记否,在vb中想在Form1中调出Form2时是如何的酣畅淋漓:
Form2.show (不讨论模式问题)
但是,在vb.net中再写form2打一点后,出来的属性框中居然没有我们料想中的show了!
原因:Visual Basic .NET 取消了早期版本中的“默认窗体实例”,并且规定,只有通过引用窗体实例,才能访问窗体的属性、方法及其控件。
原来是这样,在vb.net中窗体也变成了一个类!我们来剖析一下一个窗体的生成代码吧。请用vb.net建立一个Form:Form3。然后看一下代码并一句一句分析一下:紫色的注释是我加的,绿色的是系统自带的。
Public Class Form3 ‘类的定义方法
Inherits System.Windows.Forms.Form‘告诉我们此类是继承自何处
#Region " Windows窗体生成的代码” ‘#Region指令用于折叠并隐藏 Visual Basic .NET 文件中的代码节。通过这一方法可以更好地规划与书写我们的代码了。
Public Sub New()‘类的构造
MyBase.New()‘用于从派生类构造函数中显式调用基类构造函数。这个等会还会说明。
'该调用是 Windows 窗体设计器所必需的。
InitializeComponent()‘如果你的初始化代码有很多行,你可以建立一个子过程来管理这些代码,子过程的名字就是InitializeComponent()。见后面。
'在 InitializeComponent() 调用之后添加任何初始化
End Sub
'窗体重写处置以清理组件列表。
‘Overloads 关键字用与现有成员相同的名称来声明属性或方法,但参数列表与原始成员不同。Overrides 关键字指定属性或方法将重写从基类继承的成员。这个问题不是很清楚,请查一下面向对象的书中重载与继承的相关内容。笔者计划几天后有空会写一篇《vb.net的继承与接口》,界时会更详细地进行描述。
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
’类的析构
If disposing Then
If Not (components Is Nothing) Then‘清除组件列表中的内容
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Windows窗体所必需的
Private components As System.ComponentModel.IContainer
‘System.ComponentModel 命名空间提供用于实现组件和控件运行时和设计时行为的类。Icontainer接口提供容器的功能。容器是在逻辑上包含零个或更多个组件的对象。也就是说通过这样的定义,components就成为了可包容当前窗口所有组件的容器了。
'注意:以下过程是 Windows 窗体设计器所必需的
'可以使用 Windows 窗体设计器修改此过程。
'不要使用代码编辑器修改它。
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
‘在vb.net中用< >表示特性。能完成一些系统提供的独特功能。
'Form3以下定义的是初始化窗口的属性内容
Me.AutoScaleBaseSize = New System.Drawing.Size(6, 14)
‘AutoScaleBaseSize 属性的值在窗体显示时使用,用来计算该窗体的缩放因子。窗体将自动缩放基大小用作与系统的字体大小进行比较的基准,以确定使用自动缩放时窗体的缩放量。
Me.ClientSize = New System.Drawing.Size(336, 309)
Me.Name = "Form3"
Me.Text = "Form3"
‘用户在窗体上布局控件时,控件的初始化属性也是写在这里的
End Sub
#End Region
End Class
这里补充说明一下MyBase关键字的作用与意义:
MyBase 关键字的行为类似于引用类的当前实例的基类的对象变量。MyBase 常用于访问在派生类中被重写或隐藏的基类成员。
在上述代码中,MyBase指的当然就是System.Windows.Forms.Form类了。
从而我们可以知道,在sub new中声明的mybase.new意图在于在form3构造时继承下System.Windows.Forms.Form类的初始化内容。同样的MyBase.dispose的作用在于利用基类System.Windows.Forms.Form的析构方法来进行析构。
总结一下,现在的窗体是一个确确实实的类了,我们应该换个眼光来看待vb.net中的form了。忘掉那个vb中的form用法吧,它只不过是System.Windows.Forms.Form类的一个实例呀。
那么,回到开头的问题,怎么样来在vb.net中实现在Form1中调用Form2的功能呢?只要把类引用到实例就可以了:
Dim frm2 As New Form2() ‘定义Form2类的一个实例
frm2.Show()‘通过实例去调用类的方法,同样不讨论模式问题
是不是很简单,那么我再简单引申一下,当我们声明frm2时用到了New,自然是利用form2类中的sub new来构造这个frm2。那么我们在哪里来调用dispose来析构new出来的frm2呢?
Form.Dispose方法是重写自Control.Dispose方法的,那么Control.Dispose方法的含义又是怎么样的?它的作用就是:释放由Control占用的非托管资源,还可以另外再释放托管资源。当它参数中的[Visual Basic]
disposing 为 true 则释放托管资源和非托管资源;为 false 则仅释放非托管资源。 Form类的disposing为true。
在关闭窗体时自动调用dispose的功能是得益于.net的公共语言运行库,运行库自动处理对象布局和管理对对象的引用,当不再使用对象时释放它们。其生存期以这种方式来管理的对象称为托管数据。自动内存管理消除了内存泄漏以及其他一些常见的编程错误。当然它也不是万能的,这不是本文讨论的重点,先按下不表。
任何类型的 Dispose 方法都应该释放它拥有的所有资源。它还应该通过调用其父类型的 Dispose 方法释放其基类型拥有的所有资源。该父类型的 Dispose 方法应该释放它拥有的所有资源并同样也调用其父类型的 Dispose 方法,从而在整个基类型层次结构中传播该模式。要确保始终正确地清理资源,Dispose 方法应该可以被多次安全调用而不引发任何异常。
当我们关闭一个窗口的时候,会发出一个终止响应,并将该窗口对象(就象上面定义的frm2)送入终止队列,公共语言运行库的垃圾回收器跟踪着这个对象的生存期,此时就会调用此对象基类(比如Form2)的Dispose方法,用于销毁对象并收回资源。
如果通过Dispose还释放不干净或没有调用Dispose,系统的垃圾回收器会调用对象的 Finalize 方法进行清除。由于执行 Finalize 方法会大大减损性能,所以我们不会一开始就用它去进行清除工作。
通过这一小节,希望您已经建立起一个概念,vb.net中连窗口都成了一个实实在在的类,而且提供了一整套完整的类的解决方案,一改vb6中不能实现类继承的缺陷。下一节中,我们将开始进行多窗体编程的讨论。
----
声明:本文版权与解释权归韩睿所有,如需转载,请保留完整的内容及此声明。
QQ: 18349592