教程中国
PHOTOSHOP CS9.0中文版 MAYA 8.5 FOR WINDOWS Corel Painter v9.0 Flash MX2004 中文版 Illustrator cs2 中文版
VC++6.0含sp6 中英文版 VB6.0 +sp6 简体中文版 Borland Delphi 7汉化版 MSDN for vb6.0中文版 Visual Studio 2005简体
教程中国下属 文件存储共享专家BIBIDU.COM 提供大型软件,教材,源码,电影,音乐,图书等下载 更多精品请点此进入
  您目前所在位置: 教程中国 >> .NET类 >> VB.NET >> Visual Basic .NET 中动态加载类 RSS订阅
Visual Basic .NET 中动态加载类
教程(视频,书籍)下载:  ASP.NET AutoCAD 数据库 C# ASP java photoshop 网页设计 delphi 3dmax Flash C++ VB 张孝祥 实例   更多请进入BIBIDU搜索
IT搜索引擎   
摘要:理想情况下,编写软件系统之前我们就应该知道此软件系统需要完成哪些操作。但实际情况并非如此,因此我们的系统应该是可以调整的。

  最能体现这种适应性的是动态集成新功能的能力。例如,在 Windows 窗体应用程序中,这种能力是指加载编译原始应用程序很久以后创建的窗体的能力。

  这种操作在 Microsoft Visual Basic® 6.0 中几乎是不可能的,但是在 Visual Basic .NET 中却相当容易。利用 System.Reflection 命名空间的功能,程序只需知道程序集的位置即可请求动态加载该程序集。然后即可加载该程序集中的类并对类进行实例化。由于 Windows 窗体也是一种类,这就意味着可以动态地加载、显示和使用窗体,即使在编译原始程序时窗体并不存在。

  典型的方案

  假设我们有一个多文档界面 (MDI) 应用程序,需要具有将任意窗体加载为子窗体的能力。那么应用程序应该能够执行以下操作:

  • 获取可以加载的窗体的列表,通常不在 .NET 配置文件中。
  • 显示该列表并允许用户从中选择一个窗体。
  • 实例化并显示用户选择的窗体。

  让我们编写这样一个应用程序,看看如何完成动态加载。

  步骤 1:创建项目和 MDI 窗体

  启动一个新的 Windows 窗体项目。将其命名为 FormsOnTheFly。在新项目中包含的空窗体 Form1 中,将它的 IsMdiContainer &&属性更改为 True。这样,该窗体即变成一个 MDI 父窗体。更改窗体的大小,使窗体的长和宽的尺寸大约为默认值的两倍。

  将一个面板控件拖动到窗体上,然后设置它的 Dock &&属性,使它靠接在窗体的顶部。更改面板的大小,使它的高度大约为 0.5 英寸。

  将一个组合框拖动到面板上。将它命名为 cboForms,然后将它的 DropDownStyle 设置为 DropDownList

  最后,将一个按钮拖动到面板上。将它命名为 btnLoadForm,然后将它的 Text &&属性设置为 Load Form

  此时,Form1 应如图 1 所示。

图 1:添加所有控件后处于设计模式下的 MDI 窗体

  步骤 2:生成一个类,以存放可用窗体的数据

  我们将获取可能从基于 XML 的配置文件之外加载的窗体的有关信息。但是,为了更便于在组合框中显示可用窗体并获取有关所选窗体的信息,还应建立一个对象集合。集合中的每个对象都将存放一个可用窗体的信息。对象应具有以下&&属性:

  • Description:显示在组合框中的窗体说明。
  • Location:窗体所在的 DLL 的文件名。
  • Type:窗体的 .NET 类型的名称(例如,MyProject.Form1)。

  这样的集合可以数据绑定到列表框中。要从列表框中返回对所选对象的引用,还需要一个&&属性,我们称之为 Reference

 要创建类,请选择 Project | Add Class(项目|添加类),然后将类命名为 DynamicClass.vb。在类中添加以下代码:

Public Class DynamicClass

Dim msLocation As String
Dim msType As String
Dim msDescription As String

