4

我的任务是将 AutoCAD 插件从 VBA 转换为 VB.NET,但我目前有点卡住了。

我正在处理的命令创建一个新层(如果它已经存在,则选择它作为活动层),然后执行 2 个“-INSERT”命令,给出用户选择的点和一个 dwg 文件。然后,先前的有源层被重置为有源层。

插入命令看起来像这样:

-INSERT
C:\path\to\file.dwg
<point.x>,<point.y>,<point.z>
<documentScale>

注意:命令中的所有换行符都添加为vbCR(not vbCrLf)。

我的问题是,如何在 .NET 中针对 ObjectARX 获得相同的结果?我不能使用SendStringToExecute,因为它是异步的(没有回调),所以换句话说,一旦它完成执行,我就无法重置当前层。必须有某种方法可以在纯 .NET 代码中复制此功能,可能使用 .NET 代码,BlockTable但我不知道如何。

我试过按照这里找到的文章:http: //through-the-interface.typepad.com/through_the_interface/2006/08/import_blocks_f.html,但这对文档根本没有明显的影响。我也尝试使用myDatabase.Insert(transform, otherDatabase, False),命令提示符说明了已经存在的块,因此被跳过,但我仍然没有看到任何变化。我不知道“-INSERT”命令在幕后实际上有多大的魔力,但是在 .NET 中复制它是否可行?还是以某种方式可以作为普通方法调用(而不是作为发送以由 AutoCAD 处理的文本命令)?

4

1 回答 1

6

通过接口帖子中的代码示例会导入块,但不会将它们插入到图形中。您必须创建一个BlockReference并将其添加到模型空间。它还插入文件中的所有块,而不是将文件作为单个块插入。

