.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Change Attributes in individual drawing block by pick it.

6 REPLIES 6
Reply
Message 1 of 7
muckmailer
1432 Views, 6 Replies

Change Attributes in individual drawing block by pick it.

Is there a VB.net routine to change attributes in an individual drawing block
that is selected. I have looked at routines the change the block reference
but that changes all drawing blocks in a drawing.

 

Thank you,

 

6 REPLIES 6
Message 2 of 7
BlackBox_
in reply to: muckmailer

This blog post should get you started:

 

http://through-the-interface.typepad.com/through_the_interface/2007/07/updating-a-spec.html

 

 

 

Cheers



"How we think determines what we do, and what we do determines what we get."

Message 3 of 7
Ron_M
in reply to: BlackBox_

I'm actually currently working on just such a routine.  At this time I've handled block selection, dynamic form build from the attribute prompts in the block, and at this time have it spit back out the text entered in the form textboxes.  I'm working on putting together the text from the form and the value of the attributes in the block.  If I get it done I'll be sure to share.  Code below as it sits now.  Not cleaned up obviously.  If anyone has any suggestions on how to get from txtarray(z) to the attribute value in the selected block I would be very appreciative.

 

Imports System
Imports System.IO
Imports System.Collections.Specialized
Imports System.Windows

Imports Autodesk.AutoCAD
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.Windows
Imports Autodesk.AutoCAD.Internal
Imports Autodesk.AutoCAD.Interop
Imports Autodesk.AutoCAD.ComponentModel
Imports Autodesk.AutoCAD.GraphicsInterface
Imports Autodesk.AutoCAD.GraphicsSystem
Imports Autodesk.AutoCAD.LayerManager
Imports Autodesk.AutoCAD.PlottingServices
Imports Autodesk.AutoCAD.Publishing

Public Class EditAtt
    Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument   'Current drawing
    Dim db As Database = acDoc.Database                                     'Current drawing database
    Dim ed As Editor = acDoc.Editor                                         'Current drawing editor
    Dim x As Integer = 0
    Dim y As Integer = 0
    Dim tbname As String = Nothing
    Dim tb As System.Windows.Forms.TextBox
    Dim lb As System.Windows.Forms.Label
    Public Property promptlist As New List(Of String)()
    Public Property taglist As New List(Of String)()

    <CommandMethod("ea")> _
    Public Sub EditAtt()
        Dim form1 As EditAtt
        form1 = New EditAtt()
        Application.ShowModelessDialog(form1)
        form1 = Nothing
    End Sub

    Public Sub EditAtt_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim FilterList(0) As TypedValue
        FilterList.SetValue(New TypedValue(CInt(DxfCode.Start), "INSERT"), 0)
        Dim filter As New SelectionFilter(FilterList)
        Dim opts As New PromptSelectionOptions()
        Try
            opts.MessageForAdding = "Select a block with text to edit: "
            opts.SingleOnly = True
            Dim res As PromptSelectionResult = ed.GetSelection(opts, filter)
            If res.Status <> PromptStatus.OK Then
                Application.ShowAlertDialog("Try to select a block next time.")
                Exit Sub
            Else
            End If
            Dim selSet As SelectionSet = res.Value
            Dim idArray() As ObjectId = selSet.GetObjectIds
            Using tr As Transaction = db.TransactionManager.StartTransaction
                For Each blkId As ObjectId In idArray
                    Dim blkRef As BlockReference = CType(tr.GetObject(blkId, OpenMode.ForRead), BlockReference)
                    Dim bt As BlockTable = tr.GetObject(db.BlockTableId, OpenMode.ForRead)
                    Dim btr As BlockTableRecord = CType(tr.GetObject(bt(blkRef.Name), OpenMode.ForRead), BlockTableRecord)
                    If btr.HasAttributeDefinitions Then
                        Dim blkname As String = blkRef.Name.ToString
                        For Each ObjId As ObjectId In btr
                            Dim obj As Entity = tr.GetObject(ObjId, OpenMode.ForRead)
                            If TypeOf obj Is AttributeDefinition Then
                                Dim AttDef As AttributeDefinition = obj
                                taglist.Add(AttDef.Tag)
                                promptlist.Add(AttDef.Prompt)
                                Dim prmt As String = promptlist(x)
                                tbname = "textbox" & x
                                Dim frm1 As New System.Windows.Forms.Form
                                lb = New System.Windows.Forms.Label
                                With lb
                                    .Size = New System.Drawing.Size(100, 40)
                                    .Location = New System.Drawing.Point(20, x * 50 + 45)
                                    .Text = prmt
                                End With
                                tb = New System.Windows.Forms.TextBox
                                With tb
                                    .Name = "tb" & x
                                    .Size = New System.Drawing.Size(500, 20)
                                    .Location = New System.Drawing.Point(120, x * 50 + 40)
                                End With
                                With Me
                                    .Text = blkname
                                    .SplitContainer1.Panel1.Controls.Add(lb)
                                    .SplitContainer1.Panel1.Controls.Add(tb)
                                    .AutoSize = True
                                    .Update()
                                End With
                                x = x + 1
                            End If
                        Next
                    End If
                    tr.Commit()
                Next
            End Using
        Catch ex As Autodesk.AutoCAD.Runtime.Exception
            ed.WriteMessage(("Exception: " + ex.Message))
        Finally
        End Try
    End Sub

    Public Sub OK_Click(sender As Object, e As EventArgs) Handles OK.Click
        Dim txtlist As New List(Of String)()
        Dim childc As System.Windows.Forms.Control
        For Each childc In Me.SplitContainer1.Panel1.Controls
            If TypeOf childc Is System.Windows.Forms.TextBox Then
                txtlist.Add(childc.Text.ToString)
            End If
        Next
        Dim txtarray As String() = txtlist.ToArray()
        Dim tagarray As String() = taglist.ToArray()
        Dim prmtarray As String() = promptlist.ToArray()
        For z As Integer = 0 To txtarray.Length - 1
            MsgBox(txtarray(z))
            MsgBox(prmtarray(z))
            MsgBox(tagarray(z))
        Next

        Me.Close()
        Me.Dispose()
        Dispose()
    End Sub

    Private Sub Cancel_Click(sender As Object, e As EventArgs) Handles Cancel.Click
        Me.Close()
        Me.Dispose()
        Dispose()
    End Sub