Public Sub New(ByVal sLocation As String, _
ByVal sDescription As String, _
ByVal sType As String)
Me.Location = sLocation
Me.Description = sDescription
Me.Type = sType
End Sub

Public Property Location() As String
Get
Return msLocation
End Get
Set(ByVal Value As String)
msLocation = Value
End Set
End Property

Public Property Type() As String
Get
Return msType
End Get
Set(ByVal Value As String)
msType = Value
End Set
End Property

Public Property Description() As String
Get
Return msDescription
End Get
Set(ByVal Value As String)
msDescription = Value
End Set
End Property

Public ReadOnly Property Reference() As Object
Get
Return Me
End Get
End Property
End Class


  步骤 3:创建配置文件以存放可用窗体

  应用程序在运行时需要的某些信息可能在编译时无法提供,这些信息通常放置在配置文件中。在 Visual Basic 6.0 中,配置文件应该是 INI 文件或 Windows 注册表。而在 .NET 中,则使用基于 XML 的配置文件。

  我们无法详细介绍配置文件,因为这个主题非常复杂。但是,您应该知道,Windows 窗体应用程序的配置文件与应用程序的 EXE 启动文件在同一个目录中。配置文件的名称与程序的 EXE 启动文件的名称相同,只不过在 EXE 文件名后添加了后缀 .config。这就是说,如果执行 MyApp.exe 程序可启动我的应用程序,则配置文件的名称一定是 MyApp.exe.config,而且配置文件必须与 MyApp.exe 位于同一个目录中。

  以下是示例中要使用的配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="availableclasses" type="System.Configuration.NameValueSectionHandler" />
</configSections>
<availableclasses>
<add key="Placeholder – do not load"
value="DLLPathnameGoesHere~NameOfTypeGoesHere"></add>
</availableclasses>
</configuration>

  此处,<availableclasses> 标记是占位符信息,便于人们看清格式。稍后,我们还会再返回来,为创建的新窗体添加配置信息。

 这实际上并不是存放窗体配置信息的理想方式,因为我们用符号分隔的方式在同一位置保存 DLL 位置和类型名称。但是,使用高级方法分别存放这些信息会要求相当多的注释和代码,所以我们暂且使用这种替代方法。

  使用某些文本编辑器或 XML 编辑器(或 Microsoft Visual Studio®)创建上述配置文件,然后使用 FormsOnTheFly.exe.config 文件名将其保存在 FormsOnTheFly 项目的 \bin 目录下。因为 .NET 配置类使用区分大小写的 XML 标记,所以创建此文件时,请注意 XML 标记中字母的大小写。

  步骤 4:将配置信息读入集合中

  我们为窗体编写的代码将使用 System.ConfigurationSystem.Reflection 命名空间中的类。请将以下两行代码置于 Form1 代码的最顶端,以便更方便地访问这些类:

  Imports System.Configuration
  Imports System.Reflection

  还需要一个模块级变量来存放配置信息集合。请将以下代码行紧挨着 Inherits System.Windows.Forms.Form 代码行放在其下方:

  Dim colAvailableClasses As ArrayList

现在,可以编写核心代码了。在 Form1 的 Form Load &&事件中放置以下代码,以便读取配置文件、创建存放信息的对象集合以及将集合数据绑定到组合框:

' 实例化配置信息集合。
colAvailableClasses = New ArrayList()

' 获取要从配置文件中加载的可用项。
Dim ClassConfigValues As Specialized.NameValueCollection
ClassConfigValues = CType(ConfigurationSettings.GetConfig("availableclasses"), _
Specialized.NameValueCollection)

Dim iIndex As Integer
Dim sLocation As String
Dim sDescription As String
Dim sType As String
Dim sValue As String

' 创建可绑定到组合框的可用项的
' 集合。
For iIndex = 0 To ClassConfigValues.Count - 1
sDescription = ClassConfigValues.Keys(iIndex)
sValue = ClassConfigValues.Item(sDescription)

