vb.net .NET 中的 AutoCAD -INSERT 命令
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17344830/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AutoCAD -INSERT command in .NET
提问by Alxandr
I have been tasked with translating an AutoCAD plugin from VBA to VB.NET, and I'm currently a bit stuck.
我的任务是将 AutoCAD 插件从 VBA 翻译成 VB.NET,但我目前有点卡住了。
The command I'm working on creates a new layer (or select it as the active layer if it already exist), then executes 2 "-INSERT" commands giving a point selected by the user, and a dwg-file. Then, the previous active layer is reset as the active layer.
我正在处理的命令创建一个新层(如果它已经存在,则选择它作为活动层),然后执行 2 个“-INSERT”命令,给出用户选择的一个点和一个 dwg 文件。然后,之前的活动层被重置为活动层。
The insert-command looks something like this:
插入命令看起来像这样:
-INSERT
C:\path\to\file.dwg
<point.x>,<point.y>,<point.z>
<documentScale>
Note: All the line-breaks in the command are added as vbCR(not vbCrLf).
注意:命令中的所有换行符都添加为vbCR(not vbCrLf)。
My question is, how can I achieve the same result in .NET against ObjectARX? I can't use SendStringToExecutebecause it is async (with no callback), so in other words, I can't reset the current layer once it's done executing. There has to be some way to replicate this functionality in pure .NET code, probably using the BlockTable, but I have no idea how.
我的问题是,如何在 .NET 中针对 ObjectARX 实现相同的结果?我无法使用,SendStringToExecute因为它是异步的(没有回调),所以换句话说,一旦它完成执行,我就无法重置当前层。必须有一些方法可以在纯 .NET 代码中复制此功能,可能使用BlockTable,但我不知道如何。
I've tried following the article found here: http://through-the-interface.typepad.com/through_the_interface/2006/08/import_blocks_f.html, but that had no visible effect on the document at all. I also tried to use myDatabase.Insert(transform, otherDatabase, False)and the command-prompt said something about blocks already existing and thus beeing skipped, yet I still saw no changes. I have no idea how much magic the "-INSERT" command actually does behind the scenes, but would it be viable to replicate it in .NET? Or is it somehow availible to be called as a normal method (not as a text-command sent to be processed by AutoCAD)?
我尝试按照此处找到的文章进行操作:http: //through-the-interface.typepad.com/through_the_interface/2006/08/import_blocks_f.html,但这对文档根本没有明显影响。我也尝试使用myDatabase.Insert(transform, otherDatabase, False)并且命令提示符说了一些关于已经存在的块的信息,因此被跳过了,但我仍然没有看到任何变化。我不知道“-INSERT”命令实际上在幕后做了多少魔术,但是在.NET中复制它是否可行?或者它是否可以作为普通方法调用(而不是作为发送给 AutoCAD 处理的文本命令)?
回答by Kratz
The code example in the Through the Interface post, imports the blocks, but does not insert them into the drawing. You have to create a BlockReferenceand add it to the model space. It also inserts all the blocks from the file, not the file as a single block.
通过接口帖子中的代码示例导入块,但不会将它们插入到图形中。您必须创建一个BlockReference并将其添加到模型空间中。它还插入文件中的所有块,而不是将文件作为单个块插入。
Here is the code I use to import a file as a whole block. This function returns a block reference you can insert into your drawing.
这是我用来将文件作为一个整体导入的代码。此函数返回一个块参考,您可以将其插入到图形中。
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
Here would be the example of using that function to insert a block into the file. In this example I use a jig, which allows the user to drop the object onto a location they want, otherwise you could just set the position.
下面是使用该函数将块插入文件的示例。在这个例子中,我使用了一个夹具,它允许用户将对象放到他们想要的位置,否则你可以只设置位置。
' 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
And here is also the CheckLayerfunction I called.
这也是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
Just as a note, Kean's blog is a great resources, I pretty much learned all of the above code from there.
请注意,Kean 的博客是一个很好的资源,我几乎从那里学到了上述所有代码。
For completeness sake, here is the Jig class i reference in the insert code,
为了完整起见,这里是插入代码中引用的 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
One note regarding working in .NET ObjectARX, there is a an issue with the single threaded nature of AutoCAD, and the fact that the .NET garbage collector runs on a separate thread. If you create any temporary AutoCAD objects that do not get added to the database, you must explicity call .Dispose()on them, or AutoCAD may crash! The crash will seem random too, since it will be triggered by the garbage collector thread. See this post, http://through-the-interface.typepad.com/through_the_interface/2008/06/cleaning-up-aft.html.
关于在 .NET ObjectARX 中工作的一个注意事项,AutoCAD 的单线程特性存在一个问题,并且 .NET 垃圾收集器在单独的线程上运行这一事实。如果您创建了任何未添加到数据库中的临时 AutoCAD 对象,您必须明确调用.Dispose()它们,否则 AutoCAD 可能会崩溃!崩溃似乎也是随机的,因为它将由垃圾收集器线程触发。请参阅这篇文章,http://through-the-interface.typepad.com/through_the_interface/2008/06/cleaning-up-aft.html。

