Hi,
I’m new to this and I do need to understand better how to access the BTR, read and write BRef, attDef, AttRef etc. But this has me stumped. There are a few different examples but can’t find anything that works and don't know why.
I have inserted a block in modelspace, I have the BlockRefID and now want to change its attribute values.
This finds the attributes tags but doesn’t write the sValue. Can anyone spot why it isn’t writing the value to the block or suggest something better
Public Sub ChangeAttributeValue(ByVal BlockRefID As ObjectId, ByVal sTagName As String, ByVal sValue As String)
Dim doc As Document = Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim tr As Transaction = db.TransactionManager.StartTransaction()
Dim br As BlockReference = DirectCast(tr.GetObject(BlockRefID, OpenMode.ForWrite), BlockReference)
Dim RefBTR As BlockTableRecord = tr.GetObject(br.BlockTableRecord, OpenMode.ForRead)
Dim attEnt As Entity
Try
For Each attID As ObjectId In RefBTR
attEnt = tr.GetObject(attID, OpenMode.ForRead)
If TypeOf attEnt Is AttributeDefinition Then
Dim attDef As AttributeDefinition = attEnt
Dim attRef As AttributeReference = New AttributeReference()
attRef.SetAttributeFromBlock(attDef, br.BlockTransform)
If attRef.Tag = sTagName Then
attRef.TextString = sValue
Exit Sub
End If
End If
Next
Catch ex As Autodesk.AutoCAD.Runtime.Exception
tr.Abort()
Finally
tr.Commit()
End Try
End Sub
Hope someone can help.
Solved! Go to Solution.
Solved by chiefbraincloud. Go to Solution.
The code you have there is not doing what you think it's doing.
What you have done is opened the block definition, created a New Attribute Reference, set it's value, then threw it in the trash.
What you need to do is skip the BlockTableRecord (definition). Open the BlockReference as you have done, then change your For Each to:
For Each AttRefId in br.AttributeCollection
dim AttRef as AttributeReference = tr.GetObject(AttRefId, OpenMode.ForWrite, false, true)
If AttRef.Tag = sTagName then
.....
End If
Next
Thanks Chief,
Thats one of the few things I've tried. A similar procedure works fine with the dynamic block properties.
Strange thing is that the blockref (br) does show the 27 items in the DynamicBlockReferencePropertyCollection (which I can access and change) but 0 items in the AttributeColection when it has 3 Attributes.
I should have copied the code changes you suggested but the result is the same. 0 AttRefs in the collection.
I think the problem is my Addblock routine. It adds a block reference but without any attributes. Why would it do that?
Basically this tells me you did not properly add the Attribute References to the BlockReference when it was inserted, a process which was not necessary if coding in VBA or .NET COM automation, or LSP.
The For Each loop you had in your original post is just short of what is needed to accomplish that.
I see that while I have been typing and searching Through The Interface for an example you have arrived at the same conclusion.
Give me a minute, I'll find an example.
I really hate the way this forum mangles code pasted directly from Visual studio
Anyway, I couldn't find the blog post I was looking for, so I just tweeked the code you posted. Note, I changed the variable name for the ModelSpace BlockTableRecord, just to reduce confusion, and I inserted the necessary block of code for adding the attributes. As you read it, you'll see there is not really anything magical going on, it's just that with other forms of autocad automation, this was never necessary before. Changes Highlighted.
Public Sub AddBlock(ByVal blockname)
Dim db As Database = HostApplicationServices.WorkingDatabase()
Using tr As Transaction = db.TransactionManager.StartTransaction()
' Test if block exists in the block table
Dim bt As BlockTable = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
Dim id As ObjectId = bt(blockname)
Dim btr As BlockTableRecord = tr.GetObject(id, OpenMode.ForRead, False, True)
Dim br As New BlockReference(New Point3d(0, 0, 0), id)
Dim MS As BlockTableRecord = DirectCast(tr.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite), BlockTableRecord)
' Add the block reference to Model space
MS.AppendEntity(br)
tr.AddNewlyCreatedDBObject(br, True)
If btr.HasAttributeDefinitions Then
Dim AtDef As AttributeDefinition, AttRef As AttributeReference
For Each SubEntId As ObjectId In btr
If SubEntId.ObjectClass.Name = "AcDbAttributeDefinition" Then
AtDef = tr.GetObject(SubEntId, OpenMode.ForRead, False, True)
AttRef = New AttributeReference
AttRef.SetAttributeFromBlock(AtDef, br.BlockTransform)
br.AttributeCollection.AppendAttribute(AttRef)
tr.AddNewlyCreatedDBObject(AttRef, True)
AtDef.Dispose()
AttRef.Dispose()
End If
Next
End If
BlockRefID = br.ObjectId
' Commit the transaction
tr.Commit()
End Using
End Sub
Thanks so much!!
Been stumbling around for quite a while. At least I have a slightly better understanding now.