' 经过简单的处理,从一个字段中
' 获取位置和类型。
Dim iPos As Integer
iPos = InStr(sValue, "~")
sLocation = Microsoft.VisualBasic.Left(sValue, iPos - 1)
sType = Microsoft.VisualBasic.Right(sValue, Len(sValue) - iPos)

Dim objNewForm As New DynamicClass(sLocation, sDescription, sType)
colAvailableClasses.Add(objNewForm)
Next

' 现在,将集合绑定到组合框。
' 显示说明,并返回对象的引用。
cboForms.DataSource = colAvailableClasses
cboForms.DisplayMember = "Description"
cboForms.ValueMember = "Reference"


  步骤 5:插入逻辑以加载所选窗体   

现在,在 btnLoadForm 的 click &&事件中放置以下逻辑:

Dim objFormToLoad As DynamicClass
objFormToLoad = cboForms.SelectedValue

Dim asmAssemblyContainingForm As [Assembly] = _
[Assembly].LoadFrom(objFormToLoad.Location)
Dim TypeToLoad As Type = asmAssemblyContainingForm.GetType(objFormToLoad.Type)
Dim GenericInstance As Object
GenericInstance = Activator.CreateInstance(TypeToLoad)

Dim FormToShow As Form = CType(GenericInstance, Form)
FormToShow.MdiParent = Me
FormToShow.Show()

  这是程序的核心部分。通过使用集合中一个对象的信息实例化代码并显示窗体。让我们逐行说明这段代码。

首先我们引用了其中包含要加载窗体的位置和类型的对象 (objFormToLoad)。它被设置为组合框的 SelectedValue &&属性,在从数据绑定的组合框返回所选内容时使用。

  DLL 的位置包含在对象的 Location &&属性中。Assembly 类的 LoadForm 方法使用该&&属性创建对程序集的引用。(将 Assembly 类置于括号中是因为 Assembly 是 .NET 关键字。括号将通知编译器,其中的内容不是正在使用的关键字,而是类名。)

  下面,我们需要引用正在加载的 .NET 类型(类)。可以使用程序集的 GetType 方法,通过传递存放类型名称(该类型名称将从存放配置数据的对象的 Type &&属性中获取)的字符串进行引用。对类型的引用保存在 TypeToLoad 中。

  Reflection 类和 Activator 类使用它们的 CreateInstance 方法创建类型的实例。(CreateInstance 与 Visual Basic 6.0 中的 CreateObject 类似。)但是,实例必须是类型对象,因为该类型要动态加载。

  最后,新实例化的对象(实际上是一个窗体)必须转换为正确的类型才能启用前期绑定。我们知道它是一个窗体,所以可以使用 CType &&函数将其转换为窗体。

  最后,将新窗体设置为 MDI 父窗体的子窗体并对其进行显示。

注意:从 /html/vbnet10142001.asp">Death of the Browser?(英文)所示的 URL 处加载的程序集被复制到本地缓存中。从 UNC 加载的程序集(如本文中的程序集)仅在当前位置使用,不被复制到任何缓存中。

  步骤 6:编译应用程序   

  现在,我们可以编译应用程序,但由于尚未创建任何窗体,所以不会显示任何窗体。可以编译并运行程序,确保它能够工作并确保组合框能够正确加载占位符项。如果单击 btnLoadForm,则会显示错误信息或教程,因为配置文件中的信息还未指向任何对象。

  步骤 7:创建要显示的窗体   

现在,开始创建名为 FirstForm 的新的 Windows 窗体应用程序。在出现的空白 Form1 上放置一些控件 - 控件类型不限。

  然后在 Solution Explorer(解决方案资源管理器)中的 FirstForms 项目上单击鼠标右键,选择 Properties(&&属性)。在 Output Type(输出类型)组合框中选择 Class Library(类库)。如果未看到组合框,可以在 Solution Explorer(解决方案资源管理器)的 Solution(解决方案),而不是 Project(项目)上单击鼠标右键。

  现在开始创建项目。即创建一个包含该窗体的 DLL。

  创建一个名为 C:\NewForms 的目录。将 FirstForms.dll 从 FirstForms 的 \bin 目录复制到 C:\NewForms 中。

  对名为 SecondForm 和 ThirdForm 的项目重复上述操作。在每个窗体中拖入不同的控件以便于区分。也可以将每个窗体的背景色更改为独特的颜色。

  步骤 8:用新的窗体信息更新配置文件

  现在,我们已经创建了一些新窗体,还需要在配置文件中引用它们。请用以下代码行替换 FormsOnTheFly.exe.config 中的占位符信息:

