2013-06-27 67 views
3

我的任務是將AutoCAD插件從VBA翻譯爲VB.NET,而且我目前有點卡住了。.NET中的AutoCAD -INSERT命令

我正在處理的命令創建一個新圖層(或者選擇它作爲活動圖層,如果它已經存在),然後執行2個「-INSERT」命令,給出用戶選擇的一個點以及一個dwg文件。然後,前一個活動層被重置爲活動層。

插入命令看起來是這樣的:

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

注:所有在命令中的換行符被添加爲vbCR(不vbCrLf)。

我的問題是,我如何在.NET中實現與ObjectARX相同的結果?我不能使用SendStringToExecute,因爲它是異步的(沒有回調),所以換句話說,當它完成執行後,我無法重置當前層。必須有一些方法可以在純.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處理的文本命令)?

回答

5

Through the Interface帖子中的代碼示例導入塊,但不會將它們插入到圖形中。您必須創建一個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 

正如一個音符,基恩的博客是一個偉大的資源,我幾乎學會了所有上面的代碼從那裏。

爲了完整起見,這裏是夾具類我在插入代碼中引用,在

.NET ObjectARX的
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 

一個說明有關工作,有一個與AutoCAD的單線程性質的問題, .NET垃圾收集器在單獨的線程上運行的事實。如果您創建任何不會添加到數據庫中的臨時AutoCAD對象,則必須明確地在其上調用.Dispose(),否則AutoCAD可能會崩潰!這個崩潰看起來也是隨機的,因爲它會被垃圾收集器線程觸發。看到這篇文章,http://through-the-interface.typepad.com/through_the_interface/2008/06/cleaning-up-aft.html

+0

謝謝。一旦我開始工作,我正在檢查這個。另外,我幾乎在任何事情上都使用Using語句,所以所有事情都得到了處理(保證,即使有例外等)。 – Alxandr

+0

你知道是否有任何簡單的方法讓autocad彈出「輸入(多個)屬性(字符串)」 - 窗口?就像,如果我只是使用「-IMPORT」命令,它會彈出一個窗口告訴我輸入「修訂號」和「修訂名稱」。我可以在.NET中以某種方式獲得相同的行爲嗎? – Alxandr

+0

不確定,但您可以在代碼中設置屬性,以便始終可以顯示自己的模式對話框以獲取信息。 – Kratz