第十三章:
Visual Basic.NET组件开发知识点:
组件开发的概念
COM与,NET的互操作组件开发实例软件工程一个重要的概念就是复用,相信大多数程序员都有这样的体验,
很多时候都是在写大量重复的代码,甚至很多时候把以前一些项目中的代码直接 Copy过来用,这部分代码就是可以重用的代码,在一些情况下,将这部分代码以组件的形式封装起来,在需要的时候直接调用,可以大大提高工作效率,而且使用一些开源的组件,利用人家写好的优秀的模块,也可以省去不少麻烦,所以,组件开发是现代软件工程学中不可缺少的一部分,本章将从组件开发的基本概念出发讲解组件开发的一些要点以及,NET组件以往的
COM组件的互操作问题,最后通过一个实例来向大家展示组件开发的魅力。
13.1 组件开发概述微软 NET应用程序是从组件开始构建的。所有 NET对象通过接口提供其重要的特性,如属性、方法和事件。这些特性构成了面向对象编程的基础。作为
VisuaI Baslc,Net组件对象的程序设计师,要负责实现必需的接口(即属性、
方法和事件),其他程序员通过这些接口引用组件对象所提供的服务。因此,
开发组件的大部分精力将用于设计对象,定义所开发组件被调用的接口。一般情况下,简单的,NET面向对象的编程都将涉及到创建类,添加类所需要的属性、方法和事件,并将这个类包含在不同的应用程序中。在,NET中创建组件同样是基于面向对象的原则,但它们超出了可以在多个应用程序中使用的简单类的概念。
通常定义组件为可交换的软件部分,它是工业化系统的产物,在,NET平台的组件层中,组件是以 Assemblies的形式存在的,可以用任何,NET支持的语言来开发组件,作为一个软件部件而不是整体,组件常常以插接的形式来开发,通过接口来实现与其他程序的互操作。服务化组件是这中间的一类特殊的组件,与,NET中标准的可管理组件不同的是这类组件使用了 COM服务。
下面通过一个简单实例,介绍,Net组件的创建于与使用:
首先新建一个,windows控件库”项目,命名为,TextChange”,如图所示在集成环境中自动生成可添加控件的容器,如图所示把 UserControl1.vb改为 TextChange.vb,也就是生成的控件名为 TextChange。
再来看自动生成的代码框架。
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class textchange
Inherits System.Windows.Forms.UserControl
'UserControl1 重写 Dispose,以清理组件列表。
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
MyBase.Dispose(disposing)
End Sub
'Windows 窗体设计器所必需的
Private components As System.ComponentModel.IContainer
'注意:以下过程是 Windows 窗体设计器所必需的
'可以使用 Windows 窗体设计器修改它。
'不要使用代码编辑器修改它。
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
components = New System.ComponentModel.Container()
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
End Sub
End Class
说明:
a.Inherits
System.Win
dows.Form
s.UserContr
ol代表
TextChang
e类继承
System.Win
dows.Form
s.UserContr
ol类。
b.必须实现
dispose方法。
添加一个 Textbox控件和一个 timer控件,如图所示通过 TextChange.Design.vb可看到代码中自动创建和初始化了 txtmsg和 timer1控件。
在所有方法外面定义如下变量。
Dim x,y,As Integer ‘设置控件的左上角坐标
Dim flag As Boolean = True '方向朝左实现 Timer1_Tick事件
Private Sub Timer1_Tick(ByVal sender As System.Object,ByVal e _
As System.EventArgs) Handles Timer1.Tick
If flag = True Then ' 左移
x -= 1
txtmsg.Location = New Point(x,y)
If (Integer.Parse(txtmsg.Left) <= 0) Then
flag = False
End If
Else
x += 1
txtmsg.Location = New Point(x,y)
If (Integer.Parse(txtmsg.Left) + Integer.Parse(txtmsg.Width) >=
Integer.Parse(Me.Width)) Then
flag = True '左移
End If
End If
End Sub Timer1控件的 Interval属性设为 10,也就是 Timer1控件启动后,每隔 0.01
秒会自动执行 Timer1_Tick事件内的代码一次,txtmsg先左移,每次左移
1Pixel,边检查是否碰到左边缘。若是,则将 flag设为 false,改为右移,
同时检查是否碰到右边缘,若是,将 flag设为 true,再次左移。
至此,已经将 TextChange控件设置完毕,下一步是生成,dll文件。
右键单击 TextChange项目,选择“生成”命令,便会在项目的 bin目录下生成
TextChange.dll文件,如图所示。
接下来,在 VB.Net应用程序中使用自创建的 TextChange控件:
执行 【 文件 】 |【 添加 】 |【 项目 】 命令,创建,windows 应用程序”。
执行 【 工具 】 |【 选择工具箱项 】,选定 FrameWork选项卡,如图所示。
单击“浏览”按钮,选中刚才创建的 TextChange.dll文件,单击“确定”按扭,
如图所示。
此时工具箱中便会出现 Textchange控件,如图所示将此控件拖入 Windows窗体,便可像其他,NET
控件一样使用
13.2 在 Visual Basic NET中构造组件
13.2.1 进程内组件在 NET中,作为 DLLs构建的组件运行在宿主应用程序的进程空间中,
并与宿主应用程序共享内存和处理器时间。在运行时刻,组件(它是宿主应用程序部件的一部分,并通过它的列表( manifest)引用)从磁盘上装入,并加入到宿主应用程序的进程空间中。因为并没有为组件与它的宿主间的通信生成远程过程调用,所以设置和读取属性值,调用方法,
对该组件产生的事件做出反应,这些过程都发生得相当快。
13.2.2 进程外组件另一种结构涉及了在客户应用程序进程空间外作为独立进程运行的服务器应用程序。这些服务器应用程序通常具有,EXE扩展名。当 Windows将进程外组件装入内存时,就要为该组件创建独立的进程空间,并且 Windows独立于客户应用程序管理进程外组件的资源要求。 Wlndows通过在服务器应用程序与客户间传递消息,来协商它们之间的对话。
Visual Basic NET与 Visual Basic 6.0相比在运行进程内组件与进程外组件时具有相当的区别。在某种情况下,进程外应用程序要比进程内组件构建的应用程序稳定。如果进程外组件崩溃了,它不会使客户应用程序崩溃。如果进程内组件停止了运行,那么经常是它的客户应用程序也崩溃。进程外组件易于在多个消费者应用程序中共享。当作为共享资源编译时,windows将进程外组件的单个拷贝装入内存,并使它可被所有请求它的消费者访问得到,然而,如果组件同时被许多客户端请求,将使性能严重下降。
13.2.3,NET类和组件初学者往往弄不清楚类和组件的区别。
实际上,类和组件几乎可以互用,但它们有一些区别。
组件与常规的类没有什么不同,但它支持 VB.NET IDE中的图形设计器。这就意味着,可以采用拖放操作来提供组件中的代码。
从具体操作可以看出,通过简单的拖放操作,就能对引用 Timer对象的
theTimer变量进行访问,还能创建可以与该对象交互作用并使用该对象的方法,
这与把控件拖放至窗体中很相似。在很大程度上,组件和基类可以互用,但使用组件会导致额外的开销,而基类却不会。
13.2.4 COM组件与,NET组件
VB.NET和 C#一样也没有只属于自己的类库,它们使用的类库都是,Net
FrameWork SDK,在此类库中封装许多类,VB.NET就是通过这些类来突破自身语言的限制,实现很多强大功能的。其实对于,Net的编程语言来说,使用 VB.NET来编写程序或者使用 C#编程,已经没有象以前使用 VB和 C++之间有那么大的区别了,因为一般来说只要用 C#能够实现的功能,同样用 VB.NET也可以实现,有时使用
VB.NET还显得更为方便;虽然,Net FrameWork SDK的内容十分丰富,功能也十分强大,但有些功能使用此类库来实现就显得有点麻烦,因为在 Windows里面拥有许多 COM组件,充分利用这些已经存在的资源,对于快速开发程序就显得非常重要。
前面讲到 COM组件和,Net组件可以互用。
在,Net中使用 COM组件
VB.NET和 C#一样,不能直接使用已经存在的 COM组件,这是因为编译
VB.NET和 C#的文件的时候,必须保证编译时候所使用的文件是由受管代码
( Managed Code)文件,知道 VB.NET和 C#所使用的,Net FrameWork SDK都是受管代码,而对于那些 COM组件来说,它们都是非受管代码( Unmanaged Code),
所以这些 COM组件要能够被 VB.NET和 C#使用,必须实现自身从非受管代码到受管代码的转换。在,Net框架中提供了一个程序来专门实现这种转换,这个文件就是
,Aximp.exe”,如果你把,Net FrameWork SDK安装在,C”盘,那么在,C:\Program
Files\Microsoft Visual 8\SDK\v2.0\Bin”目录中,就可以找到这个文件。
13.3 从 COM组件调用,NET组件尽管 COM客户端可以调用由,NET服务器在公共类中公开的代码,但是 COM
客户端不能直接访问,NET代码。为了能从 COM客户端使用,NET代码,需要创建一个称为 COM可调用包装( CCW)的代理。
在创建供 COM客户端使用的,NET类时,请记住两个前提条件:
要在 Visual Basic,NET代码中明确定义一个接口,并让类实现该接口。
COM客户端可见的任何类都必须是已声明的公共类。
创建,Net组件,并通过强名工具进行签名注册:
sn –k sample.snk 将创建一个新的密钥文件
13.4 组件开发案例使用功能强大的 Visual Basic,NET编写各种类型的可视控件。不仅可以编写复合的 UserControl,还能继承现有的控件(如 TextBox)并扩展其新功能。更重要的是,还可以从头编写能够呈现其特有界面的可视控件。
在下面这个例中,将从头创建一个完整的可视控件,以说明 Visual
Basic,NET的后一种功能。该控件包含两个密码输入框,用在更改密码的场景中,控件可以设置密码的最大长度,可以设置安全强度,当密码和确认密码的是输入相同的时候,下一步才可用,Label11会显示相关的信息,
例如密码强度是否符合要求等,设计图如图所示。
下面从头开始来完成这个控件的开发
13.4.1 创建类型正确的项目打开 Microsoft Visual Studio,执行 【 文件 】 |【 新建项目 】 命令,在项目新建对话框中选择 【 Visual Basic】 |【 Windows】 |【 Windows控件库 】,输入项目名称,这样就建立了一个用户控件项目,如图所示。
13.4.2 设计界面从工具箱中拖放如下几个控件到界面上,两个 TextBox,一个 Button,3个 Label,
按如图所示放置:
13.4.3 设计属性为了在使用该控件的时候能够在设计器里面设置控件的一些变量,将这些变量封装成该控件类的属性,涉及的变量有密码的长度和强度,在控件上右击,选择查看代码,添加如下代码:
<System.ComponentModel.Description("设置或获取密码的最大长度,范围为 0-
20")> _
Private _length As Integer = 20
Private _strength As Integer = 3
Public Property Length() As Integer
Get
Return _length
End Get
Set(ByVal value As Integer)
If value > 20 Or value < 3 Then
Throw New Exception("密码长度为 -20")
End If
_length = value
txtPwd1.MaxLength = value
txtPwd2.MaxLength = value
End Set
End Property
<System.ComponentModel.Description("设置或获取密码强度,分为,2,3三个等级,强度依次递增 ")> _
Public Property Strength() As Integer
Get
Return _strength
End Get
Set(ByVal value As Integer)
If value > 3 Then
Throw New Exception("密码强度分为个级别,为,2,3")
End If
_strength = value
End Set
End Property
13.4.4 设置 TextBox的密码字符属性在默认情况下,TextBox将会显示键入的字符,因此设置 TextBox的
PasswordChar属性来使 TextBox在接收到字符的时候不显示键入的字符,而显示指定的字符,*”,进行如图 13-14所示的设置。
13.4.5 添加事件处理程序每当用户更改密码框内的数据的时候,系统就做出一系列合法性验证来确定密码是否符合要求、已经密码确认和密码的值是否一样,当所有的合法性验证都通过后,使“下一步”的按钮可用,否则使该按钮不可用。为了完成这些功能,txtPwd1,txtPwd这两个文本框控件的 TextChanged事件添加处理函数,添加如下代码:
Private Sub pwd1_TextChanged(ByVal sender As System.Object,ByVal e As
System.EventArgs) Handles txtPwd1.TextChanged
check()
End Sub
Private Sub pwd2_TextChanged(ByVal sender As System.Object,ByVal e As
System.EventArgs) Handles txtPwd2.TextChanged
check()
End Sub
Private Sub check()
btnNext.Enabled = False
Dim pwd1 As String = txtPwd1.Text
Dim pwd2 As String = txtPwd2.Text
If pwd1.Length < 3 Then
labStatus.Text = "密码长度太短! "
Return
End If
If checkStrength(pwd1) < _strength Then
labStatus.Text = "密码强度太低! "
Return
End If
If pwd1 <> pwd2 Then
labStatus.Text = "两次输入的密码不一致! "
Return
End If
btnNext.Enabled = True
End Sub
Private Function checkStrength(ByVal pwd As String) As Integer
Dim charset() As Char = ("=+-_)(*&^%$#@!~`\|]}[{'"";:/?.>,<").ToCharArray
If pwd.Length < 6 Then
Return 1
End If
If pwd.Length > 14 Then
Dim i As Integer
For i = 1 To pwd.Length
If Array.IndexOf(charset,pwd(i - 1)) <> -1 Then
Return 3
End If
Next
End If
Return 2
End Function
在这段代码中定义了一个检测密码强度的函数 checkStrength来判断传入的密码字符串的强度,判断的规则是当密码的长度小于 6时强度为 1,当密码的长度大于 14
并且包含至少一个特殊字符的时候强度为 3,其他情况强度为 2,当然,你也可以自己定制你自己的强度判断函数。在 txtPwd1和 txtPwd2的 TextChanged事件中调用
check函数来进行合法性验证,当长度小于 3、密码强度不符合设定值或者密码和密码确认不一致的时候做出提示,而当通过了这些验证的时候,使“下一步”按钮可用。
13.4.6 生成和测试控件在解决方案资源管理器中右击项目,选择“生成”选项,这样编译器就在项目的 bin文件夹下生成了一个 dll文件,如图所示。
下面新建一个 Windows窗体项目并将这个控件添加到 Visual Stdio 2005的工具箱中,这次将建立一个 C#的项目,建立项目后在右击工具箱,选择“选择项”,
如下图所示。
在弹出的工具选择框里面点浏览,选择刚才生成的 dll文件,点确定后工具箱中会多一个控件,如上右图所示。
将控件拖到窗体设计器中,效果如图所示。
右击该控件,选择属性,在属性设置页里面可以看见 Strength和 Length属性,
如图所示,通过设置 Strength属性可以设置控件工作是允许通过的密码的密码强度,例如设置为 2的时候,只有密码的强度大于等于 2的时候才被允许,而
Length属性可以设置密码的最大长度,默认是 20,如果设置成 15,文本框中就只能输入 15个字符。
运行效果如图所示。