<add key="First Form"
value="C:\NewForms\FirstForm.dll~FirstForm.Form1"></add>
<add key="Second Form"
value="C:\NewForms\SecondForm.dll~SecondForm.Form1"></add>
<add key="Third Form"
value="C:\NewForms\ThirdForm.dll~ThirdForm.Form1"></add>

  如果要更改窗体的位置或名称,则需要对以上代码行进行相应修改。

  步骤 9:运行 FormsOnTheFly.exe 并加载窗体

  现在执行 FormsOnTheFly.exe(不加载 Visual Studio)。选择组合框中的一个窗体,然后单击 btnLoadForm。如果正确完成了所有步骤,则可以看到子窗体加载到 MDI 窗口中(即使编译 MDI 应用程序时子窗体并不存在)。

图 2 显示了动态加载窗体后的 MDI 窗体。

图 2:动态加载窗体后的 MDI 窗体

  此时,您可以根据需要创建任意多个新窗体并将其加载到 MDI 应用程序中。要使其可用,请将其编译为类库,然后在配置文件中添加对它们的引用。

 动态加载其他类型的类

  此技术除了可用于窗体外,还可用于其他类型的类。但是,情况相对较复杂。在上面的示例中,之所以能够对 System.Windows.Forms.Form 类&&接口进行前期绑定是因为我们知道它是一个窗体。因此可以使用窗体的方法(例如,Show 方法)。但对于我们自己创建的类,可以依据什么&&接口进行绑定呢?

  答案是创建我们自己的&&接口。实际上,这是一个重要的实现&&接口的典型示例。您可能在 Visual Basic 6.0 中使用过&&接口。&&接口作为空类而创建。Visual Basic .NET 中有了新的语法,&&接口与类完全分开,进行单独声明。在下面的步骤 1 中,我们会看到如何实现这一操作。

  让我们设计一个可以动态加载类的示例。假设我们要编写一个需要操纵数据集的数据清理应用程序。但是,正如所有数据清理程序一样,它们似乎从来都没有完成。似乎总是需要为新的校验类型和清理任务编写代码。

  当然,可以创建新的清理逻辑并重新编译整个应用程序,但如果可以动态插入新的数据清理功能而不必重新编译主应用程序,是不是会更好?下面让我们从头开始创建这样一个示例。

  步骤 1:创建类文件以存放&&接口

  从概念上讲,在 Visual Basic .NET 中创建&&接口与在 Visual Basic 6.0 中创建&&接口相似,但在语法上有很大不同。要创建初始&&接口类,请创建一个类型为 Class Library(类库)的新项目。将其命名为 ScrubberInterface

  在创建的类文件中,用以下代码替换文件中现有的代码行:

Public Interface IScrubber
Sub Scrub(ByVal ds As DataSet)
End Interface

  我们的&&接口非常简单。我们需要一个操作数据集的方法。已将此方法命名为 Scrub

  现在,创建项目。ScrubberInterface.DLL 将创建在项目的 \bin 目录下。

  步骤 2:创建清理应用程序

  清理应用程序与前面的窗体应用程序示例在许多方面都很相似。不同之处在于,我们将依次使用所有的数据清理类,而不是选择使用一个特定的类。

  创建一个新的 Windows 窗体应用程序,然后将其命名为 ClassesOnTheFly。在显示的 Form1 中放置以下控件:

