首页 - VB.NET

Autodesk官方最新的.NET教程(七)(vb.net版)

发布时间: 2007-04-19 03:57    作者: 未知    来源: 未知    浏览:    评论

第7章 事件 
本章将讨论AutoCAD中的事件。我们将介绍事件处理函数的使用,特别是监视AutoCAD命令的事件处理函数和监视被AutoCAD命令修改的对象的事件处理函数。在解释怎样实现AutoCAD的事件处理之前,我们将首先简要地讨论一下.NET中的事件。 

第一部分  VB.NET中的事件 
事件只是用来通知一个行为已经发生的信息。在ObjectARX中,我们使用反应器(reactor)来处理AutoCAD的事件。而在AutoCAD .NET API中,ObjectARX反应器被换成了事件。 
事件处理函数(或者叫回调函数)是用来监视和反馈程序中出现的事件。事件可以以不同的形式出现。 
在介绍AutoCAD .NET API中的事件之前,让我们先来简单地了解一下代理。 

第1a部分  代理 
代理是一个存储方法索引的类(概念与函数指针类似)。代理对方法是类型安全的(与C中的函数指针类似)。代理有特定的形式和返回类型。代理可以封装符合这种特定形式的任何方法。 
代理的一个用途就是作为产生事件的类的分发器。事件是.NET环境中第一级别的对象。虽然VB.NET把事件处理的许多细节给隐藏掉了,但事件总是由代理来实现的。事件代理可以多次调用(就是它们可以存储多于1个的事件处理方法的索引)。它们保存了用于事件的一个注册事件处理的列表。一个典型的代理有以下的形式: 
Public Delegate Event (sender as Object, e as EventArgs) 

第一个参数sender表示引发事件的对象。第二个参数e是一个EventArgs参数(或者是一个派生的类),这个对象通常包含用于事件处理函数的数据。 

第1b部分 AddHandler和RemoveHandler语句 

要使用事件处理函数,我们必须把它与事件联系起来。这要通过使用AddHandler语句。AddHandler和RemoveHandler允许你在运行时连接、断开或修改与事件联系的处理函数。 
当我们使用AddHandler语句时,我们要确定事件引发者的名字,并要使用AddressOf语句来确定事件处理函数,例如: 
AddHandler MyClass1.AnEvent, AddressOf EHandler 

前面我们说过要使用RemoveHandler语句从事件处理函数中断开事件(移除联系)。语法如下所示: 
RemoveHandler MyClass1.AnEvent, AddressOf EHandler 

第2部分  处理.NET中的AutoCAD事件 

在ObjectARX中,我们使用反应器来封装AutoCAD事件。在AutoCAD .NET API中,我们可以使用事件来代替ObjectARX反应器。 
通常,处理AutoCAD事件的步骤如下: 
1.       创建事件处理函数 
当一个事件发生时,事件处理函数(或称为回调函数)被调用。任何我们想要处理的回应AutoCAD事件的动作都在事件处理函数中进行。 
例如,假定我们只想通知用户一个AutoCAD对象已被加入。我们可以使用AutoCAD数据库事件”ObjectAppended”来完成。我们可以编写回调函数(事件处理函数)如下: 
Sub objAppended(ByVal o As Object, ByVal e As ObjectEventArgs) 
    MessageBox.Show("ObjectAppended!") 
    ‘在这里加入一些代码 
End Sub  

函数中的第一个参数代表AutoCAD数据库。第二个参数代表ObjectEventArgs类,它可能包含对处理函数有用的数据。 
2.       把事件处理函数与事件联系起来 
为了开始监视动作,我们必须把事件处理函数与事件联系起来。在这里,当一个对象加入到数据库时,ObjectAppended事件将会发生。但是,事件处理函数不会响应这个事件,除非我们把它与这个事件联系起来,例如: 
         Dim db As Database 
db = HostApplicationServices.WorkingDatabase() 
AddHandler db.ObjectAppended, New ObjectEventHandler(AddressOf objAppended) 


3.       断开事件处理函数 
要终止监视一个动作,我们必须断开事件处理函数与事件的联系。当对象被加入时,我们想要停止通知用户这个事件,我们要断开事件处理函数与事件ObjectAppended的联系。 
RemoveHandler db.ObjectAppended, AddressOf objAppended 

