.NET

.NET

Reply
Mentor
mgorecki
Posts: 415
Registered: ‎09-23-2004
Message 1 of 5 (666 Views)
Accepted Solution

Reading and Writing to Block Attributes

666 Views, 4 Replies
09-22-2011 08:52 PM

Hi, this part of my code is supposed to look for a layout I just added, search through it's blocks that have attributes, and if the block with the specific attributes is found, it should open a dialog box and populate the two text boxes with the attribute text.  When the user changes the text in the dialog box and picks ok, I want it to go back and change the attribute values in the block.

I'm just not sure how to change the text value for the attributes.  Do I create an identical code that will search all over again only to write the values instad of read?  There has to be an easier way since I have the block located already.

 

    Public Sub replaceTitleText(ByVal pageNumber As Integer)
        Dim doc As Document = Application.DocumentManager.MdiActiveDocument
        Dim db As Database = doc.Database
        Dim ed As Editor = doc.Editor
        Dim layoutCount As Integer = LayoutManager.Current.LayoutCount - 1

        Dim getTexttrans As Transaction = db.TransactionManager.StartTransaction()
        Try
            Dim myBT As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)
            For Each btrID As ObjectId In myBT
                Dim myBTR As BlockTableRecord = btrID.GetObject(OpenMode.ForRead)
                ' If the block table record is a layout
                If myBTR.IsLayout Then
                    Dim layOut As Layout = myBTR.LayoutId.GetObject(OpenMode.ForRead)
                    ' If the layout is the new layout
                    If layOut.TabOrder = pageNumber Then
                        For Each id As ObjectId In myBTR
                            Dim obj As DBObject = id.GetObject(OpenMode.ForRead)
                            ' If the object is a block reference
                            If TypeOf obj Is BlockReference Then
                                Dim bref As BlockReference = DirectCast(obj, BlockReference)
                                ' If the block reference has attributes
                                If bref.AttributeCollection.Count <> 0 Then
                                    For Each attId As ObjectId In bref.AttributeCollection
                                        Dim attRef As AttributeReference = attId.GetObject(OpenMode.ForRead)
                                        ' If the title block has the "PAGE_TITLE" or "DIE_SIDE_VIEW" attribute
                                        ' get the current text values for the attributes
                                        Dim textTitle As String = ""
                                        Dim textDieSide As String = ""

                                        If attRef.Tag = "PAGE_TITLE" Then
                                            textTitle = attRef.TextString
                                        End If
                                        If attRef.Tag = "DIE_SIDE_VIEW" Then
                                            textDieSide = attRef.TextString
                                            'diaTitleText.txtDieSide.Visible = True
                                        End If
                                        ' If the block has either one of these attributes
                                        If Not textTitle = "" Or Not textDieSide = "" Then
                                            Dim diaTitleText As dialogTitleText = New dialogTitleText(textTitle, textDieSide)
                                            'diaTitleText.ShowDialog()
                                            If diaTitleText.ShowDialog = System.Windows.Forms.DialogResult.OK Then
                                                textTitle = diaTitleText.newTextTitle
                                                textDieSide = diaTitleText.newTextDieSide
                                            End If
                                        End If
                                    Next
                                End If
                            End If
                        Next
                    End If
                End If
            Next
        Catch
            ed.WriteMessage("Error!")
        Finally

            getTexttrans.Commit()
        End Try
End Sub

 

 

Hi,

 

>> Do I create an identical code that will search all over again only to write the values instad of read?

No, you could save the ObjectID of the AttributeReference and reopen it (writeable) when finished with the dialog and the values changed.

