Hello, I've hit a wall trying to access an existing table by layer name in vb.net. I've seen in the help documents how to play around with tables when creating a new one, but I can't find an example online that gets me access to one without user input. I have only one table in the drawing and it is on layer "BOMTable". I figured this would be enough to filter through the entities in the drawing and get me access to the table. I'm still learning the Autocad API, and I'm willing to go through the motions with trial and error to get certain cell contents via the help documents. But I just need to know how to iterate through all entities in a drawing, then if that entity is on layer "BOMTable", assign my acTable variable to that entity. I'll stumble on from there. Any help would be GREATLY appreciated. Thank You.
Solved! Go to Solution.
Solved by khoa.ho. Go to Solution.
Solved by cncah. Go to Solution.
I got it.
Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument Dim acDB As Database = acDoc.Database Dim acBlkTbl As BlockTable Dim acBlkTblRec As BlockTableRecord Dim acTable As Table = Nothing Using acTrans As Transaction = acDB.TransactionManager.StartTransaction acBlkTbl = acTrans.GetObject(acDB.BlockTableId, OpenMode.ForRead) acBlkTblRec = acTrans.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), _ OpenMode.ForWrite) For Each acObjId As ObjectId In acBlkTblRec Dim ent As Entity = acTrans.GetObject(acObjId, OpenMode.ForRead) If TypeOf ent Is Table And CStr(ent.Layer) = "BOMTable" Then acTable = ent Exit For End If Next End Using
It is better to have a generic method to get entities from a give type (table, line...), then use it to retrieve any information you want. Here is the code:
C#
public class Test { [CommandMethod("GetEntitiesByType")] public static void GetEntitiesByType() { var doc = Application.DocumentManager.MdiActiveDocument; var db = doc.Database; IEnumerable<Table> list = GetAllEntitiesInModelSpace<Table>(db); foreach (Table table in list) { string layer = table.Layer; } } public static IEnumerable<T> GetAllEntitiesInModelSpace<T>(Database db, OpenMode openMode = OpenMode.ForRead, bool openErased = false) { using (Transaction trans = db.TransactionManager.StartTransaction()) { var blockTable = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead); var model = (BlockTableRecord)trans.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForRead); var list = new List<T>(); foreach (ObjectId id in model) { var entity = trans.GetObject(id, openMode, openErased) as Entity; if ((entity != null) && (entity is T)) { object obj2 = entity; list.Add((T)obj2); } } return list; } } }
VB.NET
Public Class Test <CommandMethod("GetEntitiesByType")> _ Public Shared Sub GetEntitiesByType() Dim doc = Application.DocumentManager.MdiActiveDocument Dim db = doc.Database Dim list As IEnumerable(Of Table) = GetAllEntitiesInModelSpace(Of Table)(db) For Each table As Table In list Dim layer As String = table.Layer Next End Sub Public Shared Function GetAllEntitiesInModelSpace(Of T)(db As Database, Optional openMode__1 As OpenMode = OpenMode.ForRead, Optional openErased As Boolean = False) As IEnumerable(Of T) Using trans As Transaction = db.TransactionManager.StartTransaction() Dim blockTable = DirectCast(trans.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable) Dim model = DirectCast(trans.GetObject(blockTable(BlockTableRecord.ModelSpace), OpenMode.ForRead), BlockTableRecord) Dim list = New List(Of T)() For Each id As ObjectId In model Dim entity = TryCast(trans.GetObject(id, openMode__1, openErased), Entity) If (entity IsNot Nothing) AndAlso (TypeOf entity Is T) Then Dim obj2 As Object = entity list.Add(DirectCast(obj2, T)) End If Next Return list End Using End Function End Class
We can use all LINQ for IEnumerable type classes to have shorter code, but it will make it difficult to understand than longer code.
Why do you include optional parameters to GetAllEntitiesInModelSpace ??
I can understand perhaps using openErased but not not openMode .
// Called Kerry in my other life.
Everything will work just as you expect it to, unless your expectations are incorrect.
class keyThumper<T> : Lazy<T>; another Swamper
I use optional parameters in GetAllEntitiesInModelSpace to get more options of the entity type to read or write. Here is the modified version which is better for faster performance, and presents both OpenMode.ForRead and .ForWrite
Instead of using Transaction.GetObject for every objects in model space during the loop, which costs memory and time, we can check class of an ObjectId for a given type.
C#
[CommandMethod("ReadEntities")] public static void ReadEntities() { Document doc = Application.DocumentManager.MdiActiveDocument; Editor editor = doc.Editor; Database db = doc.Database; using (Transaction trans = db.TransactionManager.StartTransaction()) { // Get all lines in model space for read IEnumerable<Line> list = GetAllEntitiesInModelSpace<Line>(db); foreach (Line line in list) { // Display line info editor.WriteMessage(line.StartPoint.ToString() + "," + line.EndPoint.ToString()); } } } [CommandMethod("WriteEntities")] public static void WriteEntities() { Document doc = Application.DocumentManager.MdiActiveDocument; Editor editor = doc.Editor; Database db = doc.Database; using (Transaction trans = db.TransactionManager.StartTransaction()) { // Get all circles in model space for write IEnumerable<Circle> list = GetAllEntitiesInModelSpace<Circle>(db, OpenMode.ForWrite); foreach (Circle circle in list) { // Change circle radius by multiply 2 circle.Radius *= 2; // Downgrade this entity to read before transaction commit circle.DowngradeOpen(); } trans.Commit(); } } public static IEnumerable<T> GetAllEntitiesInModelSpace<T>(Database db, OpenMode openMode = OpenMode.ForRead, bool openErased = false) where T : DBObject { var list = new List<T>(); using (Transaction trans = db.TransactionManager.TopTransaction ?? db.TransactionManager.StartTransaction()) { var blockTable = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead); var model = (BlockTableRecord)trans.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForRead); foreach (ObjectId id in model) { if (id.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(T)))) { DBObject entity = trans.GetObject(id, openMode, openErased); list.Add((T)entity); } } } return list; }
VB.NET
<CommandMethod("ReadEntities")> _ Public Shared Sub ReadEntities() Dim doc As Document = Application.DocumentManager.MdiActiveDocument Dim editor As Editor = doc.Editor Dim db As Database = doc.Database Using trans As Transaction = db.TransactionManager.StartTransaction() ' Get all lines in model space for read Dim list As IEnumerable(Of Line) = GetAllEntitiesInModelSpace(Of Line)(db) For Each line As Line In list ' Display line info editor.WriteMessage(line.StartPoint.ToString() + "," + line.EndPoint.ToString()) Next End Using End Sub <CommandMethod("WriteEntities")> _ Public Shared Sub WriteEntities() Dim doc As Document = Application.DocumentManager.MdiActiveDocument Dim editor As Editor = doc.Editor Dim db As Database = doc.Database Using trans As Transaction = db.TransactionManager.StartTransaction() ' Get all circles in model space for write Dim list As IEnumerable(Of Circle) = GetAllEntitiesInModelSpace(Of Circle)(db, OpenMode.ForWrite) For Each circle As Circle In list ' Change circle radius by multiply 2 circle.Radius *= 2 ' Downgrade this entity to read before transaction commit circle.DowngradeOpen() Next trans.Commit() End Using End Sub Public Shared Function GetAllEntitiesInModelSpace(Of T As DBObject)(db As Database, Optional openMode1 As OpenMode = OpenMode.ForRead, Optional openErased As Boolean = False) As IEnumerable(Of T) Dim list = New List(Of T)() Using trans As Transaction = If(db.TransactionManager.TopTransaction, db.TransactionManager.StartTransaction()) Dim blockTable = DirectCast(trans.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable) Dim model = DirectCast(trans.GetObject(blockTable(BlockTableRecord.ModelSpace), OpenMode.ForRead), BlockTableRecord) For Each id As ObjectId In model If id.ObjectClass.IsDerivedFrom(RXClass.GetClass(GetType(T))) Then Dim entity As DBObject = trans.GetObject(id, openMode1, openErased) list.Add(DirectCast(entity, T)) End If Next End Using Return list End Function
Khoa