第3部分  使用事件处理函数来控制AutoCAD的行为 
本章的目的是解释AutoCAD事件怎样才能被用于控制AutoCAD图形中的行为。现在,让我们使用前一章(第六章)的内容在AutoCAD图形中创建几个EMPLOYEE块索引。我们不想让用户能改变EMPLOYEE块索引的位置,而对于其它的非EMPLOYEE块索引的位置则没有这个限制。我们将混合使用数据库与文档事件来做到这一点。 
首先,我们想要监视将要被执行的AutoCAD命令(使用CommandWillStart事件)。特别地,我们要监视MOVE命令。另外,当一个对象要被修改时,我们应该被通知(使用ObjectOpenedForModify事件),这样我们可以确定它是否为一个EMPLOYEE块索引。如果这时就修改对象可能是无效的,因为我们的修改可能会再次触发事件,从而引起不稳定的行为。所以,我们要等待Move命令的执行结束(使用CommandEnded事件),这时就可以安全地修改对象了。当然,任何对块索引的修改将会触发ObjectOpenedForModify事件。我们还需要设置一些全局变量来表明一个MOVE命令在运行和被修改的对象是一个EMPLOYEE块索引。 
注意:因为本章需要比较多的代码来获得想要的结果,所以我们不会解释任何与事件处理无关的代码,而只是将它们粘贴到事件处理函数中。这里的重点是成功创建和注册事件处理函数。 
第一步:创建新工程 
我们以第六章的工程开始。请新加入一个类AsdkClass2。我们还要加入四个全局变量。前两个是Boolean型的:一个用来表示我们监视的命令是否是活动的,另外一个用来表示ObjectOpenedForModify事件处理函数是否该被忽略。 
'全局变量 
Dim bEditCommand As Boolean 
Dim bDoRepositioning As Boolean 
 
 
接下来,我们要声明一个全局变量来表示一个ObjectIdCollection,它用来存储我们所选择的要修改的对象的ObjectID。 
Dim changedObjects As New ObjectIdCollection() 

最后,我们要声明一个全局变量来表示一个Point3dCollection,它用来包含我们所选对象的位置(三维点)。 
Dim employeePositions As New Point3dCollection() 
第2步:创建第一个文档事件处理函数(回调函数) 
现在我们要创建一个事件处理函数。当AutoCAD命令开始执行的时候它会通知我们。我们要检查GlobalCommandName的值是否为MOVE。 
If e.GlobalCommandName = "MOVE" Then 
    'Set the global variables 
    ‘ 
    ‘ 
    ‘'Delete all stored information 
    ‘ 
    ‘ 
End If 
如果MOVE命令开始执行的话,我们要相应地设置Boolean变量bEditCommand的值,这样我们可以知道我们所监视的命令是活动的。同样地,我们应该把另外一个Boolean变量bDoRepositioning设置为false来忽略ObjectOpenedForModify事件处理函数。两个变量设置好以后,在命令活动期间,我们必须要获得所选块索引的信息。 
我们还应该把两个集合对象的内容清空。我们只关心当前选择的对象。 
第3步: 创建数据库事件处理函数(回调函数) 
无论什么时候一个对象被打开并要被修改时,数据库事件处理函数会被调用。当然,如果这时我们监视的命令不是活动的,我们就应该跳过任何被这个回调函数调用的内容。 
If bEditCommand = False Then 
    Return 
End If 
同样地,如果我们监视的命令已经结束,而ObjectOpenedForModify事件被另一个回调函数再次触发的话,而这时有对象被修改时,我们要阻止所有由这个回调函数执行的动作。 
If bDoRepositioning = True Then 
    Return 
End If 
这个回调函数剩余部分的代码用来验证我们是否正在处理EMPLOYEE块索引。如果是的话,我们就获取它的ObjectID和位置(三维点)。下面的代码可以被粘贴到这个事件处理函数函数。 

Public Sub objOpenedForMod(ByVal o As Object, ByVal e As ObjectEventArgs) 
    If bEditCommand = False Then 
        Return 
    End If 

    If bDoRepositioning = True Then 
        Return 
    End If 

    Dim objId As ObjectId 
    objId = e.DBObject.ObjectId 

    Dim trans As Transaction 
    Dim bt As BlockTable 
    Dim db As Database 
    db = HostApplicationServices.WorkingDatabase 

    trans = db.TransactionManager.StartTransaction() 
    Try 
        'Use it to open the current object! 
        Dim ent As Entity = trans.GetObject(objId, OpenMode.ForRead, False) 
        If TypeOf ent Is BlockReference Then 'We use .NET's RTTI to establish type. 
            Dim br As BlockReference = CType(ent, BlockReference) 
            'Test whether it is an employee block 
            'open its extension dictionary 
            If br.ExtensionDictionary().IsValid Then 
                Dim brExtDict As DBDictionary = trans.GetObject(br.ExtensionDictionary(), OpenMode.ForRead) 
                If brExtDict.GetAt("EmployeeData").IsValid Then 
                    'successfully got "EmployeeData" so br is employee block ref 

                    'Store the objectID and the position 
                    changedObjects.Add(objId) 
                    employeePositions.Add(br.Position) 
                    'Get the attribute references,if any 
                    Dim atts As AttributeCollection 
                    atts = br.AttributeCollection 
                    If atts.Count > 0 Then 
                        Dim attId As ObjectId 
                        For Each attId In atts 
                            Dim att As AttributeReference 
                            att = trans.GetObject(attId, OpenMode.ForRead, False) 
                            changedObjects.Add(attId) 
                            employeePositions.Add(att.Position) 

                        Next 
                    End If 
                End If 
            End If 
        End If 
        trans.Commit() 
    Finally 
        trans.Dispose() 
    End Try 