For Each attId As ObjectId In bref.AttributeCollection
Dim attRef As AttributeReference = attId.GetObject(OpenMode.ForRead)
' If the title block has the "PAGE_TITLE" or "DIE_SIDE_VIEW" attribute
' get the current text values for the attributes
Dim textTitle As String = ""
Dim textDieSide As String = ""
'CHANGE 1: prepare variables for the ObjectID of the AttRefs
Dim textTitleAttRefID as ObjectID
Dim textDieSideAttRefID as ObjectID
'CHANGE 1 end
If attRef.Tag = "PAGE_TITLE" Then
textTitle = attRef.TextString
textTitleAttRefID = attRef.ObjectID 'CHANGE 2 save the ObjectID
End If
If attRef.Tag = "DIE_SIDE_VIEW" Then
textDieSide = attRef.TextString
'diaTitleText.txtDieSide.Visible = True
textDieSideAttRefID = attRef.ObjectID 'CHANGE 3: save the ObjectID
End If
' If the block has either one of these attributes
If Not textTitle = "" Or Not textDieSide = "" Then
Dim diaTitleText As dialogTitleText = New dialogTitleText(textTitle, textDieSide)
'diaTitleText.ShowDialog()
If diaTitleText.ShowDialog = System.Windows.Forms.DialogResult.OK Then
'CHANGE 4: open the AttRef's for write and save the new textvalues
if textTitle <> diaTitleText.newTextTitle Then
'only overwrite when value has changed
textTitle = diaTitleText.newTextTitle
if textTitleAttRefID.isValid Then 'check if the AttRef exists (seems as it does not have to exist)
Dim tAttRefWRITE as AttributeReference = ctype(getTexttrans.GetObject(textTitleAttRefID,OpenMode.ForWrite),AttributeReference)
tAttRefWRITE.TextString = textTitle
end if
end if
if textDieSide <> diaTitleText.newTextDieSideThen
'only overwrite when value has changed
textDieSide = diaTitleText.newTextDieSideThen
if textDieSideAttRefID.isValid Then 'check if the AttRef exists (seems as it does not have to exist)
Dim tAttRefWRITE as AttributeReference = ctype(getTexttrans.GetObject(textDieSideAttRefID, OpenMode.ForWrite),AttributeReference)
tAttRefWRITE.TextString = textDieSideAttRefID
end if
end if
'CHANGE 5: you can remove this as it is built in CHANGE 4
'textTitle = diaTitleText.newTextTitle
'textDieSide = diaTitleText.newTextDieSide
End If
End If
Next

Hope I have not overlooked something.

 

One more input to your code:

You set the .Commit for the transaction within the Finally-Statement (of the Try-Catch).

What does that mean? Finally runs after Catch, so it will also run if the code crashed somewhere within the Try-section. IMHO that does not make sense to .Commit the transaction even not knowing if the code run clean or failed. I would prefere to set the .Commit-statement in the Try-section/last code-line before Catch. So I know if this code-line is reached there was no error so far.

And there is a second problem you can solve with my version: Sometimes the .Commit itself throws an exception, every time it should commit something where object-creations or database-modifications where not prepared well. And for this exception you are out of a Try- and not before a Catch-section! That means this exception will throw up to the next/hierarchically above Catch ... if you have one ... if not AutoCAD crashes!

 

Hope my description is understandable and helps, good luck, - alfred -

*Expert Elite*
Alfred.NESWADBA
Posts: 9,583
Registered: ‎06-29-2007
Message 2 of 5 (652 Views)

Betreff: Reading and Writing to Block Attributes

09-23-2011 12:00 AM in reply to: mgorecki

Hi,

 

>> Do I create an identical code that will search all over again only to write the values instad of read?

No, you could save the ObjectID of the AttributeReference and reopen it (writeable) when finished with the dialog and the values changed.

