.NET

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

Inserting a Block with Attributes

346 Views, 15 Replies
05-05-2014 02:18 PM

Hello, this is the code that I've put together by reading posts on here and elsewhere. 

I have drawings in a library folder like "SMD_0201.dwg".  The drawing consists of a rectangle and an invisible attribute.

I want to bring the appropriate block (dwg) into my drawing and place the references at the correct location and rotation with the correct attribute text.

 

When I use this, all seems to run fine (the rectangles show up placed perfectly and rotated), but there are no attributes.  Then when I double pick on the block, it does not have a block name, it doesn't even have a definition. 

 

BlockName = the path and name of the block

basename = block name

 

Public Sub InsertSMDComp(ByVal InsPt As Point3d, ByVal BlockName As String, ByVal basename As String, ByVal RefDes As String, _
        ByVal rotation As Double, ByVal scale As Double)
        Dim smdTransMan As DatabaseServices.TransactionManager
        Dim smdTrans As DatabaseServices.Transaction
        Dim myDwg As Document
        Dim myBT As BlockTable

        myDwg = Application.DocumentManager.MdiActiveDocument
        smdTransMan = myDwg.TransactionManager
        smdTrans = smdTransMan.StartTransaction
        myBT = myDwg.Database.BlockTableId.GetObject(OpenMode.ForRead)
        Dim myDB As Database
        myDB = myDwg.Database
        Try
            Using db As Database = New Database(False, True)
                db.ReadDwgFile(BlockName, IO.FileShare.Read, True, "")
                Dim BlkId As ObjectId
                BlkId = myDB.Insert(BlockName, db, True)
                Dim bt As BlockTable = smdTrans.GetObject(myDB.BlockTableId, OpenMode.ForRead, True)
                Dim btr As BlockTableRecord = smdTrans.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite, True)
                Dim bref As BlockReference
                bref = New BlockReference(InsPt, BlkId)
                bref.Rotation = rotation
                bref.ScaleFactors = New Scale3d(scale, scale, scale)
                btr.AppendEntity(bref)
                smdTrans.AddNewlyCreatedDBObject(bref, True)
                'Set the Attribute Value
                Dim myAttColl As DatabaseServices.AttributeCollection
                Dim myEnt As DatabaseServices.Entity
                Dim myBTREnum As BlockTableRecordEnumerator
                myAttColl = bref.AttributeCollection
                myBTREnum = btr.GetEnumerator
                While myBTREnum.MoveNext
                    myEnt = myBTREnum.Current.GetObject(OpenMode.ForWrite)
                    If TypeOf myEnt Is DatabaseServices.AttributeDefinition Then
                        Dim myAttDef As DatabaseServices.AttributeDefinition = myEnt
                        Dim myAttRef As New DatabaseServices.AttributeReference
                        myAttRef.SetAttributeFromBlock(myAttDef, bref.BlockTransform)
                        myAttRef.TextString = RefDes
                        myAttColl.AppendAttribute(myAttRef)
                        smdTrans.AddNewlyCreatedDBObject(myAttRef, True)
                    End If
                End While
                smdTrans.Commit()
            End Using
        Catch ex As Autodesk.AutoCAD.Runtime.Exception
            MsgBox(ex.ToString)
        End Try
        smdTrans.Dispose()
        smdTransMan.Dispose()
    End Sub

 

Help!

Thanks,

Mark

In your code, myBTR is ModelSpace block, NOT the block definition that you use to create the BlockReference!

 

You need to open the block definition then loop thorugh its AttributeDefinition. Something, after you created your BlockReference, like:

 

Dim bDef As BlockTableRecord=myTran.GetObject(myBT{baseName), OpenMode.ForRead)

 

If (bDef.HasAttributeDefinitions) Then

    ...

End If

*Expert Elite*
norman.yuan
Posts: 1,064
Registered: ‎04-27-2009
Message 2 of 16 (335 Views)

Re: Inserting a Block with Attributes

05-05-2014 02:45 PM in reply to: mgorecki

The problem that you get a block definition without name created in the drawing, is because the block definition was inserted into this drawing with an INVALID block name. The offending code is:

 

BlkId = myDB.Insert(BlockName, db, True)

 

necause BlockName is a file name with a full folder path, which includes characters line ":","\" that are not allowed to be used in block name. When you manulally define block, AutoCAD validates the block name; while you inserts block with .NET API's Database.Insert(), if the block name contaims invalid characters, the block definition can still be inserted, the AutoCAD somehow gives the block definition an empty name, instead of raising an exception. I personally think this is an API bug.

 

Based on your sub's signature, I think you meant to use "baseName" as block name in the Insert() method.

 

However, you should follow AutoCAD convention to use block's file name as Block name, in general. So, you do not need to pass "baseName" to the subroutine.

 

you can get block file name from its full path name like this:

 

Dim bName As String=System.IO.Path.GetFileNameWothoutExtension(BlockName)

BlkId=nyDB.Insert(bName,...)

 

 

 

 

Mentor
mgorecki
Posts: 415
Registered: ‎09-23-2004
Message 3 of 16 (336 Views)

Re: Inserting a Block with Attributes

05-05-2014 02:53 PM in reply to: norman.yuan

Hi Norman,

Thanks, but when I try to use you suggestion, it tells me "GetFileNameWothoutExtension is not a member of 'System.IO.Path"

 

Above the sub, I do have: 

Imports System.IO

 

Also, if I don't include the path, how does it know where to get the drawing?

 

Thanks

Mentor
mgorecki
Posts: 415
Registered: ‎09-23-2004
Message 4 of 16 (332 Views)

Re: Inserting a Block with Attributes

