Hello, I'm trying to chnage the text of the sheet number and total sheet number attributes for each layout in my drawing. I have code that adds and deletes the specified pages, now I need to edit the attributes to reflect the correct page and correct total amount of pages. Here is my code, based on my old VBA version. Please forgive my ignorance, but I'm teaching myself as I go. Any commenst within the code describing what it does really helps me learn.
I know there is a problem with the line:
For Each item In myBTR.ObjectId
I just threw something in there as I searched the internet for help. I've used a njumber of websites and books, but I would really like to find something that teaches about block tables, block table references, block table IDs so I can get a better understanding of breaking stuff down to get the info I need. Any suggestions are welcome.
Public Sub updatePageNumbers() Dim myDWG As Autodesk.AutoCAD.ApplicationServices.Document Dim myDB As Autodesk.AutoCAD.DatabaseServices.Database Dim myTransManForPageNumbers As Autodesk.AutoCAD.DatabaseServices.TransactionManager Dim myTransForPageNumbers As Transaction Dim myLM As DatabaseServices.LayoutManager Dim myLMCount As Integer Dim myLayout As DatabaseServices.Layout Dim myBT As DatabaseServices.BlockTable Dim myBTR As DatabaseServices.BlockTableRecord Dim myBTRE As DatabaseServices.SymbolTableEnumerator myDWG = DocumentManager.MdiActiveDocument 'myDB = myDWG.Database myTransManForPageNumbers = myDWG.TransactionManager myTransForPageNumbers = myTransManForPageNumbers.StartTransaction myBT = myDB.BlockTableId.GetObject(DatabaseServices.OpenMode.ForWrite) myBTRE = myBT.GetEnumerator myLM = DatabaseServices.LayoutManager.Current myLMCount = myLM.LayoutCount - 1 Dim strLayoutTotal As String Dim strLayoutCounter As Integer Dim strLayoutNumber As String Dim strLayoutTabName As String While myBTRE.MoveNext myBTR = myBTRE.Current.GetObject(DatabaseServices.OpenMode.ForRead) If myBTR.IsLayout Then If Not myBTR.Name = "*Model_Space" Then myLayout = myBTR.LayoutId.GetObject(DatabaseServices.OpenMode.ForRead) strLayoutNumber = myLayout.TabOrder Dim item As Object For Each item In myBTR.ObjectId 'Get Each Block Reference If TypeOf item Is AcadBlockReference Then 'Check for Attributes If item.HasAttributes Then Dim atts As Object atts = item.GetAttributes 'Verify Range is valid If isValid(atts) Then Dim AttributeCounter As Integer For AttributeCounter = LBound(atts) To UBound(atts) 'Check if attribute has the correct Tag, then change it to the last sheet number If atts(AttributeCounter).TagString = "TOTAL_SHEET_NO" Then 'Set Value atts(AttributeCounter).TextString = strLayoutTotal End If 'Update the sheet number to be the current or new sheet number If atts(AttributeCounter).TagString = "SHEET_NO" Then 'Set Value atts(AttributeCounter).TextString = strLayoutNumber End If Next End If End If End If Next End If End If End While myDWG.Editor.Regen() myTransForPageNumbers.Commit() myTransForPageNumbers.Dispose() myTransManForPageNumbers.Dispose() End Sub
Thanks,
Mark
Solved! Go to Solution.
Solved by cadMeUp. Go to Solution.
We have not accessed block attrributes in .NET code yet, so take my comments with a grain of salt. There are several posts here (and the swamp) on accessing block attributes.
You define item as an object and then use it as an enumerator through a collection of objectids. For me, code is easier to follow if you create an objectid as an enumerator in the for each statement. "For each myObjid as ObjectID in myBTR.ObjectID" is more efficient and cleaner IMO.
In most cases it is easiest to cast the object to the type you require. After you use "If TypeOf item Is AcadBlockReference Then" create your own block reference from the object by casting, something like
Dim myBREF As BlockReference = CType(myObjidr.GetObject(OpenMode.ForWrite), BlockReference). Once you have created your own object, intellisense provides all of the available methods and properties of the object.
You can compare your code to the attached file...
A BlockTableRecord object is a container, of the object ids of the objects, that are conatined within the record, just like the BlockTable object is a container of ObjectId's to BlockTableRecord objects. They both implement the 'IEnumerable' interface so you can basically iterate thru the collection directly without the need of a 'SymbolTableEnumerator'. Something like:
Dim myBT As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead) For Each btrid As ObjectId In myBT Dim myBTR As BlockTableRecord = btrid.GetObject(OpenMode.ForRead) For Each id As ObjectId In myBTR Dim obj As DBObject = id.GetObject(OpenMode.ForRead) Next Next
But it is important to note that BlockTable and BlockTableRecord's are containers of ObjectId's and not the objects themselves.
Also, you DO NOT want to dispose of the TransactionManager object:
Dim myTransManForPageNumbers As Autodesk.AutoCAD.DatabaseServices.TransactionManager
...
myTransManForPageNumbers.Dispose()
Not good, remove the Dispose() line from your code!!
Also if you know the TitleBlock's 'BlockName'
you can grab its objectId using BlockTable("Name")
then use GetBlockReferenceIds to get all the BlockReferences
If you need the Layout name then get it's owner and use LayoutId.
Hi fieldguy,
Thanks for the information. I'll have to study up on enumerators, but yes I understand what you mean about mixing objects and object ID's. I'll have to be more careful about that. I'll also be looking at CTYPE information.
Thanks again,
Mark
Hi cadMeUp,
Thank you fro the explainations of the BlockTable and BlockTableRecords.
Thank you also for the code. I'm going to be busy this afternoon dissecting it and finding out what all it does. It does seem very straightforward though.
I've also removed the "transManager.dispose" from my code. I must have seen it in an example somewhere.
Best regards,
Mark
Hi Jeff,
For this case, I will not know the title blocks blockname, as it will change from drawing to drawing, but thanks for the info about grabbing the ID by using the BlockTable name. I believe I have another application that could use something like that.
Best regards,
Mark