For Each attId As ObjectId In bref.AttributeCollection
  Dim attRef As AttributeReference = attId.GetObject(OpenMode.ForRead)
  ' If the title block has the "PAGE_TITLE" or "DIE_SIDE_VIEW" attribute
  ' get the current text values for the attributes
  Dim textTitle As String = ""
  Dim textDieSide As String = ""

  'CHANGE 1: prepare variables for the ObjectID of the AttRefs
  Dim textTitleAttRefID as ObjectID
  Dim textDieSideAttRefID as ObjectID
  'CHANGE 1 end

  If attRef.Tag = "PAGE_TITLE" Then
    textTitle = attRef.TextString
    textTitleAttRefID = attRef.ObjectID   'CHANGE 2 save the ObjectID
  End If
  If attRef.Tag = "DIE_SIDE_VIEW" Then
    textDieSide = attRef.TextString
    'diaTitleText.txtDieSide.Visible = True
    textDieSideAttRefID = attRef.ObjectID 'CHANGE 3: save the ObjectID
  End If
    ' If the block has either one of these attributes
  If Not textTitle = "" Or Not textDieSide = "" Then
    Dim diaTitleText As dialogTitleText = New dialogTitleText(textTitle, textDieSide)
    'diaTitleText.ShowDialog()
    If diaTitleText.ShowDialog = System.Windows.Forms.DialogResult.OK Then
      
      'CHANGE 4: open the AttRef's for write and save the new textvalues
      if textTitle <> diaTitleText.newTextTitle Then
        'only overwrite when value has changed
        textTitle = diaTitleText.newTextTitle
        if textTitleAttRefID.isValid Then  'check if the AttRef exists (seems as it does not have to exist)
          Dim tAttRefWRITE as AttributeReference = ctype(getTexttrans.GetObject(textTitleAttRefID,OpenMode.ForWrite),AttributeReference)
          tAttRefWRITE.TextString = textTitle 
        end if
      end if
      if textDieSide <> diaTitleText.newTextDieSideThen
        'only overwrite when value has changed
        textDieSide = diaTitleText.newTextDieSideThen
        if textDieSideAttRefID.isValid Then  'check if the AttRef exists (seems as it does not have to exist)
          Dim tAttRefWRITE as AttributeReference = ctype(getTexttrans.GetObject(textDieSideAttRefID, OpenMode.ForWrite),AttributeReference)
          tAttRefWRITE.TextString = textDieSideAttRefID 
        end if
      end if

      'CHANGE 5: you can remove this as it is built in CHANGE 4
      'textTitle = diaTitleText.newTextTitle
      'textDieSide = diaTitleText.newTextDieSide
    End If
  End If
Next

Hope I have not overlooked something.

 

One more input to your code:

You set the .Commit for the transaction within the Finally-Statement (of the Try-Catch).

What does that mean? Finally runs after Catch, so it will also run if the code crashed somewhere within the Try-section. IMHO that does not make sense to .Commit the transaction even not knowing if the code run clean or failed. I would prefere to set the .Commit-statement in the Try-section/last code-line before Catch. So I know if this code-line is reached there was no error so far.

And there is a second problem you can solve with my version: Sometimes the .Commit itself throws an exception, every time it should commit something where object-creations or database-modifications where not prepared well. And for this exception you are out of a Try- and not before a Catch-section! That means this exception will throw up to the next/hierarchically above Catch ... if you have one ... if not AutoCAD crashes!

 

Hope my description is understandable and helps, good luck, - alfred -

-------------------------------------------------------------------------
Alfred NESWADBA
Ingenieur Studio HOLLAUS ... www.hollaus.at
-------------------------------------------------------------------------
Mentor
mgorecki
Posts: 415
Registered: ‎09-23-2004
Message 3 of 5 (616 Views)

Betreff: Reading and Writing to Block Attributes

09-27-2011 09:13 AM in reply to: Alfred.NESWADBA

Hi Alfred,

Thank you very much for your help.  I did what you suggested and after a few tweaks of my own, the code works great!

