We're trying to convert VB to VB.Net and need some pointers to get it up and running. We need to go through all blocks and search for an attribute called "REV" in a .dwg drawing. We then need to read the value into the "Revision" variable.
'' Get revision character
Dim blk As Object
Dim varAttributes As Object
Dim blockrefobj As AcadBlockReference <- Not defined
Dim i As Integer
Dim Revision As String
Dim AcadApp As Application
AcadApp = GetObject(, "AutoCAD.Application.17")
Dim thisDrawing As Object = Application.DocumentManager.MdiActiveDocument.AcadDocument()
For Each blk In thisDrawing.Modelspace()
If blk.EntityName = "AcDbBlockReference" Then
blockrefobj = blk
If blockrefobj.HasAttributes Then
varAttributes = blockrefobj.GetAttributes
For i = LBound(varAttributes) To UBound(varAttributes)
If varAttributes(i).TagString = "REV" Then
Revision = varAttributes(i).TextString
End If
Next i
End If
End If
Next
Do someone have some tips that could help us in the right direction?
Thanks in advance!
Best regards
B&A
Solved! Go to Solution.
Solved by Alfred.NESWADBA. Go to Solution.
Hi,
find the code for doing your job, not built for COM-handling. Using transactions makes it much faster!
'On Top of your Class/Module you have to set: Import Autodesk.AutoCAD Public Sub RevisionChange(ByVal RevStr As String) Dim tAcadDoc As ApplicationServices.Document = Nothing Dim tAcadDocLock As ApplicationServices.DocumentLock = Nothing Dim tTrAct As DatabaseServices.Transaction = Nothing Try tAcadDoc = ApplicationServices.Application.DocumentManager.MdiActiveDocument tAcadDocLock = tAcadDoc.LockDocument tTrAct = tAcadDoc.TransactionManager.StartTransaction Dim tBlTab As DatabaseServices.BlockTable = CType(tTrAct.GetObject(tAcadDoc.Database.BlockTableId, DatabaseServices.OpenMode.ForRead), DatabaseServices.BlockTable) Dim tModelSpace As DatabaseServices.BlockTableRecord = CType(tTrAct.GetObject(tBlTab("MODEL_SPACE"), DatabaseServices.OpenMode.ForRead), DatabaseServices.BlockTableRecord) For Each tDbObjID As DatabaseServices.ObjectId In tModelSpace If (tDbObjID.IsValid) AndAlso (Not tDbObjID.IsErased) AndAlso (tDbObjID.ObjectClass.DxfName = "INSERT") Then 'ok, now we know that we have the objectid of a blockreference Dim tBlRef As DatabaseServices.BlockReference = CType(tTrAct.GetObject(tDbObjID, DatabaseServices.OpenMode.ForRead), DatabaseServices.BlockReference) If (tBlRef.AttributeCollection IsNot Nothing) AndAlso (tBlRef.AttributeCollection.Count > 0) Then 'now we know, this BlockReference has attributes, let's scan through them For Each tAttRefID As DatabaseServices.ObjectId In tBlRef.AttributeCollection If (tAttRefID.IsValid) AndAlso (Not tAttRefID.IsErased) Then Dim tAttRef As DatabaseServices.AttributeReference = CType(tTrAct.GetObject(tAttRefID, DatabaseServices.OpenMode.ForRead), DatabaseServices.AttributeReference) If tAttRef.Tag.ToUpper = "REV" Then tAttRef.TextString = RevStr Exit For 'we need not scan through more attributes as we found "REV" in the collection of this BlockReference End If End If Next End If End If Next tTrAct.Commit() Catch ex As Exception Call MsgBox("Error executing 'RevisionChange'" & vbNewLine & ex.Message) Finally If tTrAct IsNot Nothing Then tTrAct.Dispose() : tTrAct = Nothing If tAcadDocLock IsNot Nothing Then tAcadDocLock.Dispose() : tAcadDocLock = Nothing End Try End Sub
Just wrote, not verified, so be careful running this on drawings without saving before 😉
- alfred -
Hi,
sorry, 2 mistakes:
1) in the first line: Imports Autodesk.AutoCAD 'here one "s" was missing
2) and before setting the TextString of the AttributeReference, it has to be opened ForWrite ... and not ForRead!
Sorry, -alfred -
Thank you for a quick response. We just want to read the attribute not change it. So the 2. point you raise seems to be correct already. However we get this error when running the code: "Error executing 'RevisionChange' eKeyNotFound".
Best regards
B&A
Hi,
lost a star in this (now corrected) line:
Dim tModelSpace As DatabaseServices.BlockTableRecord = CType(tTrAct.GetObject(tBlTab("*MODEL_SPACE"), DatabaseServices.OpenMode.ForRead), DatabaseServices.BlockTableRecord)
>> We just want to read the attribute not change it
In this case I don't understand, why you scan through the complete model-space. If you look for a title-block to get the revision it would be much faster to do a select and not to go through maybe thousands of entities.
- alfred -
That worked perfect! Thank you very much, you made our day!
Best Regards
B&A
You can also get Modelspace like this
Function getModelSpace(ByRef tr As Transaction, ByRef db As Database) As BlockTableRecord Dim rtnBTR As BlockTableRecord = Nothing Dim bt As BlockTable = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable) For Each btrId As ObjectId In bt Dim btr As BlockTableRecord = DirectCast(tr.GetObject(btrId, OpenMode.ForRead), BlockTableRecord) If btr.IsLayout AndAlso btr.Name.ToUpper() = BlockTableRecord.ModelSpace.ToUpper() Then rtnBTR = btr Exit For End If Next Return rtnBTR End Function
You could, but I wouldn't...
Most times I get the model (or paper) space by the OwnerId of an object I have selected. This example would have to select the block first using a filter (like alfred already suggested).
If I must open ModelSpace without having a preselected child, then I use
SymbolUtilityServices.GetBlockModelSpaceId ( db as Database) As ObjectId
to get the ObjectId. As you can see from the signature, it has the added benefit of a Database argument, so it even works when you are working with a side database, like when you use ReadDwgFile.
chiefbraincloud,
You win the shortest code contest.
Thanks