05-05-2014 02:59 PM in reply to: mgorecki

Never mind, I got it.

Since I already have the "basename" I used that instead.

Try

           

Using db AsDatabase = NewDatabase(False, True)

     db.ReadDwgFile(BlockName, IO.FileShare.Read, True, "")  

  'Dim bName As String = System.IO.Path.GetFileNameWothoutExtension(BlockName)

   Dim BlkId AsObjectId

     BlkId = myDB.Insert(basename, db, True)

Mentor
mgorecki
Posts: 415
Registered: ‎09-23-2004
Message 5 of 16 (332 Views)

Re: Inserting a Block with Attributes

05-05-2014 03:06 PM in reply to: mgorecki

Ok, was too quick on that.  The blocks come in, and they look good.  They even have names and definitions (including an attribute definition) in the block editor.  The only problem now is how to insert them and apply a text value to the attribute?

I thought this should work.  it includes the value for the attribute textstring.

While myBTREnum.MoveNext
                    myEnt = myBTREnum.Current.GetObject(OpenMode.ForWrite)
                    If TypeOf myEnt Is DatabaseServices.AttributeDefinition Then
                        Dim myAttDef As DatabaseServices.AttributeDefinition = myEnt
                        Dim myAttRef As New DatabaseServices.AttributeReference
                        myAttRef.SetAttributeFromBlock(myAttDef, bref.BlockTransform)
                        myAttRef.TextString = RefDes
                        myAttColl.AppendAttribute(myAttRef)
                        smdTrans.AddNewlyCreatedDBObject(myAttRef, True)
                    End If
                End While

 

Mentor
mgorecki
Posts: 415
Registered: ‎09-23-2004
Message 6 of 16 (331 Views)

Re: Inserting a Block with Attributes

05-05-2014 03:19 PM in reply to: mgorecki

Also, when I try to do a manual insert on one of these existing blocks, there is a problem.

When I pick a name from the list, and pick ok to insert, it pops up with "The specified file was not found.  Specify the correct filename or select a valid block name."

 

*Expert Elite*
norman.yuan
Posts: 1,064
Registered: ‎04-27-2009
Message 7 of 16 (307 Views)

Re: Inserting a Block with Attributes

05-06-2014 06:17 AM in reply to: mgorecki

Sorry, there was a typo:

 

GetFileNameWothout...() SHOULD HAVE BEEN GetFileNameWithout...()

*Expert Elite*
norman.yuan
Posts: 1,064
Registered: ‎04-27-2009
Message 8 of 16 (304 Views)

Re: Inserting a Block with Attributes

05-06-2014 06:31 AM in reply to: mgorecki

If you had stepped through your code in debugging, you would have easily found out thta the code inside the "If...End If"

 

If TypeOf myEnt Is... Then

 

End If

 

is never reached, thus, no attribute reference is added to the BlockReference. Do not just run code and wonder why it is not work. Debugging teaches a lot.

 

The problem is with Enumerator "myBTREnum", which you declare as BlockTableEnumerator. Why you need to iterate through BlockTable for an AttributeDefinition that belongs to a BlockTablerecord? You'll never find an AttributeDefinition in BlockTable.

 

Instead, what you need is to interate through the BlockTableRecord your BlockReference is based on to find AttributeDefinition. The code would be like:

 

''btr is the BlockTableRecord

bref=New Blockreference(....)

....

 

For Each id As ObjectId in btr

    myEnt=id.GetObject(OpenMode.ForRead)

    If TypeOf myEnt Is AttributeDefinition Then

 

        Dim myAttDef As AttributeDefinition = myEnt

 

        ''Create attribute reference based on the attributeDefinition

        Dim attrRef As New Attributereference

        ''''

 

    End If

Next

*Expert Elite*
norman.yuan
Posts: 1,064
Registered: ‎04-27-2009
Message 9 of 16 (303 Views)

Re: Inserting a Block with Attributes

05-06-2014 06:38 AM in reply to: mgorecki

Debugging, and Debugging. If you step thorugh the code, or place a break point at where InsertSMDComp() is called, you simply examine what the block name and block file path is passed to this subroutine, then you probably can tell why you get that error message.

 

If the code passes a file name without full path, the .NET runtime would only examine the current application folder for the block file. Thta is probably why the message. You need either supply full path, or write code to search through AutoCAd supporting folders to find block file by only given file name.

Mentor
mgorecki
Posts: 415
Registered: ‎09-23-2004
Message 10 of 16 (292 Views)

Re: Inserting a Block with Attributes

05-06-2014 12:38 PM in reply to: norman.yuan

Hi Norman, you, as always, have been very helpful.  I did run through the code many, many times.  I put in the breaks, even inside the If...End If block and it stopped there.  I had watches going as well.  That's why this was so confusing and frustrating.

The blocks in my library include a rectangle and a block attribute, but sometimes it sounds like I'm having to add a new attribute to the block that just got read in.

I had the code you mentioned above in regards to btr and bref:

 Dim btr As BlockTableRecord = smdTrans.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite, True)
                Dim bref As BlockReference
                bref = New BlockReference(InsPt, BlkId)
                bref.Rotation = rotation
                bref.ScaleFactors = New Scale3d(scale, scale, scale)
                btr.AppendEntity(bref)

 Since bref was included in the If..End If, I thought it was using the attribute in the block. 

When I look up some of these things, like enumerator, most of the help I find is really no help.  All of the writers think their audience must be full time programmers with multiple degrees.  I'm not one to just splice code together and cross my fingers hoping it will work.  I search the Internet trying to understand what it is.

Thanks for all the time you've already spent helping me.  I really do appreciate it.

 

Best regards,

Mark

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.