控件类型 名称 &&属性设置
Button btnLoadDataset Text = "Load Dataset"
Button btnScrubDataset Text = "Scrub Dataset"
DataGrid DataGrid1 不作更改

  在 Form1 的代码顶部,放置与前述示例顶部代码相同的代码:

  Imports System.Configuration
  Imports System.Reflection

  这里也需要一个模块级变量来存放配置信息集合。将以下代码行置于 Inherits System.Windows.Forms.Form 代码行的下方:

  Dim colAvailableClasses As ArrayList

  步骤 3:将数据集加载到网格中进行处理

  为简化操作,将从 XML 文件中加载数据集。将以下 XML 文件放置到 ClassesOnTheFly 项目的 \bin 目录中,然后将其命名为 TimeCardData.xml:

<TimeCardData>
<Employee>
<Name>Sherlock Holmes</Name>
<ID>123</ID>
</Employee>
<Employee>
<Name>John Watson</Name>
<ID>345</ID>
</Employee>
<Employee>
<Name>Irene Adler</Name>
<ID>567</ID>
</Employee>
<Employee>
<Name>Jabez Wilson</Name>
<ID>789</ID>
</Employee>
</TimeCardData>

  我们需要一个模块级的数据集引用,所以请将以下代码行放置在声明 colAvailableClasses 的代码行的下方:

  Dim ds As DataSet

要读取数据集并加载网格,请将以下代码放置到 btnLoadDatasetclick &&事件中:

ds = New DataSet()
ds.ReadXml("TimeCardData.xml")
DataGrid1.DataSource = ds.Tables(0)

  然后运行程序,确保正确加载网格。

  步骤 4:添加对清理程序&&接口的引用

  下面,我们需要添加对 DLL 的引用,该 DLL 是以前创建的,用来存放数据清理类的&&接口。选择 Project | Add Reference(项目|添加引用)。单击 Browse(浏览)按钮,浏览到 ScrubberInterface.DLL(在步骤 1 中创建),然后单击 Open(打开)。单击 OK(确定),添加引用。

  步骤 5:使类在可用窗体上存放数据

  现在,复制以前窗体示例中使用的 DynamicClass.vb 模块,将其插入到 ClassesOnTheFly 项目中。可以不进行修改,直接使用。

  步骤 6:创建配置文件以存放可用窗体

  创建一个与前面窗体示例中使用的配置文件完全相同的配置文件。配置文件应如下显示:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="availableclasses" type="System.Configuration.NameValueSectionHandler" />
</configSections>
<availableclasses>
<add key="Placeholder – do not load"
value="DLLPathnameGoesHere~NameOfTypeGoesHere"></add>
</availableclasses>
</configuration>

  请记住,将此文件放置到 ClassesOnTheFly 项目的 \bin 目录中,然后将其命名为 ClassesOnTheFly.exe.config。

   步骤 7:将配置信息读入集合中

  此操作几乎与前面窗体示例中的操作完全相同,不同之处在于我们现在未将集合绑定到组合框。所以,复制窗体示例的 Form Load &&事件中使用的逻辑,但是省略最后三行代码(此三行代码用于执行绑定到组合框的操作)。将此逻辑粘贴到 ClassesOnTheFly 项目中 Form1 的 Form Load &&事件中。

   步骤 8:插入逻辑以加载和使用数据清理类

  现在,在 btnScrubDatasetclick &&事件中放置以下逻辑:

Dim objScrubberClass As DynamicClass
For Each objScrubberClass In colAvailableClasses
Dim asmAssemblyContainingForm As [Assembly] = _
[Assembly].LoadFrom(objScrubberClass.Location)
Dim TypeToLoad As Type = _
asmAssemblyContainingForm.GetType(objScrubberClass.Type)
Dim GenericInstance As Object
GenericInstance = Activator.CreateInstance(TypeToLoad)