Public Sub replaceTitleText(ByVal pageNumber As Integer)
        Dim doc As Document = Application.DocumentManager.MdiActiveDocument
        Dim db As Database = doc.Database
        Dim ed As Editor = doc.Editor
        Dim layoutCount As Integer = LayoutManager.Current.LayoutCount - 1
        Dim textTitle As String = ""
        Dim textDieSide As String = ""

        Dim getTexttrans As Transaction = db.TransactionManager.StartTransaction()
        Try
            Dim myBT As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)
            For Each btrID As ObjectId In myBT
                Dim myBTR As BlockTableRecord = btrID.GetObject(OpenMode.ForRead)
                ' If the block table record is a layout
                If myBTR.IsLayout Then
                    Dim layOut As Layout = myBTR.LayoutId.GetObject(OpenMode.ForRead)
                    ' If the layout is the new layout
                    If layOut.TabOrder = pageNumber Then
                        For Each id As ObjectId In myBTR
                            Dim obj As DBObject = id.GetObject(OpenMode.ForRead)
                            ' If the object is a block reference
                            If TypeOf obj Is BlockReference Then
                                Dim bref As BlockReference = DirectCast(obj, BlockReference)
                                ' If the block reference has attributes
                                Dim attCounter As Integer = 1
                                If bref.AttributeCollection.Count <> 0 Then
                                    For Each attId As ObjectId In bref.AttributeCollection
                                        Dim attRef As AttributeReference = attId.GetObject(OpenMode.ForRead)
                                        ' If the title block has the "PAGE_TITLE" or "DIE_SIDE_VIEW" attribute
                                        ' get the current text values for the attributes
                                        Dim textTitleAttRefID As ObjectId
                                        Dim textDieSideAttRefID As ObjectId

                                        If attRef.Tag = "PAGE_TITLE" Then
                                            textTitle = attRef.TextString
                                            textTitleAttRefID = attRef.ObjectId
                                        End If
                                        If attRef.Tag = "DIE_SIDE_VIEW" Then
                                            textDieSide = attRef.TextString
                                            textDieSideAttRefID = attRef.ObjectId
                                        End If
                                        ' If all of the attributes in the block have been checked
                                        If attCounter = bref.AttributeCollection.Count Then
                                            Dim diaTitleText As dialogTitleText = New dialogTitleText(textTitle, textDieSide)
                                            If diaTitleText.ShowDialog = System.Windows.Forms.DialogResult.OK Then
                                                ' Open the AttRef's for write and save the new textvalues
                                                If textTitle <> diaTitleText.txtSheetTitle.Text Then
                                                    ' Only overwrite when value has changed
                                                    textTitle = diaTitleText.txtSheetTitle.Text
                                                    If textTitleAttRefID.IsValid Then  'check if the AttRef exists
                                                        Dim tAttRefWRITE As AttributeReference = CType(getTexttrans.GetObject(textTitleAttRefID, OpenMode.ForWrite), AttributeReference)
                                                        tAttRefWRITE.TextString = textTitle
                                                    End If
                                                End If
                                                If Not textDieSide = "" Then
                                                    If textDieSide <> diaTitleText.txtDieSide.Text Then
                                                        ' Only overwrite when value has changed
                                                        textDieSide = diaTitleText.txtDieSide.Text
                                                        If textDieSideAttRefID.IsValid Then  'check if the AttRef exists
                                                            Dim tAttRefWRITE As AttributeReference = CType(getTexttrans.GetObject(textDieSideAttRefID, OpenMode.ForWrite), AttributeReference)
                                                            tAttRefWRITE.TextString = textDieSide
                                                        End If
                                                    End If
                                                End If
                                            End If
                                        End If
                                        attCounter += 1
                                    Next
                                End If
                            End If
                        Next
                    End If
                End If
            Next
        Catch
            ed.WriteMessage("Error!")
        Finally
            getTexttrans.Commit()
        End Try
    End Sub

 Again, thanks a lot.

Mark

Contributor
jamkhp
Posts: 24
Registered: ‎05-19-2011
Message 4 of 5 (495 Views)

Betreff: Reading and Writing to Block Attributes

01-03-2012 10:04 PM in reply to: mgorecki

 Hi I had a smimilar requirement, but  a little change, I would like to read the contents of the Titleblock and write it down to xl file, but the block is there in the model space, so here is what I have done, please suggest me that is there any other way so that I can improvise this code. thanks in advance

 

