I am trying to change a text in attribute using vb.net.
I am using the following sub to update my attribute, if I use the message box I get correct information about the block, the attribute.tag I want to change and the text. The changes to my attribute are not saved.
Sub UpdateAttributeValue(ByVal BlockID AsObjectId, ByVal AttributeTag AsString, ByVal TextaStr AsString)
Using myTrans AsTransaction = BlockID.Database.TransactionManager.StartTransaction
Dim myBRef AsBlockReference = BlockID.GetObject(OpenMode.ForRead)
Dim myAttCollection AsAttributeCollection = myBRef.AttributeCollection
ForEach myAttRefID AsObjectIdIn myAttCollection
Dim myAttRef AsAttributeReference = myAttRefID.GetObject(OpenMode.ForWrite)
If myAttRef.Tag.Equals(AttributeTag, StringComparison.OrdinalIgnoreCase) = True Then
myAttRef.TextString = TextaStr
'MsgBox(myBRef.Name & " - " & myAttRef.Tag & " - " & myAttRef.TextString)
Exit For
End If
Next
myTrans.Commit()
EndUsing
End Sub
I do not know what exactly your code problem but Try that it works fine
Public Sub SetAttribute(ByVal BlockID As Autodesk.AutoCAD.DatabaseServices.ObjectId, ByVal blckname As String, ByVal AttTag As String, ByVal AttVal As String) Dim MyDb As Database = Application.DocumentManager.MdiActiveDocument.Database If BlockID.IsNull Then Exit Sub Try Using myTrans As Transaction = MyDb.TransactionManager.StartTransaction Dim myBlckRef As BlockReference Dim myAttColl As AttributeCollection Dim myBlckTable As BlockTableRecord myBlckRef = BlockID.GetObject(OpenMode.ForWrite) If myBlckRef.IsDynamicBlock Then myBlckTable = myTrans.GetObject(myBlckRef.DynamicBlockTableRecord, OpenMode.ForRead) Else myBlckTable = myTrans.GetObject(myBlckRef.BlockTableRecord, OpenMode.ForRead) End If If String.Compare(myBlckTable.Name, blckname, True) = 0 Then myAttColl = myBlckRef.AttributeCollection Dim myEnt As Autodesk.AutoCAD.DatabaseServices.ObjectId Dim myAttRef As Autodesk.AutoCAD.DatabaseServices.AttributeReference For Each myEnt In myAttColl myAttRef = myEnt.GetObject(OpenMode.ForWrite) If String.Compare(myAttRef.Tag, AttTag, True) = 0 Then myAttRef.TextString = AttVal.ToString End If Next End If myTrans.Commit() End Using Catch ex As Exception End Try End Sub
You have to open BlockReference ForWrite before,
~'J'~
You do NOT have to open the BlockReference ForWrite.
If you were to happen to have the ObjectId of the AttributeReference stored (like from a previous operation maybe) you would not even have to open the BlockReference at all. Opening the BlockReference ForRead is just fine for changing AttributeReferences.
Sorry, have disagreed
OP asked about his wrong logic
He do not have mix both methods to Open object
In the function it is ObjectID.GetObject(blah..)
But in the calling Sub it would be use transaction.GetObject instead
Take a look ath this quick code, I had no problem with them on my A2010
Sub UpdateAttributeValue(ByVal BlockID As ObjectId, ByVal AttributeTag As String, ByVal TextaStr As String) Using myTrans As Transaction = BlockID.Database.TransactionManager.StartTransaction Dim myBRef As BlockReference = DirectCast(myTrans.GetObject(BlockID, OpenMode.ForWrite), BlockReference) Dim myAttCollection As AttributeCollection = myBRef.AttributeCollection For Each myAttRefID As ObjectId In myAttCollection Dim myAttRef As AttributeReference = DirectCast(myTrans.GetObject(myAttRefID, OpenMode.ForWrite), AttributeReference) If myAttRef.Tag = AttributeTag.ToUpper Then myAttRef.TextString = TextaStr 'MsgBox(myBRef.Name & " - " & myAttRef.Tag & " - " & myAttRef.TextString) Exit For End If Next myTrans.Commit() End Using End Sub <CommandMethod("chat")> _ Public Sub chAttValue() Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument Dim db As Database = doc.Database Dim ed As Editor = doc.Editor Dim peo As New PromptEntityOptions(vbLf & "Select block: ") peo.SetRejectMessage(vbLf + "You have to select block only!") peo.AddAllowedClass(GetType(BlockReference), True) Dim per As PromptEntityResult = ed.GetEntity(peo) If per.Status <> PromptStatus.OK Then Return End If Using tr As Transaction = db.TransactionManager.StartTransaction() Dim ent As Entity = TryCast(tr.GetObject(per.ObjectId, OpenMode.ForRead), Entity) Dim bref As BlockReference = TryCast(ent, BlockReference) If bref.AttributeCollection IsNot Nothing Then UpdateAttributeValue(bref.ObjectId, "TAG1", "Value1") End If tr.Commit() End Using End Sub
Regards,
Oleg
I am afraid I don't understand your point. This code works just fine (and has since 2007)
Public Sub SetAttTxt(ByVal BrefID As ObjectId, ByVal AttTag As String, ByVal Val As String) Try Using trans As Transaction = BrefID.Database.TransactionManager.StartTransaction Using Bref As BlockReference = trans.GetObject(BrefID, OpenMode.ForRead, False, True) Dim Alist As AttributeCollection = Bref.AttributeCollection Try For Each AttID As ObjectId In Alist If Not AttID.IsEffectivelyErased Then Dim Ref As AttributeReference = trans.GetObject(AttID, OpenMode.ForRead, False, True) If Ref.Tag = AttTag Then Ref.UpgradeOpen() Ref.TextString = Val trans.Commit() Exit For End If Ref.Dispose() End If Next Catch ex As Exception StdExEd(ex, "Error Setting Attribute Value" & vbCrLf) Finally Alist = Nothing End Try End Using End Using Catch ex As Exception StdExEd(ex, "Error Setting Attributes: Bad ObjectId or No Attribute Collection" & vbCrLf) End Try End Sub
It also still works just the same using the ObjectId.GetObject method, and more importantly, the BlockReference is only opened for Read.
I honestly don't see what is wrong with the OP's code, but it is not that he is opening the BlockReference for Read.