End Sub 
第4步 创建第二个文档事件处理函数(回调函数) 
当一个命令结束时,第三个事件处理函数被调用。同样地,我们要检查全局变量来验证这个将要结束的命令是我们监视的命令。如果是我们监视的,那么我们要重置这个变量: 
If bEditCommand = False Then 
    Return 
End If 

bEditCommand = False 

这个回调函数执行的动作将会再次触发ObjectOpenedForModify事件。我们必须确定在这个回调函数中跳过了所有与此事件有关的动作。 
'设置标志来跳过OpenedForModify处理函数 
bDoRepositioning = True 


这个回调函数的剩余代码用来把EMPLOYEE块索引和它的关联属性引用的当前(修改过的)位置与它们的初始位置作比较。如果位置改变了,我们在这个回调函数中把它们重置这初始的位置。下面的代码可以被粘贴到这个事件处理函数中。 

Public Sub cmdEnded(ByVal o As Object, ByVal e As CommandEventArgs) 
    'Was our monitored command active? 
    If bEditCommand = False Then 
        Return 
    End If 

    bEditCommand = False 

    'Set flag to bypass ObjectOpenedForModify handler 
    bDoRepositioning = True 

    Dim db As Database = HostApplicationServices.WorkingDatabase 
    Dim trans As Transaction 
    Dim bt As BlockTable 
    Dim oldpos As Point3d 
    Dim newpos As Point3d 
    Dim i As Integer 
    Dim j As Integer = 1 
    For i = 0 To changedObjects.Count - 1 
        trans = db.TransactionManager.StartTransaction() 
        Try 
            bt = trans.GetObject(db.BlockTableId, OpenMode.ForRead) 
            Dim ent As Entity = CType(trans.GetObject(changedObjects.Item(i), OpenMode.ForWrite), Entity) 
            If TypeOf ent Is BlockReference Then 'We use .NET's RTTI to establish type. 
                Dim br As BlockReference = CType(ent, BlockReference) 
                newpos = br.Position 
                oldpos = employeePositions.Item(i) 

                'Reset blockref position 
                If Not oldpos.Equals(newpos) Then 
                    trans.GetObject(br.ObjectId, OpenMode.ForWrite) 
                    br.Position = oldpos 
                End If 
            ElseIf TypeOf ent Is AttributeReference Then 
                Dim att As AttributeReference = CType(ent, AttributeReference) 
                 newpos = att.Position 
                oldpos = employeePositions.Item(i) 

                'Reset attref position 
                If Not oldpos.Equals(newpos) Then 
                    trans.GetObject(att.ObjectId, OpenMode.ForWrite) 
                    att.Position = oldpos 
                End If 
            End If 
            bt.Dispose() 
            trans.Commit() 
        Finally 
            trans.Dispose() 
        End Try 
    Next 
End Sub 

第5步  创建命令来注册/断开事件处理函数 
创建一个ADDEVENTS命令,使用+=语句来把上面的3个事件处理函数连接到各自的事件。在这个命令中,我们还应该设置全局Boolean变量: 
bEditCommand = False 
bDoRepositioning = False 
 
创建另外一个命令REMOVEEVENTS,使用RemoveHandler语句把事件处理函数与事件断开。 
第6步: 测试工程 
要测试这个工程,请使用CREATE命令创建一个或多个EMPLOYEE块索引。如果你要作比较的话,你也可以插入一些非EMPLOYEE的块索引。 
在命令行中键入ADDEVENTS命令来执行它。 
在命令行中输入MOVE命令,然后选择你想要的块索引。注意,当MOVE命令结束时,EMPLOYEE块索引(包括属性)还留在原处。 
执行REMOVEEVENTS命令,然后在试一下MOVE命令。注意,EMPLOYEE块索引现在可以被移动了。 

附加的问题:添加一个附加的回调函数,当用户改变EMPLOYEE块索引的”Name”属性时,这个回调函数被触发。 

TAG

Smile Big Smile Surprise Stick out tongue Wink Sad Tongue Tied Indifferent Crying Embarrassed Cool Angry Angel Devil [8-|] [:#] [:-*] [:^)] [<:o)] [|-)] Yes Beer Left Hug Music Star Time Snail Pizza Automobile Umbrella Computer Storm [mo] [8o|] [^o)] [+o(] [*-)] [8-)] Coffee No Drinks [Z] Right Hug Cake Broken Heart Gift Wilted Flower Movie Dog Idea Sleep Email Travel Paradise
呢称:

加粗 斜体 下划线 链接 图片 代码 邮件地址 引用 列表

最多只能输入100个字符

Tags

SQL 数据库 asp.net C# XML 控件 .NET教程 程序 事件 数据 安全 代码 Server 客户端 验证 数据库专栏 接口 文件 Oracle DataSet 函数 DataGrid 问题 .net return C#语言 JavaScript 服务 IIS 对象 语句 windows 继承 时间 web.config 设计 开发 参数 变量 解决 字符 ADO.net 环境 VB.Net语言 web 异常 工具 服务器 计算 实例 OLEDB Application VB Word WebService insert asp net 安装 记录

精华推荐

更多

精品下载

更多