Iterating through all block references in Model Space in C# to get their names?

Iterating through all block references in Model Space in C# to get their names?

Anonymous
Not applicable
11,271 Views
11 Replies
Message 1 of 12

Iterating through all block references in Model Space in C# to get their names?

Anonymous
Not applicable

I'm having a hard time with the .NET API. To begin with, I find the object hierarchy documentation cumbersome, even more, I haven't managed to find a proper "map" showing object relationships and dependencies. Is it just me or it's way more complicated than VBA? I've read the Autodesk documentation to no avail. 

 

I've been lately challenging myself through coding in order to make sure I have a good grasp of object relationships. Next, I'm pasting the code corresponding to a custom command meant to list all block references names in my drawing - just for practising purposes - . It turns out AutoCad crashes and I suspect is because I haven't understood how the Blockreference object relates to the BlockTableRecord, I guess. Aren't block references contained in the Model Space block table? Can anybody point me in the right direction? 

 

[CommandMethod("ListarBloques")]
public void ListarBloques()
{
Document miDibujo = Application.DocumentManager.MdiActiveDocument;
Database misElementos = miDibujo.Database;

using(Transaction miTransaccion = misElementos.TransactionManager.StartTransaction())
{
BlockTable blckTbl;
blckTbl = miTransaccion.GetObject(misElementos.BlockTableId, OpenMode.ForRead) as BlockTable;

BlockTableRecord blckTblRcrd;
blckTblRcrd = miTransaccion.GetObject(blckTbl[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;

foreach (ObjectId id in blckTblRcrd)
{
BlockReference blckRef;
blckRef = miTransaccion.GetObject(id, OpenMode.ForRead) as BlockReference;
miDibujo.Editor.WriteMessage("" + blckRef.Name);
}

miTransaccion.Commit();
}
}
}

 

0 Likes
Accepted solutions (2)
11,272 Views
11 Replies
Replies (11)
Message 2 of 12

_gile
Consultant
Consultant
Accepted solution

Hi,

 

You can see a simplified example of the AutoCAD .NET object hierarchy here.

 

To get all the block references from model space you can start with this:

        [CommandMethod("ListarBloques")]
        public void ListarBloques()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                // open the block table which contains all the BlockTableRecords (block definitions and spaces)
                var blockTable = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);

                // open the model space BlockTableRecord
                var modelSpace = (BlockTableRecord)tr.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForRead);

                // iterate through the model space 
                foreach (ObjectId id in modelSpace)
                {
                    // check if the current ObjectId is a block reference one
                    if (id.ObjectClass.DxfName == "INSERT")
                    {
                        // open the block reference
                        var blockReference = (BlockReference)tr.GetObject(id, OpenMode.ForRead);

                        // print the block name to the command line
                        ed.WriteMessage("\n" + blockReference.Name);
                    }
                }

                tr.Commit();
            }
        }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 12

Anonymous
Not applicable

Thanks for your reply, gile, I had already checked your link and the whole manual before opening this post. I feel there should a much more comprehensive map out there. For instance, where are the block references, where are the DBObjects? I think the object hierarchy map for VBA is clearer. That's what I'm after in .NET, but apparently doesn't exist. Does it?

 

Going back to your code, hmmm it seems pretty similar to mine, the only difference being the DxfName property (does it have anything to do with the Dxf codes that one would use, for example, with selection sets?). Instead of filtering based on that I use the "As" keyword. Could you please take a look at my code and tell me if you see anything wrong to make AutoCad crash? 

Thank you. 

0 Likes
Message 4 of 12

ilovejingle
Enthusiast
Enthusiast
Accepted solution