Public Sub ReadData(ByVal fName As String)
        Dim acdoc As Document = Application.DocumentManager.Open(fName, False, Nothing)
        acdoc = Application.DocumentManager.MdiActiveDocument
        Dim acCurDb As Database = acdoc.Database
        Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
            Using mydoclock As DocumentLock = acdoc.LockDocument()
                Try
                    Dim acBlkTbl As BlockTable = acCurDb.BlockTableId.GetObject(OpenMode.ForRead)
                    For Each acOjbid As ObjectId In acBlkTbl
                        Dim acBlkTblRec As BlockTableRecord = acOjbid.GetObject(OpenMode.ForRead)
                        For Each accObjId As ObjectId In acBlkTblRec
                            Dim acObj As DBObject = accObjId.GetObject(OpenMode.ForRead)
                            If TypeOf acObj Is BlockReference Then
                                Dim acBlkRef As BlockReference = DirectCast(acObj, BlockReference)
                                Dim acAttCount As Integer = 1
                                If acBlkRef.AttributeCollection.Count <> 0 Then
                                    For Each acAttId As ObjectId In acBlkRef.AttributeCollection
                                        Dim acAttRef As AttributeReference = acAttId.GetObject(OpenMode.ForRead)
                                        Dim macNum As String = ""
                                        Dim drgName As String = ""
                                        Dim drgNum As String = ""
                                        If acAttRef.Tag = "MACHINE_NO" Then

                                           ' Here I take the string and put in xl in another sub, for sake of simplicity I just used the msgbox
                                            MsgBox(acAttRef.TextString)
                                        End If
                                    Next
                                End If
                            End If
                        Next
                    Next
                Catch ex As System.Exception
                    MsgBox("This drawing does not contain and blocks")
                End Try
               
            End Using
        End Using
        acCurDb.Dispose()
        acdoc.CloseAndDiscard()

    End Sub

*Expert Elite*
Hallex
Posts: 1,569
Registered: ‎10-08-2008
Message 5 of 5 (487 Views)

Betreff: Reading and Writing to Block Attributes

01-04-2012 02:35 AM in reply to: jamkhp

I think for the particular block you might be want to use:

 

 

#Region "Read Attributes to Excel"
        <CommandMethod("ReadTitleBlockToExcel", "readbx", CommandFlags.Session)> _
     
   Public Sub TestCmd()
      
      ReadData("C:\Test\Temp\Title-1.dwg", "TitleBlock")
     
   End Sub

    
    Public Sub ReadData(ByVal fName As String, ByVal blkname As String)
     
       Dim acdoc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.Open(fName, False, Nothing)
          
  acdoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
    
        Dim acCurDb As Database = acdoc.Database
       
     Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
       
         Using mydoclock As DocumentLock = acdoc.LockDocument()
           
         Try
             
           Dim acBlkTbl As BlockTable = acCurDb.BlockTableId.GetObject(OpenMode.ForRead)
             
           If Not acBlkTbl.Has(blkname) Then
           
                 MsgBox("Block " + blkname + " does not exist")
             
               Exit Sub
            
            End If
              
          Dim btrec As BlockTableRecord = DirectCast(acTrans.GetObject(acBlkTbl(blkname), OpenMode.ForRead, False), BlockTableRecord)
                  
      Dim idcoll As ObjectIdCollection = btrec.GetBlockReferenceIds(True, True)

                        For Each id As ObjectId In idcoll
 
                            Dim acObj As DBObject = id.GetObject(OpenMode.ForRead)
                        
    If TypeOf acObj Is BlockReference Then
                        
        Dim acBlkRef As BlockReference = DirectCast(acObj, BlockReference)
                             
   Dim acAttCount As Integer = 1
                          
      If acBlkRef.AttributeCollection.Count <> 0 Then
                          
          For Each acAttId As ObjectId In acBlkRef.AttributeCollection
                        
                Dim acAttRef As AttributeReference = acAttId.GetObject(OpenMode.ForRead)
                       
                 Dim macNum As String = ""
                             
           Dim drgName As String = ""
                            
            Dim drgNum As String = ""
                             
           If acAttRef.Tag = "MACHINE_NO" Then
                                    
        'collect data here then pass it to XL after
                                   
         ' Here I take the string and put in xl in another sub, for sake of simplicity I just used the msgbox
                                
            MsgBox(acAttRef.TextString)
                           
             End If
                        
            Next
                    
            End If
                   
         End If
                    
    Next


                
    Catch ex As System.Exception
                   
     MsgBox("This drawing does not contain and blocks")
               
     End Try

          
      End Using
          
  End Using

            acdoc.CloseAndDiscard()

        End Sub

#End Region

 

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Announcements
Do you have 60 seconds to spare? The Autodesk Community Team is revamping our site ranking system and we want your feedback! Please click here to launch the 5 question survey. As always your input is greatly appreciated.