Dim Scrubber As ScrubberInterface.IScrubber = _
CType(GenericInstance, ScrubberInterface.IScrubber)
Scrubber.Scrub(ds)
Next

  此逻辑与动态加载窗体的逻辑有很多相似之处,这里不再作详细说明。主要的不同之处在于:

  • 对配置文件中的每一个类都进行动态加载。
  • 新实例化的对象被转换为 ScrubberInterface.IScrubber 类型。这样就可以绑定到 IScrubber &&接口。
  • 执行每个对象的 Scrub 方法,在数据集中进行传递。

      步骤 9:编译并运行应用程序

      运行应用程序以确保能够正确编译。但是,先不要单击 Scrub Dataset(清理数据集)按钮,因为尚未创建清理类。

      应用程序编译完成后,关闭 ClassesOnTheFly 项目中的 Visual Studio。

      步骤 10:创建数据清理类

      在 Visual Studio 中,创建一个类型为 Class Library(类库)的新项目。将其命名为 FirstClass。用以下代码替换 Class1 中自动插入的代码:

    Public Class FirstClass
    Implements ScrubberInterface.IScrubber
    Public Sub Scrub(ByVal ds As DataSet) _
    Implements ScrubberInterface.IScrubber.Scrub
    Dim dr As DataRow

    dr = ds.Tables(0).NewRow
    dr.Item(0) = "Professor Moriarty"
    dr.Item(1) = "666"
    ds.Tables(0).Rows.Add(dr)
    End Sub

    End Class

      此类实现 IScrubber &&接口(只是一个方法)。该方法获取数据集,并在数据集中添加一个单独的行。当然,实际的数据清理类中应已具备所有必要的数据操作逻辑。

      创建此项目以获取 FirstClass.DLL。将 DLL 从项目的 \bin 目录复制到名为 C:\ScrubberClasses 的新目录中。

      步骤 11:用新类更新配置文件

      现在,返回到 ClassOnTheFly.exe.config。更改 <availableclasses> 标记中的内容,使其如下所示:

    <add key="First Class"
    value="C:\ScrubberClasses\FirstClass.dll~FirstClass.FirstClass">

      保存配置文件,然后执行最后一步操作。

      步骤 12:测试新的数据清理类的操作

      现在,运行 ClassesOnTheFly.exe 并单击 Load Dataset(加载数据集)按钮。请注意网格包含四行。单击 Scrub Dataset(清理数据集)按钮。网格中将显示第五行(这是由数据清理类添加的)。

      如果需要,可以添加其他清理类,在数据集上执行所需的任何操作。只需创建清理类并将其添加到配置文件中即可。这样,单击 Scrub Dataset(清理数据集)按钮时,将自动使用这些清理类。

      小结

      这两个示例中最重要的一点是,在创建和编译原始应用程序(FormsOnTheFlyClassesOnTheFly)时,并不包含对后来动态加载的窗体和类的引用。实际上,这些窗体和类在编译应用程序时还没有创建!

      创建窗体和类之后,只需在配置文件中引用它们的位置和类型,即可使用它们更新应用程序。可以根据需要创建新的窗体和类并进行动态添加。如果您的应用程序需要具有这种扩展功能,则可以使用 .NET 提供的完善解决方案,它具有反映和动态加载类的功能。


    来源:十度教育
    作者:
    关键字:Visual,Basic,.NET,中动态加载类
    发表日期:2006-5-16 10:44:04

    网页显示有限 阅读全文请下载本文完整版WORD文档

    上一篇:如何用VB.Net创建一个三层的数据库应用程序   下一篇:Visual Basic.NET中访问数据的方法


    2008-8-29 10:37:07
    本文的相类似文章
  • Visual Basic_美化你的文字
  • Visual Basic 6中发送邮件的新方法
  • Visual Basic 中字符淡出淡入的实现
  • 想不到的VB指针用法{Visual Basic6.0}
  • ASP.Net发现漏洞 黑客绕过安全设置
  • .NET中用Oracle 10g Single-Sign-On
  • .NET 访问 Oracle 数据库相关
  • Oracle9i连接ASP.NET方法及注意点
  • 一个ASP.Net的DataGrid分页控件
  • 在.net中Oracle日期类型的处理
  • 在学习中进步 在进步中成长 教程中国相随您的成长之路
    华腾联合科技股份有限公司版权所有
    广告联系:Rosibo@163.com