分享
 
 
 

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

王朝c#·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

第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”属性时,这个回调函数被触发。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有