L'exemple de code dans la publication Through the Interface importe les blocs, mais ne les insère pas dans le dessin. Vous devez créer un BlockReference
et l'ajouter à l'espace objet. Il insère également tous les blocs du fichier, pas le fichier comme un seul bloc.
Voici le code que j'utilise pour importer un fichier en bloc entier. Cette fonction renvoie une référence de bloc que vous pouvez insérer dans votre dessin.
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
Voici l'exemple de l'utilisation de cette fonction pour insérer un bloc dans le fichier. Dans cet exemple, j'utilise un gabarit, qui permet à l'utilisateur de déposer l'objet sur l'emplacement souhaité, sinon vous pouvez simplement définir la 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
Et voici aussi la fonction CheckLayer
que j'ai appelée.
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
Tout comme une note, le blog de Kean est un grand ressources, j'appris à peu près tout le code ci-dessus à partir de là.
Pour être complet, voici la classe Jig i référence dans le code d'insertion,
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
Une note concernant le travail dans ObjectARX .NET, il y a un problème avec la nature un seul thread d'AutoCAD, et le fait que le garbage collector .NET s'exécute sur un thread séparé. Si vous créez des objets AutoCAD temporaires qui ne sont pas ajoutés à la base de données, vous devez explicitement appeler le .Dispose()
ou AutoCAD peut tomber en panne! Le crash semblera aléatoire aussi, car il sera déclenché par le thread garbage collector. Voir cet article, http://through-the-interface.typepad.com/through_the_interface/2008/06/cleaning-up-aft.html.
Merci.Je vérifie ça une fois que je serai au travail demain. En outre, j'utilise l'instruction Using sur presque tout, donc tout est disposé (garanti, même avec des exceptions etc.). – Alxandr
Savez-vous s'il existe un moyen simple de faire apparaître autocad avec ses "enter (multiple) attributes (strings)" - fenêtre? Comme, si je viens d'utiliser la commande "-IMPORT", il apparaîtra avec une fenêtre m'indiquant d'entrer "Numéro de Révision" et "Nom de Révision". Puis-je avoir le même comportement d'une certaine manière dans .NET? – Alxandr
Je ne suis pas sûr de cela, mais vous pouvez définir des attributs dans le code afin que vous puissiez toujours afficher votre propre boîte de dialogue Modale pour obtenir les informations. – Kratz