这是我用来将文件作为一个整体导入的代码。此函数返回可以插入到图形中的块参考。

    Private Shared Function InsertFile(ByVal FileName as String, ByVal dwgdb As Database, ByVal tr As Transaction) As BlockReference

        Dim br As BlockReference
        Dim id As ObjectId

        'use a temporary database 
        Using TempDB As New Database(False, True)

            'Get block table
            Dim bt As BlockTable = tr.GetObject(dwgdb.BlockTableId, OpenMode.ForWrite, False)

            'Create unique block name
            Dim BlockName As String = FileName.Replace("\", "").Replace(":", "").Replace(".", "")

            'check if block already exists
            If Not bt.Has(BlockName) Then
                'check if file exists
                If IO.File.Exists(FileName) Then
                    'read in the file into the temp database
                    TempDB.ReadDwgFile(FileName, IO.FileShare.Read, True, Nothing)
                    'insert the tempdb into the current drawing db, id is the new block id
                    id = dwgdb.Insert(BlockName, TempDB, True)
                Else
                    'Throw exception for missing file 
                    Throw New System.Exception(String.Format("File {0} is not found for library item {1}", FileName, item.PartNo))
                End If

            Else
                id = bt.Item(BlockName)
            End If

            'create a new block reference
            br = New BlockReference(New Point3d(0, 0, 0), id)
        End Using

        Return br


    End Function

这是使用该函数将块插入文件的示例。在这个例子中,我使用了一个夹具,它允许用户将对象放到他们想要的位置,否则你可以只设置位置。

      ' Get Editor
        Dim ed As Editor = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor
        ' Get Database
        Dim dwg As Database = ed.Document.Database

        'Lock document
        Using dl As DocumentLock = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.LockDocument()

            '### Changed Try Finally to using, try was hiding errors
            'Begin Transaction
            Using trans As Transaction = dwg.TransactionManager.StartTransaction()

                Dim blockRef As BlockReference = InsertFile(FileName, dwg, trans)

                'check if layer exists/create
                AcadUtil.AcadFunctions.CheckLayer(LayerName, trans, dwg)
                blockRef.Layer = LayerName

                'set focus to the editor
                Autodesk.AutoCAD.Internal.Utils.SetFocusToDwgView()

                'have the user pick insert point
                Dim BlockMove As New AcadJigs.JigBlockMove(blockRef, False, 0)
                ed.Drag(BlockMove)
                'optionally you could just set the .Position of the block reference


                ' add it to the current space, first open the current space for write
                Dim btr As BlockTableRecord = trans.GetObject(dwg.CurrentSpaceId, OpenMode.ForWrite, True, True)

                ' Add block reference to current space
                btr.AppendEntity(blockRef)

                'Capture the handle
                handle = blockRef.Handle.Value.ToString

                ' remember to tell the transaction about the new block reference so that the transaction can autoclose it
                trans.AddNewlyCreatedDBObject(blockRef, True)

                'commit the transaction
                trans.Commit()

            End Using

        End Using

这也是CheckLayer我调用的函数。

    Public Shared Sub CheckLayer(ByVal Name As String, ByVal tr As Transaction, ByVal dwg As Database)


        Dim lt As LayerTable = CType(tr.GetObject(dwg.LayerTableId, OpenMode.ForWrite), LayerTable)

        If lt.Has(Name) Then
            Return
        Else
            Dim ly As New LayerTableRecord
            ly.Name = Name
            lt.Add(ly)
            tr.AddNewlyCreatedDBObject(ly, True)
        End If

    End Sub

顺便说一句,Kean 的博客是一个很好的资源,我几乎从那里学到了上面所有的代码。

为了完整起见,这是我在插入代码中引用的 Jig 类,

 Class JigBlockMove
        Inherits EntityJig

        Private _CenterPt As Point3d
        Private _ActualPoint As Point3d
        Private _LockZ As Boolean
        Private _Z As Double

        Public ReadOnly Property SelectedPoint() As Point3d
            Get
                Return _ActualPoint
            End Get
        End Property

        Public Sub New(ByVal BlockRef As BlockReference, ByVal LockZ As Boolean, ByVal Z As Double)
            MyBase.New(BlockRef)
            _CenterPt = BlockRef.Position
            _LockZ = LockZ
            _Z = Z
        End Sub

        Protected Overloads Overrides Function Sampler(ByVal prompts As JigPrompts) As SamplerStatus
            Dim jigOpts As New JigPromptPointOptions()
            jigOpts.UserInputControls = (UserInputControls.Accept3dCoordinates Or UserInputControls.NoZeroResponseAccepted Or UserInputControls.NoNegativeResponseAccepted)
            jigOpts.Message = vbLf & "Enter insert point: "
            Dim dres As PromptPointResult = prompts.AcquirePoint(jigOpts)
            If _ActualPoint = dres.Value Then
                Return SamplerStatus.NoChange
            Else
                _ActualPoint = dres.Value
            End If

            Return SamplerStatus.OK
        End Function

        Protected Overloads Overrides Function Update() As Boolean
            If _LockZ Then
                _CenterPt = New Point3d(_ActualPoint.X, _ActualPoint.Y, _Z)
            Else
                _CenterPt = _ActualPoint
            End If

            Try
                DirectCast(Entity, BlockReference).Position = _CenterPt
            Catch generatedExceptionName As System.Exception
                Return False
            End Try

            Return True
        End Function

        Public Function GetEntity() As Entity
            Return Entity
        End Function

    End Class

关于在 .NET ObjectARX 中工作的一个注意事项是,AutoCAD 的单线程特性以及 .NET 垃圾收集器在单独的线程上运行这一事实存在问题。如果您创建任何未添加到数据库的临时 AutoCAD 对象,则必须显式调用.Dispose()它们,否则 AutoCAD 可能会崩溃!崩溃看起来也是随机的,因为它是由垃圾收集器线程触发的。请参阅这篇文章,http ://through-the-interface.typepad.com/through_the_interface/2008/06/cleaning-up-aft.html 。

于 2013-06-27T14:02:36.257 回答