I have a successful Copy Layer program that copies all entities on an xref layer to the current (non-Xref) layer. I'm doing this by creating a new database, and using the db.ReadDwgFile() function. My question is: is it possible to use db.WblockCloneObjects to copy objects by accessing the in-memory xref database? I can get the database using XrefGraphNode.Database, but all efforts to use WblockCloneObjects have failed. Can anyone provide direction? Thanks in advance for your efforts. Pete Elliott
Yes, we can. But instead of using WblockCloneObjects which may cause eWrongDatabase error, we can use Clone() method of entities from Xref database. This is a different way to copy entities between AutoCAD databases. The following code is an example to copy all entities (except BlockReference) from xrefs to the host drawing:
[CommandMethod("CopyEntitiesFromXrefs")] public static void CopyEntitiesFromXrefs() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; using (Transaction trans = db.TransactionManager.StartTransaction()) { try { var list = new List<Entity>(); var bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead); var modelSpace = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite); XrefGraph xrefGraph = db.GetHostDwgXrefGraph(true); int xrefCount = xrefGraph.NumNodes; for (int i = 0; i < xrefCount; i++) { XrefGraphNode xrefNode = xrefGraph.GetXrefNode(i); Database xrefDb = xrefNode.Database; using (var xrefBt = (BlockTable)trans.GetObject(xrefDb.BlockTableId, OpenMode.ForRead, false)) { using (var xrefModelSpace = (BlockTableRecord)trans.GetObject(xrefBt[BlockTableRecord.ModelSpace], OpenMode.ForRead, false)) { foreach (ObjectId id in xrefModelSpace) { DBObject obj = trans.GetObject(id, OpenMode.ForRead); Entity clonedEntity = (Entity)obj.Clone(); list.Add(clonedEntity); } } } } if (list.Count > 0) { foreach (Entity entity in list) { modelSpace.AppendEntity(entity); trans.AddNewlyCreatedDBObject(entity, true); } } modelSpace.DowngradeOpen(); modelSpace.Dispose(); bt.Dispose(); trans.Commit(); } catch (System.Exception ex) { } } }
This code does not copy BlockReference as it requires BlockTableRecord to import from source to destination database. In-memory xref database is much faster than db.ReadDwgFile() as all external databases were loaded inside AutoCAD memory.
You can extend the code with predicate delegate to filter out entities of specified properties (layer, entity type…).
Have a look at Hallex solution for copying BlockTableRecord between two AutoCAD databases at the post: http://forums.autodesk.com/t5/NET/Copy-of-BlockTableRecord-save-as/td-p/3602444
I have a feeling that we can use either WblockCloneObjects() or Clone() from my code to replicate entities. But we have to do some twists (Deep Cloning) to avoid eWrongDatabase error. I will go back later today as I have a hard time to maintain my daily job while playing with this forum.
If you use db.ReadDwgFile to open xref and db.WblockCloneObjects to clone xref entities (including BlockReference), it should not be a problem for your task. I tested it works.
The problem is in-memory xrefs deny all cloning process either to use db.WblockCloneObjects or db.DeepCloneObjects, AutoCAD returns errors of eWrongDatabase or eInvalidOwnerObject. I have no luck with it now. I will go back this pain problem later when I have more time.
You can use DBObject.DeepClone instead of RXObject.Clone to copy the BlockReference objects.