End Class

 

Message 4 of 7
muckmailer
in reply to: Ron_M

I looked at the code in the link that blockbox suggested. I converted it to Vb.net but I am having problems with it.

I can figure out what ".Toupper" means in the code below.  I know if I try to set blockName to blkname as a string

it causes and error a statement  ar.UpgradeOpen(). I do not know what upgradeopen does.

 

 

Dim pr As PromptResult = ed.GetString(vbLf & "Enter name of block to search for: ")
        'Dim pr As PromptResult = ed.GetString(vbLf & blkName & vbLf)
        'Dim pr As PromptResult = bkname
        If pr.Status <> PromptStatus.OK Then
            Return
        End If
        Dim blockName As String = pr.StringResult.ToUpper()

        'blockName = blkName (blkName as a string)

 Here is my complete code in the box below. It is in form 2 with a textbox4 and a button click event.

Imports System
Imports System.IO
Imports System.Diagnostics
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput
Public Class Form2
    Private blkName As String
    Private idArray As ObjectId()
    Private Property btrid As Database
    Private blockname As String
    Public Sub SelectForBlkName()
        Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
        Dim db As Database = HostApplicationServices.WorkingDatabase
        Dim tr As Transaction = db.TransactionManager.StartTransaction()
        ' Start the transaction
        Try
            ' Build a filter list so that only
            ' block references are selected
            Dim filList As TypedValue() = New TypedValue(0) {New TypedValue(CInt(DxfCode.Start), "INSERT")}
            'Private filList As TypedValue() = New TypedValue(0) {New TypedValue(CInt(DxfCode.Start), "INSERT")}
            Dim filter As New SelectionFilter(filList)
            'Was inbetween Note 3 in public Shared
            'Dim filList As TypedValue() = New TypedValue(0) {New TypedValue(CInt(DxfCode.Start), "INSERT")}
            'Dim filter As New SelectionFilter(filList)
            'was inbetween note 3 in public shared
            Dim opts As New PromptSelectionOptions()
            Dim dbObj As DBObject
            Me.Hide()
            opts.MessageForAdding = "Select block references: "
            Dim res As PromptSelectionResult = ed.GetSelection(opts, filter)
            '***Dim ent As Entity = acTrans.GetObject(acObjId, OpenMode.ForRead)
            ' Do nothing if selection is unsuccessful
            If res.Status <> PromptStatus.OK Then
                Return
            End If
            Dim selSet As SelectionSet = res.Value
            'Dim res1 As PromptSelectionResult = ed.GetEntity
            'Dim ent As Entity = tr.GetObject(acObjId, OpenMode.ForRead)

            idArray = selSet.GetObjectIds()
            For Each blkId As ObjectId In idArray


                Dim blkRef As BlockReference = DirectCast(tr.GetObject(blkId, OpenMode.ForRead), BlockReference)
                Dim btr As BlockTableRecord = DirectCast(tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
                dbObj = tr.GetObject(blkId, OpenMode.ForRead)
                'dbObj.
                'TextBox4.Text = btr.Name
                blkName = btr.Name
                ed.WriteMessage(vbLf & "Block: " + btr.Name)
                'MsgBox(btr.Name)
                'For Each attId As ObjectId In btr
                'For Each acObjId As ObjectId In acBlkTblRec
                Dim ent As Entity = tr.GetObject(blkId, OpenMode.ForRead)
                ed.WriteMessage(vbLf & "Layer: " & ent.Layer.ToString())
                'Next
                btr.Dispose()

                'Dim attCol As AttributeCollection = blkRef.AttributeCollection
                'For Each attId As ObjectId In attCol
                'Dim attRef As AttributeReference = DirectCast(tr.GetObject(attId, OpenMode.ForRead), AttributeReference)
                'Dim str As String = ((vbLf & "  Attribute Tag: " + attRef.Tag & vbLf & "    Attribute String: ") + attRef.TextString)
                'ed.WriteMessage(str)
                'Next
            Next
            tr.Commit()
        Catch ex As System.Exception
            'Catch ex As Autodesk.AutoCAD.Runtime.Exception
            ed.WriteMessage(("Exception: " + ex.Message))
            MsgBox("Selection Routine Exception: " + ex.Message)
            tr.Dispose()
            Exit Sub
        Finally
            tr.Dispose()
        End Try
        ' ListAttributes()
        'Me.Show()
        'Returnvalue = blkName
    End Sub
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        SelectForBlkName()
        UpdateAttribute()
    End Sub
    Public Sub UpdateAttribute()
        Dim doc As Document = Application.DocumentManager.MdiActiveDocument
        Dim db As Database = doc.Database
        Dim ed As Editor = doc.Editor
        ' Have the user choose the block and attribute
        ' names, and the new attribute value

        Dim pr As PromptResult = ed.GetString(vbLf & "Enter name of block to search for: ")
        'Dim pr As PromptResult = ed.GetString(vbLf & blkName & vbLf)
        'Dim pr As PromptResult = bkname
        If pr.Status <> PromptStatus.OK Then
            Return
        End If
        Dim blockName As String = pr.StringResult.ToUpper()

        'blockName = blkName (blkName as a string)

        pr = ed.GetString(vbLf & "Enter tag of attribute to update: ")
        If pr.Status <> PromptStatus.OK Then
            Return
        End If

        Dim attbName As String = pr.StringResult.ToUpper()
        pr = ed.GetString(vbLf & "Enter new value for attribute: ")

        If pr.Status <> PromptStatus.OK Then

            Return
        End If

        Dim attbValue As String = pr.StringResult
        UpdateAttributesInDatabase(db, blockName, attbName, attbValue)
    End Sub
    
    Private Sub UpdateAttributesInDatabase(db As Database, blockName As String, attbName As String, attbValue As String)
        Dim doc As Document = Application.DocumentManager.MdiActiveDocument
        Dim ed As Editor = doc.Editor
        ' Get the IDs of the spaces we want to process
        ' and simply call a function to process each
        Dim msId As ObjectId, psId As ObjectId
        Dim tr As Transaction = db.TransactionManager.StartTransaction()
        Using tr


            Dim bt As BlockTable = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)

            msId = bt(BlockTableRecord.ModelSpace)
            psId = bt(BlockTableRecord.PaperSpace)
            ' Not needed, but quicker than aborting
            tr.Commit()
        End Using

        Dim msCount As Integer = UpdateAttributesInBlock(msId, blockName, attbName, attbValue)
        Dim psCount As Integer = UpdateAttributesInBlock(psId, blockName, attbName, attbValue)
        ed.Regen()


        ' Display the results
        ed.WriteMessage(vbLf & "Processing file: " & Convert.ToString(db.Filename))
        ed.WriteMessage(vbLf & "Updated {0} instance{1} of " & "attribute {2} in the modelspace.", msCount, If(msCount = 1, "", "s"), attbName)
        ed.WriteMessage(vbLf & "Updated {0} instance{1} of " & "attribute {2} in the default paperspace.", psCount, If(psCount = 1, "", "s"), attbName)

    End Sub
    Private Function UpdateAttributesInBlock(btrId As ObjectId, blockName As String, attbName As String, attbValue As String) As Integer
        ' Will return the number of attributes modified
        Dim changedCount As Integer = 0
        Dim doc As Document = Application.DocumentManager.MdiActiveDocument
        Dim db As Database = doc.Database
        Dim ed As Editor = doc.Editor
        Dim tr As Transaction = doc.TransactionManager.StartTransaction()
        Using tr
            Dim btr As BlockTableRecord = DirectCast(tr.GetObject(btrId, OpenMode.ForRead), BlockTableRecord)
            ' Test each entity in the container...

            For Each entId As ObjectId In btr
                Dim ent As Entity = TryCast(tr.GetObject(entId, OpenMode.ForRead), Entity)
                If ent IsNot Nothing Then
                    Dim br As BlockReference = TryCast(ent, BlockReference)
                    If br IsNot Nothing Then
                        Dim bd As BlockTableRecord = DirectCast(tr.GetObject(br.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
                        ' ... to see whether it's a block with
                        ' the name we're after
                        If bd.Name.ToUpper() = blockName Then
                            ' Check each of the attributes...
                            For Each arId As ObjectId In br.AttributeCollection
                                Dim obj As DBObject = tr.GetObject(arId, OpenMode.ForRead)
                                Dim ar As AttributeReference = TryCast(obj, AttributeReference)
                                If ar IsNot Nothing Then
                                    ' ... to see whether it has
                                    ' the tag we're after
                                    If ar.Tag.ToUpper() = attbName Then
                                        ' If so, update the value
                                        ' and increment the counter
                                        ar.UpgradeOpen()
                                        ar.TextString = attbValue
                                        ar.DowngradeOpen()
                                        changedCount += 1
                                    End If
                                End If
                            Next
                        End If


                        ' Recurse for nested blocks
                        changedCount += UpdateAttributesInBlock(br.BlockTableRecord, blockName, attbName, attbValue)
                    End If
                End If
            Next
            tr.Commit()
        End Using
        Return changedCount
    End Function
   

    Private Sub Form2_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

    End Sub
End Class

 

My problem with vb.net and Autocad is the I cannot find a place that tell how the statements are defined and used.  

Any suggestions?  ar.UpgradeOpen() is in the Function UpdateAttributesInBlock near the ending of the code.

 

Thank you,

 

Message 5 of 7
Ron_M
in reply to: muckmailer

This is sloppy but currently working for me as desired.  It needs some tweaking I know.

 

Imports System
Imports System.IO
Imports System.Collections.Specialized
Imports System.Windows

Imports Autodesk.AutoCAD
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.Windows
Imports Autodesk.AutoCAD.Internal
Imports Autodesk.AutoCAD.Interop
Imports Autodesk.AutoCAD.ComponentModel
Imports Autodesk.AutoCAD.GraphicsInterface
Imports Autodesk.AutoCAD.GraphicsSystem
Imports Autodesk.AutoCAD.LayerManager
Imports Autodesk.AutoCAD.PlottingServices
Imports Autodesk.AutoCAD.Publishing

Public Class EditAtt
    Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument   'Current drawing
    Dim db As Database = acDoc.Database                                     'Current drawing database
    Dim ed As Editor = acDoc.Editor                                         'Current drawing editor
    Dim x As Integer = 0
    Dim y As Integer = 0
    Dim tbname As String = Nothing
    Dim tb As System.Windows.Forms.TextBox
    Dim lb As System.Windows.Forms.Label
    Public Property promptlist As New List(Of String)()
    Public Property taglist As New List(Of String)()
    Public Property txtlist As New List(Of String)()
    Public Property br As BlockReference
    Public Property bt As BlockTable
    Public Property btr As BlockTableRecord

    <CommandMethod("ea")> _
    Public Sub EditAtt()
        Dim form1 As EditAtt
        form1 = New EditAtt()
        Application.ShowModalDialog(form1)
        form1 = Nothing
    End Sub

    Public Sub EditAtt_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim FilterList(0) As TypedValue
        FilterList.SetValue(New TypedValue(CInt(DxfCode.Start), "INSERT"), 0)
        Dim filter As New SelectionFilter(FilterList)
        Dim opts As New PromptSelectionOptions()
        Try
            opts.MessageForAdding = "Select a block with text to edit: "
            opts.SingleOnly = True
            Dim res As PromptSelectionResult = ed.GetSelection(opts, filter)
            If res.Status <> PromptStatus.OK Then
                Application.ShowAlertDialog("Try to select a block next time.")
                Exit Sub
            Else
            End If
            Dim selSet As SelectionSet = res.Value
            Dim idArray() As ObjectId = selSet.GetObjectIds
            Using tr As Transaction = db.TransactionManager.StartTransaction
                For Each blkId As ObjectId In idArray
                    br = CType(tr.GetObject(blkId, OpenMode.ForRead), BlockReference)
                    bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead)
                    btr = CType(tr.GetObject(bt(br.Name), OpenMode.ForRead), BlockTableRecord)
                    If btr.HasAttributeDefinitions Then
                        Dim blkname As String = br.Name.ToString
                        For Each ObjId As ObjectId In btr
                            Dim obj As Entity = tr.GetObject(ObjId, OpenMode.ForRead)
                            If TypeOf obj Is AttributeDefinition Then
                                Dim AttDef As AttributeDefinition = obj
                                taglist.Add(AttDef.Tag)
                                promptlist.Add(AttDef.Prompt)
                                Dim prmt As String = promptlist(x)
                                tbname = "textbox" & x
                                Dim frm1 As New System.Windows.Forms.Form
                                lb = New System.Windows.Forms.Label
                                With lb
                                    .Size = New System.Drawing.Size(100, 40)
                                    .Location = New System.Drawing.Point(10, x * 40 + 45)
                                    .Text = prmt
                                End With
                                tb = New System.Windows.Forms.TextBox
                                With tb
                                    .Name = "tb" & x
                                    .Size = New System.Drawing.Size(500, 20)
                                    .Location = New System.Drawing.Point(120, x * 40 + 40)
                                End With
                                With Me
                                    .Text = blkname
                                    .SplitContainer1.Panel1.Controls.Add(lb)
                                    .SplitContainer1.Panel1.Controls.Add(tb)
                                    .AutoSize = True
                                    .Update()
                                End With
                                x = x + 1
                            End If
                        Next
                    End If
                    tr.Commit()
                Next
            End Using
        Catch ex As Autodesk.AutoCAD.Runtime.Exception
            ed.WriteMessage(("Exception: " + ex.Message))
        Finally
        End Try

    End Sub

    Public Sub OK_Click(sender As Object, e As EventArgs) Handles OK.Click
        Dim txtlist As New List(Of String)()
        Dim childc As System.Windows.Forms.Control
        For Each childc In Me.SplitContainer1.Panel1.Controls
            If TypeOf childc Is System.Windows.Forms.TextBox Then
                txtlist.Add(childc.Text.ToString)
            End If
        Next
        Dim txtarray As String() = txtlist.ToArray()
        Dim tagarray As String() = taglist.ToArray()
        Dim prmtarray As String() = promptlist.ToArray()

        Using (acDoc.LockDocument())
            Using tr As Transaction = db.TransactionManager.StartTransaction()
                For z As Integer = 0 To txtarray.Length - 1
                    MsgBox(txtarray(z))
                    MsgBox(prmtarray(z))
                    MsgBox(tagarray(z))

                    MsgBox(br.Name)

                    Dim btrIDs As ObjectIdCollection = btr.GetBlockReferenceIds(True, False)
                    For Each id As ObjectId In btrIDs
                        If Not id.IsEffectivelyErased Then
                            'Dim bref As BlockReference = id.GetObject(OpenMode.ForRead)
                            Dim AttCol As AttributeCollection = br.AttributeCollection
                            For Each AttID As ObjectId In AttCol
                                Dim AttR As AttributeReference = tr.GetObject(AttID, OpenMode.ForRead, False)
                                If AttR.Tag = tagarray(z) Then
                                    AttR.UpgradeOpen()
                                    AttR.TextString = txtarray(z)

                                End If
                            Next
                        End If
                    Next
                Next
                tr.Commit()
            End Using
        End Using
        Me.Close()
        Me.Dispose()
        Dispose()
        br.Dispose()
        btr.Dispose()
        bt.Dispose()
    End Sub

    Private Sub Cancel_Click(sender As Object, e As EventArgs) Handles Cancel.Click
        Me.Close()
        Me.Dispose()
        Dispose()
    End Sub

End Class               

 

Message 6 of 7
muckmailer
in reply to: Ron_M

Ron,

   How is your code used. Should I cut and paste it in a form?

I am getting several errors cutting/pasting it in mycommands module.

Thank you,

Message 7 of 7
Ron_M
in reply to: muckmailer

You'll have to create the form for it.  I used the designer, not code to do that.  I use this as a separate windows form within my project.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost