欢迎光临
我们一直在努力

Autodesk官方最新的.NET教程(七)(vb.net版)-.NET教程,VB.Net语言

建站超值云服务器,限时71元/月

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

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » Autodesk官方最新的.NET教程(七)(vb.net版)-.NET教程,VB.Net语言
分享到: 更多 (0)