TheSwamp
Code Red => .NET => Topic started by: vegbruiser on July 01, 2008, 05:43:36 AM
-
Hi,
I've been struggling with the following problem for a couple of weeks and I wondered if one of you fine chaps would be able to point me in the right direction:
In VBA, if I want to find and edit specific attributes contained within the layouts of a drawing I'd simply do this: -
Set layouts = thisdrawing.layouts
for each layout in layouts
Thisdrawing.activelayout = layout
If thisdrawing.activelayout.name <> "Model" then
For each Bobj in thisdrawing.paperspace
If Bobj.objectname = "AcDbBlockreference" Then
varattributes = bobj.getattributes
for i = lbound(varattributes) to ubound(varattributes)
if ucase(varattributes(i).TagString = ucase("date") then
varattributes(i).textstring = "some value"
end if
next i
End if
Next
end if
next
Now, I realise that the .NET way of doing this is almost completely different, and, having paid for the latest .NET book by Jerry Winters, I am beginning to get to grips with the problem, but am still having a hard time getting the .NET equivalent of the above code working.
As I understand it, having searched both the Autodesk .NET newsgroups, and this very forum is that I need to search the Blocktablerecords and determine whether the various blockreferences I find are part of a layout, but having implemented the following code, it doesn't function as I'd have expected: -
<CommandMethod("UTB")> _
Public Sub UpdateTitleBlock()
Dim db As Database = HostApplicationServices.WorkingDatabase
Using trans As Transaction = db.TransactionManager.StartTransaction()
Try
Dim bt As BlockTable = DirectCast(trans.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
Dim btr As BlockTableRecord = DirectCast(trans.GetObject(bt(BlockTableRecord.PaperSpace), OpenMode.ForRead), BlockTableRecord)
For Each bId As ObjectId In btr
Using ent As Entity = DirectCast(trans.GetObject(bId, OpenMode.ForRead, False), Entity)
If ent.GetRXClass().Name.ToString() = "AcDbBlockReference" Then
Dim br As BlockReference = DirectCast(ent, BlockReference)
Dim blkObj As BlockTableRecord = DirectCast(trans.GetObject(br.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
If blkObj.IsDynamicBlock = False Then
btr = DirectCast(trans.GetObject(br.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
Else
btr = DirectCast(trans.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead), BlockTableRecord)
End If
MsgBox(btr.Name & " : " & vbTab & blkObj.Name) ' these end up the same?
If (blkObj.HasAttributeDefinitions) AndAlso (btr.Name = "Drawing Border") Then
Dim attcol As Autodesk.AutoCAD.DatabaseServices.AttributeCollection = br.AttributeCollection
For Each attId As ObjectId In attcol
Dim attRef As AttributeReference = DirectCast(trans.GetObject(attId, OpenMode.ForWrite), AttributeReference)
MsgBox(attRef.Tag & " : " & vbTab & attRef.TextString)
Next
End If
End If
End Using
Next
trans.Commit()
Catch ex As System.Exception
System.Windows.Forms.MessageBox.Show(ex.ToString())
MessageBox.Show("Unexpected Error: " + ex.ToString())
End Try
End Using
End Sub
Given what I've learnt reading Jerry's very informative book, this should be able to at least list the attributes contained within the block called drawing border, but it doesn't work. Any suggestions?
-
What version of AutoCAD are you using?
-
Also, what version of Visual Studio (if any) and Framework version are you targeting?
-
:oops: It's for AutoCAD 2006 and .NET Framework 3.5 - I'm using VB.NET 2008 (Express) (although I do have a trial (full) version of VS 2008 that I can use for debugging)
Thanks in advance.
-
What is the EXACT spelling of the block 'drawing border'?
Also, don't open things for Write unless you are actually going to modify the object and even then, open for write for the shortest time possible.
-
The exact spelling is "Drawing Border" :whistle: , that's one reason why it may not be working correctly.
Also, the open for write bit is a mistake as I only want to read the attributes and bung them into an XML "reporting" file.
I'll add a (couple of) Ucase entries to my code and see what happens.
Actually, I have just changed this: -
If blkobj.IsDynamicBlock = False then
to this: -
If br.IsDynamicBlock = False then
and it finds the correct block no problem
Cheers.
What it doesn't do however is find the same block in multiple layouts?
-
You do understand the difference between a BlockTableRecord (Block Definition) and a BlockReference (INSERT)?
-
I do, yes. (at least I think I do): -
A Blocktablerecord (Block Definition) is the block as initially defined (or subsequently updated) and the blockreference is the unique copy of that definition contained in either Modelspace or paperspace. (which then has unique attribute references)
So what you're saying is that I should be looking for Blockreferences, not blocktablerecords? I thought that's what the line: -
If ent.GetRXClass().Name.ToString() = "AcDbBlockReference" Then
was for (or have I missed the point of what you were saying entirely)?
:oops:
-
Correct - you should be looking for BlockReferences.
The block definition is the master blueprint/look of all the BlockReferences that 'reference' the definition - hence all references will look exactly the same (excluding rotation/scale/attrib values), so they are NOT a unique copy by any means.
As far as this goes:
If ent.GetRXClass().Name.ToString() = "AcDbBlockReference" Then
you're correct, however it's in a loop over paperspace ONLY. If you want to get ALL references of your block def, then either:
A. 'Loop the layouts'. Essentailly do what you do now, except put an outer loop to loop the layouts, or
B. Look up GetBlockReferenceIds (this is the fastest way and the way I would do it)
-
Correct - you should be looking for BlockReferences.
The block definition is the master blueprint/look of all the BlockReferences that 'reference' the definition - hence all references will look exactly the same (excluding rotation/scale/attrib values), so they are NOT a unique copy by any means.
As far as this goes:
If ent.GetRXClass().Name.ToString() = "AcDbBlockReference" Then
you're correct, however it's in a loop over paperspace ONLY. If you want to get ALL references of your block def, then either:
A. 'Loop the layouts'. Essentailly do what you do now, except put an outer loop to loop the layouts, or
B. Look up GetBlockReferenceIds (this is the fastest way and the way I would do it)
Ok, I shall give that a try - I think there are some examples of how to use GetBlockReferenceIds in Jerry's book. Thanks for your help Glenn.
:)
-
No probs veg. I wouldn't be following Jerry's book too closely though.
-
Right, I figured it was worth posting an update seeing as I've managed to cobble something together that seems to work (using Jerry's book as a guide, and some code I found here (http://tinyurl.com/432b77) - and then converted to VB .Net): -
<CommandMethod("FindBlockInLayout")> _
Public Sub FindBlockInLayout()
Dim myDB As DatabaseServices.Database
Dim myDWG As ApplicationServices.Document
Dim myEd As EditorInput.Editor
Dim myBlockRef As DatabaseServices.BlockReference
Dim myTransMan As DatabaseServices.TransactionManager
Dim myTrans As DatabaseServices.Transaction
Dim I As Integer
Dim J As Integer
Dim myBT As DatabaseServices.BlockTable
Dim myBTR As DatabaseServices.BlockTableRecord
Dim myBTR2 As DatabaseServices.BlockTableRecord
Dim myBTE As IEnumerator
Dim MyBlockstoCheckIds As New DatabaseServices.ObjectIdCollection
Dim myOtherIDs As New DatabaseServices.ObjectIdCollection
Dim tmpObjIDs As New DatabaseServices.ObjectIdCollection
Dim myLayoutIDs As New DatabaseServices.ObjectIdCollection
myDWG = ApplicationServices.Application.DocumentManager.MdiActiveDocument
myDB = myDWG.Database
myEd = myDWG.Editor
myTransMan = myDB.TransactionManager
myTrans = myTransMan.StartTransaction
myBT = DirectCast(myTrans.GetObject(myDB.BlockTableId, OpenMode.ForRead), BlockTable)
myBTE = myBT.GetEnumerator
While myBTE.MoveNext = True
myBTR = DirectCast(myTrans.GetObject(myBTE.Current, OpenMode.ForRead), BlockTableRecord)
' Debug.Print(myBTR.Name)
Select Case myBTR.Name.ToUpper
Case "DRAWING BORDER"
tmpObjIDs = myBTR.GetBlockReferenceIds(False, False)
For I = 1 To tmpObjIDs.Count
myBlockRef = DirectCast(myTrans.GetObject(tmpObjIDs(I - 1), OpenMode.ForRead), BlockReference)
MyBlockstoCheckIds.Add(myBlockRef.ObjectId)
Next
Case Else
If myBTR.IsAnonymous Then
tmpObjIDs = myBTR.GetBlockReferenceIds(False, False)
For I = 1 To tmpObjIDs.Count
myBlockRef = DirectCast(myTrans.GetObject(tmpObjIDs(I - 1), OpenMode.ForRead), BlockReference)
myBTR2 = DirectCast(myTrans.GetObject(myBlockRef.DynamicBlockTableRecord, OpenMode.ForRead), BlockTableRecord)
Select Case myBTR2.Name.ToUpper
Case "DRAWING BORDER"
MyBlockstoCheckIds.Add(myBlockRef.ObjectId)
End Select
Next
End If
End Select
End While
myBT = DirectCast(myTrans.GetObject(myDB.BlockTableId, OpenMode.ForRead), BlockTable)
myBTE = myBT.GetEnumerator
While myBTE.MoveNext
myBTR = DirectCast(myTrans.GetObject(myBTE.Current, OpenMode.ForRead), BlockTableRecord)
If myBTR.IsLayout Then
If Not myBTR.Name.ToUpper Like "*MODEL*" Then 'should provide us with the paperspace layouts only
myLayoutIDs.Add(myBTR.ObjectId)
End If
End If
End While
For I = 1 To MyBlockstoCheckIds.Count
myBlockRef = DirectCast(myTrans.GetObject(MyBlockstoCheckIds(I - 1), OpenMode.ForRead), BlockReference)
For J = 1 To myLayoutIDs.Count
Dim mylayoutBtr As BlockTableRecord = DirectCast(myTrans.GetObject(myLayoutIDs(J - 1), OpenMode.ForRead), BlockTableRecord)
Dim LayoutName As String = ""
If myBlockRef.OwnerId = mylayoutBtr.ObjectId Then
myBTR = DirectCast(myTrans.GetObject(myBlockRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
Dim layoutdict As DBDictionary = DirectCast(myTrans.GetObject(myDB.LayoutDictionaryId, OpenMode.ForRead), DBDictionary)
Dim iLayout As Int32 = 0
For Each id As DictionaryEntry In layoutdict
Dim ltr As Layout = DirectCast(myTrans.GetObject(DirectCast(id.Value, ObjectId), OpenMode.ForRead), Layout)
If mylayoutBtr.ObjectId = ltr.BlockTableRecordId Then
LayoutName = ltr.LayoutName
Debug.Print(ltr.LayoutName)
End If
ed.WriteMessage("" & Chr(10) & "Layout N{0} = {1}", System.Threading.Interlocked.Increment(iLayout), ltr.LayoutName)
Next
MessageBox.Show("We found a drawing border on a layout!" & vbCr & LayoutName & " Was where we found it!")
End If
Next
Next
myTrans.Dispose()
myTransMan.Dispose()
End Sub
The next logical step (for each "Drawing Border" block at least) would be to iterate through it's attributereferences, and check their values against some known values (things like site number, issue date, revision etc.)
-
Why are you using an IEnumerator? There are few places you need to do this and this isn't one of them.
If you looping the BlockTable, use a for each like so:
foreach (ObjectId btrId in bt)
{
BlockTableRecord btr = trans.GetObject(btrId, OpenMode.ForRead, false) as BlockTableRecord;
// ... do more mojo here
}
That's just typed in the edit post section, so don't take it as gospel.
-
Why are you using an IEnumerator? There are few places you need to do this and this isn't one of them.
If you looping the BlockTable, use a for each like so:
foreach (ObjectId btrId in bt)
{
BlockTableRecord btr = trans.GetObject(btrId, OpenMode.ForRead, false) as BlockTableRecord;
// ... do more mojo here
}
That's just typed in the edit post section, so don't take it as gospel.
Looking back at some other similar code, that was the way I had already done it, I did indeed just copy+paste the code that Jerry provided. Ah well.
-
An example for your indigestion :) :
[CommandMethod("BlocksInLayouts")]
static public void BlocksInLayoutsCommand()
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
DBDictionary layoutDict = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead, false) as DBDictionary;
if (layoutDict == null)
{
ed.WriteMessage("{0}Error: Failed to get Layout dictionary.", Environment.NewLine);
return;
}
foreach (DictionaryEntry dictEntry in layoutDict)
{
ed.WriteMessage("{0}Layout name: {1}", Environment.NewLine, dictEntry.Key);
ObjectId layoutId = (ObjectId)dictEntry.Value;
Layout layout = tr.GetObject(layoutId, OpenMode.ForRead, false) as Layout;
}
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead, false) as BlockTable;
foreach (ObjectId btrId in bt)
{
BlockTableRecord btr = tr.GetObject(btrId, OpenMode.ForRead, false) as BlockTableRecord;
if (btr.IsLayout || btr.IsFromExternalReference || btr.IsDynamicBlock
|| btr.IsFromOverlayReference || !btr.HasAttributeDefinitions)
{
continue;
}
if (btr.Name.ToUpper() != "TESTBLOCK")
continue;
ObjectIdCollection blkRefIds = btr.GetBlockReferenceIds(true, false);
if (blkRefIds == null || blkRefIds.Count == 0)
break;
int counter = 0;
foreach (ObjectId blkRefId in blkRefIds)
{
BlockReference blkRef = tr.GetObject(blkRefId, OpenMode.ForRead, false) as BlockReference;
AttributeCollection attRefIds = blkRef.AttributeCollection;
foreach (ObjectId attRefId in attRefIds)
{
AttributeReference attRef = tr.GetObject(attRefId, OpenMode.ForRead, false) as AttributeReference;
switch (attRef.Tag)
{
case "ATTRIBUTE_A":
attRef.UpgradeOpen();
string update = string.Format("{0}. Hey there vege B!", ++counter);
attRef.TextString = update;
attRef.DowngradeOpen();
break;
default:
break;
}
}
}
break;
}
tr.Commit();
}
}
The layout stuff at the beginning doesn't need to be in there to accomplish what you were after, however I left it in there for illustrative purposes.
Have at it.
Cheers,
Glenn.
-
After this line:
attRef.TextString = update;
you may want to add this:
attRef.DowngradeOpen();
Although the code will run just fine without it.
-
Cheers Glenn, that's ace. :)
I was going to ask the following, and then I re-read your code:
I notice that you open the attributereference ForRead meaning you wouldn't be able to edit the entry?
I guess that the attRef.UpgradeOpen is enough to allow editing?
-
It does exactly what is says it does - Upgrade the Open Status of the object. So, in this case, it was open for read and by upgrading it, it goes to OpenForWrite status.
-
Scrap what I said about adding a call to DowngradeOpen()
This will cause it to not update the attribute at all - don't know what I was on when I made that statement...
-
Having a bad day. The call to DowngradeOpen is ok.
I found an error in my logical negation.
This:
!btr.IsDynamicBlock
should have been this:
btr.IsDynamicBlock
Sorry about that. I've fixed the original code as well.
-
Hello all (first post) (Some experience with .net c# and VB, but fairly new to AutoCAD)
I am using VS 2008 and ACad 2009
I have a similar requirment to this thread and I learned a lot from this thread, Thanks for posting lots of code!
Now in my application I have to read many title blocks from many files, allow the user to edit any and all attributes and then if they do edit them, udate the attributes in the files.
You can see from the code, that I am getting all the title blocks, even though they can be in model space or in one or more paper space blocks. So far so good. What I want to do is save the location of the title blocks from each file later updates (I don't keep the drawings open between reading and updating), so I want to track where they were found, either in model space or paper space, and if in paper space which paper space block they were in. I can do this using tblock.InsertSpace. The only problem is if one of the paper spaces is the current space, I can only get "*paper_space" instead of the "*paper_space##" name that I need. Theoretically the file could be opened between the read and update and saved with another paper space as the current space.
So does anyone know of a way to get the actual name of a paper space when it is the current space?
Also I thought I saw somewhere how to get the name on the space tab instead of the paper space name, does anyone know how to get that?
TIA
Public Function AddDrawing(ByVal fName As String) As Integer
' Read all title blocks in the current drawing and add to the drawings collection
Dim tblock As sida_TBAttributes
Dim iCount As Integer ' The number of drawings added to the collection
' mark if we found anything or not
Dim tbFound As Boolean = False
If fName = "" Then
AddDrawing = 0
Else
' Create a document object
Dim doc As Document
doc = Application.DocumentManager.MdiActiveDocument
' create an editor object
Dim ed As Editor = doc.Editor
' create a database and try to load the selected file
Dim db As Database = New Database(False, True)
Using (db)
Try
' open the file for reading
db.ReadDwgFile(fName, FileOpenMode.OpenForReadAndAllShare, False, "")
' start a transaction
Dim tr As Transaction = db.TransactionManager.StartTransaction()
Using (tr)
Dim bFoundTB As Boolean = False
Dim btr As BlockTableRecord
' open the block table
Dim bt As BlockTable = tr.GetObject(db.BlockTableId, OpenMode.ForRead)
' If a title block exists then open the blocktable record
If bt.Has("Titleblock_Type1") Then
btr = tr.GetObject(bt("Titleblock_Type1"), OpenMode.ForRead)
tbFound = True
ElseIf bt.Has("Titleblock_Type2") Then
btr = tr.GetObject(bt("Titleblock_Type2"), OpenMode.ForRead)
tbFound = True
ElseIf bt.Has("Titleblock_Type3") Then
btr = tr.GetObject(bt("Titleblock_Type3"), OpenMode.ForRead)
tbFound = True
End If
If tbFound Then
Dim objIds As ObjectIdCollection = btr.GetBlockReferenceIds(False, False)
Dim objId As ObjectId
' Get the info on all the titleblocks in a file
For Each objId In objIds
Dim i As Integer
Dim ac As Integer
Dim blockref As BlockReference = tr.GetObject(objId, OpenMode.ForRead)
' A new attribute class for the new title block
tblock = New sida_TBAttributes()
iCount = 0
' Save the drawing file name
tblock.DWGFilePathName = fName
' Save the paper/model space the title block is on
'**** Current paperspace only returns "*paper_space" not actual name
'**** like "*paper_space12"
'tblock.InsertSpace = blockref.BlockName
' get the attributes
ac = blockref.AttributeCollection.Count
For i = 0 To ac - 1
Dim atr As AttributeReference
' Cast the enumerated type to an attribute reference
atr = CType(tr.GetObject(blockref.AttributeCollection(i), OpenMode.ForRead, False, True), AttributeReference)
tblock.AddTBlockAttInfo(blockref.Name, i, atr.TextString)
Next
' Add the TB to the collection
Try
Me.Drawings.Add(tblock, tblock.attProject.OrderNumber + _
tblock.attSheet.Number + tblock.attRev.CurrentRevisionLevel)
' Update the count of TB's we have found
iCount += 1
Catch
' It already exists so we don't add, but also don't need to do anything here
End Try
Next
End If
End Using
Catch
End Try
End Using
End If
AddDrawing = iCount
End Function
Eric
-
Welcome to TheSwamp Eric!
I’m not sure what you mean by “space tab”, bit if you mean the Layout Name you can try to retrieve this by getting the owner id of the block reference then getting it’s LayoutId
i.e..
void Commands::doit()
{
Editor ^pEditor = Application::DocumentManager->MdiActiveDocument->Editor;
Database ^pDatabase = HostApplicationServices::WorkingDatabase;
try
{
AcDb::TransactionManager ^pTransactionManager = pDatabase->TransactionManager;
Transaction ^pTransaction = pTransactionManager->StartTransaction();
try
{
BlockTable ^pBlockTable = dynamic_cast<BlockTable^>
(pTransaction->GetObject(pDatabase->BlockTableId, OpenMode::ForRead));
if (pBlockTable->Has("n"))
{
BlockTableRecord ^pBlockTableRecord = dynamic_cast<BlockTableRecord^>
(pTransaction->GetObject(pBlockTable["n"], OpenMode::ForRead));
ObjectIdCollection ^pBlockReferenceIds =
pBlockTableRecord->GetBlockReferenceIds(false, false);
for each (ObjectId blockReferenceId in pBlockReferenceIds)
{
BlockReference ^pBlockReference = dynamic_cast<BlockReference^>
(pTransaction->GetObject(blockReferenceId, OpenMode::ForRead));
BlockTableRecord ^pOwnerRecord = dynamic_cast<BlockTableRecord^>
(pTransaction->GetObject (pBlockReference->OwnerId, OpenMode::ForRead));
Layout ^pLayout = dynamic_cast<Layout^>
(pTransaction->GetObject (pOwnerRecord->LayoutId, OpenMode::ForRead));
pEditor->WriteMessage("\n{0}",pLayout->LayoutName);
}
}
}
finally
{
delete pTransaction;
}
}
catch (System::Exception ^ex)
{
pEditor->WriteMessage(ex->Message);
}
}
-
Also…this might be a stupid question, but have you considered using fields? E.g.
CurrentRevisionLevel && OrderNumber could point to variables in your custom summary info. Then all you need to do is update those variables in each database.
-
Welcome to TheSwamp Eric!
I’m not sure what you mean by “space tab”, bit if you mean the Layout Name you can try to retrieve this by getting the owner id of the block reference then getting it’s LayoutId
Thanks, I will take a look at this next week.
The tab name is the name that is diplayed in the tabs if you set the "Dispaly Model and Layout Tabs" check box in the "Layout Elements" group of the "Display" tab of the Options dialog window.
The sample file I am working on shows the paper space name as "*paper_space12" but the displayed tab shows "108" which is what the user changed it to.
Eric
-
Also…this might be a stupid question, but have you considered using fields? E.g.
CurrentRevisionLevel && OrderNumber could point to variables in your custom summary info. Then all you need to do is update those variables in each database.
This is all legacy stuff that I have to deal with. Hundreds (perhaps thousands) of existing files. There is no DB of anything right now, everything is done manually: printing, editing title blocks, creating transmittals, cover letters, etc. The plan is to automate the existing process using all existing Excel data while also dumping everything into a DB, so that eventually we can switch over to only a DB. One of the title blocks is from an AutoCad add-on that uses there on data fields for some of the title block. There will probably always be three different title blocks. I could change 2 of them to use fields and have considered this, but it adds another process to manage or account for.
I will check into this though and appreciate your suggestion.
Eric
-
Cool, then the code ought to work for you.
Yes, do have a look at putting field variables in those attributes, they works quite well. What I meant by database was the dwg file, not an external database
-
An example for your indigestion :) :
[CommandMethod("BlocksInLayouts")]
static public void BlocksInLayoutsCommand()
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
DBDictionary layoutDict = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead, false) as DBDictionary;
if (layoutDict == null)
{
ed.WriteMessage("{0}Error: Failed to get Layout dictionary.", Environment.NewLine);
return;
}
foreach (DictionaryEntry dictEntry in layoutDict)
{
ed.WriteMessage("{0}Layout name: {1}", Environment.NewLine, dictEntry.Key);
ObjectId layoutId = (ObjectId)dictEntry.Value;
Layout layout = tr.GetObject(layoutId, OpenMode.ForRead, false) as Layout;
}
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead, false) as BlockTable;
foreach (ObjectId btrId in bt)
{
BlockTableRecord btr = tr.GetObject(btrId, OpenMode.ForRead, false) as BlockTableRecord;
if (btr.IsLayout || btr.IsFromExternalReference || btr.IsDynamicBlock
|| btr.IsFromOverlayReference || !btr.HasAttributeDefinitions)
{
continue;
}
if (btr.Name.ToUpper() != "TESTBLOCK")
continue;
ObjectIdCollection blkRefIds = btr.GetBlockReferenceIds(true, false);
if (blkRefIds == null || blkRefIds.Count == 0)
break;
int counter = 0;
foreach (ObjectId blkRefId in blkRefIds)
{
BlockReference blkRef = tr.GetObject(blkRefId, OpenMode.ForRead, false) as BlockReference;
AttributeCollection attRefIds = blkRef.AttributeCollection;
foreach (ObjectId attRefId in attRefIds)
{
AttributeReference attRef = tr.GetObject(attRefId, OpenMode.ForRead, false) as AttributeReference;
switch (attRef.Tag)
{
case "ATTRIBUTE_A":
attRef.UpgradeOpen();
string update = string.Format("{0}. Hey there vege B!", ++counter);
attRef.TextString = update;
attRef.DowngradeOpen();
break;
default:
break;
}
}
}
break;
}
tr.Commit();
}
}
I'm new to C, so just trying to get my head around this. I'd know how to do this in VB, but am still getting to grips with C. I don't understand how this works.
At this point in the code, it scrolls through all of the layouts...
DBDictionary layoutDict = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead, false) as DBDictionary;
foreach (DictionaryEntry dictEntry in layoutDict)
{
ed.WriteMessage("{0}Layout name: {1}", Environment.NewLine, dictEntry.Key);
ObjectId layoutId = (ObjectId)dictEntry.Value;
Layout layout = tr.GetObject(layoutId, OpenMode.ForRead, false) as Layout;
}
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead, false) as BlockTable;
... but that seems to be nothing more than a loop. How does this code tie the layouts to the blocks that exist in each of the layouts? The code for extracting block information comes after this. It would seem there's no relationship between the layouts an the blocks, and I've confirmed this. This program lists the contents of blocks in layouts other than the current one.
Any ideas?
-
I used a bit of Glenn R's code, and a bit of my own. Forgive the ol' VB programmer turning it into code VB programmers would probably understand more easily, but I think this is more logical for us.
This code allows the developer to access the blocks on the current layout (whatever layout that is), and update their attributes. It could, however, be used to find any object type on any layout, if that's what you wanted.
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// Edit the AutoCAD Drawing
//
// Place at the beginning of the module
/*
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
*/
// Placed earlier in the class.
/*
Document acdDOC = AcadApp.DocumentManager.MdiActiveDocument;
Database acdDB = acdDOC.Database;
Editor acdED = acdDOC.Editor;
*/
using ( Transaction acdTR = acdDB.TransactionManager.StartTransaction())
{
// get a BlockTableRecord of the current space being used in AutoCAD
BlockTableRecord acdBTR = (BlockTableRecord)acdTR.GetObject(acdDB.CurrentSpaceId, OpenMode.ForRead);
// create the Layout Object
Layout acdLayout = (Layout)acdTR.GetObject(acdBTR.LayoutId, OpenMode.ForRead);
// write the layout name to the autocad console.
acdED.WriteMessage("{0}Layout name: {1}", Environment.NewLine, acdLayout.LayoutName);
// Get the block table record for that layout.
BlockTableRecord acdLayoutBTR = (BlockTableRecord)acdTR.GetObject(acdLayout.BlockTableRecordId, OpenMode.ForRead);
if (acdLayoutBTR.IsLayout == true)
{
// scroll through each objectid in this layout
foreach (ObjectId objId in acdLayoutBTR)
{
// create an entity object from each objectid
Entity acdENT = (Entity)acdTR.GetObject(objId, OpenMode.ForRead );
System.Type objType = acdENT.GetType();
string strEntType = objType.Name;
// find out if this object is a BlockReference
if (strEntType == "BlockReference") {
// create a BlockReference of that object
BlockReference acdBR = (BlockReference)acdTR.GetObject(objId, OpenMode.ForRead);
// if you want to only look for a specific block, put that if statement here. I'm updating all attributes of a certain value in this code.
// if (xx == yy)
// {
AttributeCollection acdATTRefIds = acdBR.AttributeCollection;
foreach (ObjectId acdATTRefId in acdATTRefIds)
{
AttributeReference acdATTRef = acdTR.GetObject(acdATTRefId, OpenMode.ForRead, false) as AttributeReference;
switch (acdATTRef.Tag)
{
case "ATTRIBUTE_A":
acdATTRef.UpgradeOpen();
acdATTRef.TextString = "Blah Blah Blah";
acdATTRef.DowngradeOpen();
break;
default:
break;
}
}
// end the block conditional if statement here.
// }
}
}
}
acdED.WriteMessage("{0}Completed Processing Blocks", Environment.NewLine);
acdTR.Commit();
}
//
// Edit the AutoCAD Drawing
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Apologies for the formatting. If you quote the message, the formatting actually works. It just respaces it for this window.
-
can't make time to look at your code ..
... regarding changing Glens variable names,
If you have a look around you will notice that there are some variable names like doc db ed tr tm btr ent that are used consistently by a lot of programmenrs ( here and elsewhere.
I had a giggle to see that those were the names you changed to make the code more readable.
-
I concur Kerry :D
I also find the penchant for VB'ers to use string comparisons for entity types funny...use typeof or 'as' would be my recommendation.