I think the issue of your code is that you are casting everything in ModelSpace to a BlockReference object which is not necessarily true. I modify your code a bit and I found it running without any issues.

        [CommandMethod("TestMe")]
        public void ListarBloques()
        {
            Document miDibujo = Application.DocumentManager.MdiActiveDocument;
            Database misElementos = miDibujo.Database;

            using (Transaction miTransaccion = misElementos.TransactionManager.StartTransaction())
            {
                BlockTable blckTbl;
                blckTbl = miTransaccion.GetObject(misElementos.BlockTableId, OpenMode.ForRead) as BlockTable;

                BlockTableRecord blckTblRcrd;
                blckTblRcrd = miTransaccion.GetObject(blckTbl[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;

                foreach (ObjectId id in blckTblRcrd)
                {
                    
                    var  dbObj = miTransaccion.GetObject(id, OpenMode.ForRead);
                    if(dbObj is BlockReference)
                    {
                        var blckRef = (BlockReference)dbObj;
                        miDibujo.Editor.WriteMessage("" + blckRef.Name);
                    }
                }

                miTransaccion.Commit();
            }
        }

 

Message 5 of 12

_gile
Consultant
Consultant

@Anonymous wrote:

Thanks for your reply, gile, I had already checked your link and the whole manual before opening this post. I feel there should a much more comprehensive map out there. For instance, where are the block references, where are the DBObjects? I think the object hierarchy map for VBA is clearer. That's what I'm after in .NET, but apparently doesn't exist. Does it?


The .NET API is much greater than the COM/ActiveX API (the one use by VBA).

If you've downloaded the ObjectARX SDK for the version(s) of AutoCAD you use (as you should have), you'll find the ObjectARX 20XX\classmap\classma.dwg file which shows the class hierachies for ObjectARX C++, Managed ObjectARX (.NET) and ActiveX.

 

 


@Anonymous wrote:

Going back to your code, hmmm it seems pretty similar to mine, the only difference being the DxfName property (does it have anything to do with the Dxf codes that one would use, for example, with selection sets?). Instead of filtering based on that I use the "As" keyword. Could you please take a look at my code and tell me if you see anything wrong to make AutoCad crash?


Checking the type from ObjectId.ObjectClass is cheaper than opening  the object before checking its type.

As said by @ilovejingle, your code craches because you do not check if blockReference is null (i.e. the object was not a block reference).

// open the object as block reference
var blockReference = tr.GetObject(id, OpenMode.ForRead) as BlockReference;

// check if the object was a block reference
if (blockReference != null)
{ // print the block name to the command line ed.WriteMessage("\n" + blockReference.Name);
}

 

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 6 of 12

Anonymous
Not applicable

I haven't had the chance to review my code but I've been thinking all the time about the solution and knew I was not using the As keyword properly with the "null" check. I guess that my code was checking for null.Name and that was making it crash. 

 

If you or anybody else happens to have a good object hierarchy map, I'd highly appreciate it!

 

Thanks a lot for your help.

0 Likes
Message 7 of 12

Anonymous
Not applicable

Thanks again for the heads-up. I'll keep the memory save in mind in future projects.

 

🙂

0 Likes
Message 8 of 12

_gile
Consultant
Consultant

@Anonymous wrote:

If you or anybody else happens to have a good object hierarchy map, I'd highly appreciate it!


As said upper, you should download the ObjectARX SDK for the AutoCAD version you use.

It contains a complete .chm documentation, code samples, AutoCAD libraries to be referenced in VisualStudio and a classmap.dwg with the complete object hierarchy.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 9 of 12

0906dokaga
Explorer
Explorer

Hi, I tried this code, but it does not include the names of the dynamic blocks. 

why is that?

0 Likes
Message 10 of 12

Ed__Jobe
Mentor
Mentor

Use the EffectiveName property instead of the Name property. A dynamic block that has changed from the default view will be an anonymous block name, but the EffectiveName will have the name of the original block.

Ed


Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
How to post your code.

EESignature

0 Likes
Message 11 of 12

0906dokaga
Explorer
Explorer

thanks for your reply.

 

first. I could not find the EffectiveName property.

 

0906dokaga_0-1703305428814.png

 

 

second: The dynamic block will show if it remains to the default, but once change it will not be available in the blckTblRcrd

 

0906dokaga_1-1703304990852.png

 

 

 

0 Likes
Message 12 of 12

_gile
Consultant
Consultant

EffectivName is not available in the .NET API (it's a COM API property).

You can get the name of an anonymous dynamic block reference via its dynamic block definition.

// iterate through the model space 
foreach (ObjectId id in modelSpace)
{
    if (id.ObjectClass.DxfName == "INSERT")
    {
        // open the block reference
        var blockReference = (BlockReference)tr.GetObject(id, OpenMode.ForRead);
		
	    // get the (dynamic) block definition
	    var dynamicBlockDefinition = (BlockTableRecord)tr.GetObject(blockReference.DynamicBlockTableRecord, OpenMode.ForRead);

        // print the block name to the command line
        ed.WriteMessage("\n" + dynamicBlockDefinition.Name);
    }
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes