When I use the following code to clone dynamic blocks to a different drawing database, the blocks in the destination drawing are either invisible or their geometry is black where the color is set by layer (block geometry with explicit color assigned is drawn correctly). I've confirmed that the layers the source blocks are assigned to in the source drawing exist and have the same color in the destination drawing prior to cloning.
Here is the code responsible for cloning the blocks:
Using maps As New IdMapping() Dim cloned As Boolean = False Dim clones As New ObjectIdCollection() Using lock As DocumentLock = destDocument.LockDocument() Using srcTran As Transaction = sourceDocument.TransactionManager.StartTransaction() Using destTran As Transaction = destDocument.TransactionManager.StartTransaction() Try sourceDocument.Database.WblockCloneObjects(sourceObjs, destDocument.Database.CurrentSpaceId, maps, DuplicateRecordCloning.Replace, False) For Each clId As IdPair In maps If clId.IsPrimary AndAlso clId.IsCloned Then clones.Add(clId.Value) Next destTran.Commit() cloned = True Catch ex As System.Exception destTran.Abort() cloned = False End Try End Using End Using End Using
Here is the result in the destination drawing:
Here is what the blocks should look like:
The color is defined in the layer these blocks are assigned to. If I save the drawing containing the cloned blocks, close it, then open it, the color is correct. Also, sometimes the blocks in the destination drawing are completely invisible until I select them, then they have the same black geometry issue after selection.
I've tried regen and UpdateScreen to no effect. However, if I use the LAYER command and freeze/unfreeze the layers these blocks are assigned to, their color is rendered correctly after. I'm sorry if my terminology is off; I do not use AutoCAD, I've just been developing plugins.
Thanks in advance for any advice,
Kevin
Solved! Go to Solution.
Solved by moogalm. Go to Solution.
Can you please share sample drawing , at my end I'm not able to reproduce the behavior.
Steps I Followed.
public void ImportBlocks() { DocumentCollection dm = Application.DocumentManager; Editor ed = dm.MdiActiveDocument.Editor; Database destDb = dm.MdiActiveDocument.Database; Database sourceDb = new Database(false, true); string sourceFileName; try { sourceFileName = "C:\\Users\\moogalm\\Documents\\CustomerData\\Test_DynMicBlock.dwg"; sourceDb.ReadDwgFile(sourceFileName, System.IO.FileShare.Read, true, ""); ObjectIdCollection blockIds = new ObjectIdCollection(); Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = sourceDb.TransactionManager; using (Transaction myT = tm.StartTransaction()) { BlockTable bt = (BlockTable)tm.GetObject(sourceDb.BlockTableId, OpenMode.ForRead, false); foreach (ObjectId btrId in bt) { BlockTableRecord btr = (BlockTableRecord)tm.GetObject(btrId, OpenMode.ForRead, false); if ( !btr.IsLayout) blockIds.Add(btrId); btr.Dispose(); } } IdMapping mapping = new IdMapping(); sourceDb.WblockCloneObjects(blockIds, destDb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false); ed.WriteMessage("\nCopied " + blockIds.Count.ToString() + " block definitions from " + sourceFileName + " to the current drawing."); } catch (Autodesk.AutoCAD.Runtime.Exception ex) { ed.WriteMessage("\nError during copy: " + ex.Message); } sourceDb.Dispose(); }
Attached DWG, I used.
Note: Don't share any confidential data.
I've attached a project which can be used to reproduce the results. In the project directory there are 3 drawing files. I included BCC250.dwg, which just includes the definition of the dynamic block used in the other two drawings in case you need it.
To reproduce, open SourceDrawing.dwg and DestDrawing.dwg. Make SourceDrawing the active drawing and run the command TestCommand defined in the plugin. Select the only block instance in the SourceDrawing when prompted to, then hit enter. The resulting geometry in DestDrawing is not black as it is when I use my actual plugin, but it is neither the color of the active layer nor is it the color assigned to the layer (Layer1) created by my AddLayer method, which the block in the dest drawing is assigned to if you click on it.
If you remove the call to AddLayer, the block is invisible in the DestDrawing. I had to take code from various places in my actual plugin and paste it all into this project to reproduce.
Thanks,
Kevin
Hi ,
This because your are cloning to current space ,
sourceDocument.Database.WblockCloneObjects(sourceObjs, destDocument.Database.CurrentSpaceId, maps, DuplicateRecordCloning.Replace, False)
You need to use ,BlockTable as container not Current Space. Use destDocument.Database.BlockTableId
Now definations are cloned to blocktable container, and you can "INSERT" to get the block reference with color of active layer. No need to add layer in your code ,layer is created by wblockclone api in the dest drawing.
wblockclone API is very lowleve functionality just does what it name implies , we need to explicit implement to get correct colors on all entities as of source block using IdMapping api , I have written similar functionality some time back for draworder ,where drawing order is put incorrectly in destination database,this is just for an idea , we need to write on similar line.
I will update you if I can find a sample or will try to write one to get corrrect colors as of source block.
This change (using destDocument.Database.BlockTableID) made matters worse. I'm guessing you mean for me to insert after cloning? Remember, these are dynamic blocks. Are you saying I need to load the dynamic block definitions for the block references I intend to copy using clone, then manually create the references myself, transforming each block reference and setting the properties of each dynamic block reference?
Hi ,
Sorry If I'm not clear.I think I might have digressed the topic.
You are cloning dynamic block reference and I'm talking about cloning dynamic block defination.
Generally for dynamic blocks we prefer cloning block definations and programattically inserting and apply neccessary changes , I know this is pathetic idea,this we do because dynamic blocks have anonymous references and behavior of cloning dynamic block refernece is unexpected .
Nonetheless I'm pursuing your idea i.e. cloning references not defination and working on it .I will get back to you.
Thanks to you ,
"If I save the drawing containing the cloned blocks, close it, then open it, the color is correct." this led me to revisit your code and checked on without opening source drawing i.e just reading source drawing and cloning dynamic blockreferene to current drawing.
It worked out.
Code Sample:
[CommandMethod("WBCLONEToCurrent")] public void WBCLONEToCurrent() { DocumentCollection dm = Application.DocumentManager; Editor ed = dm.MdiActiveDocument.Editor; Database destDb = dm.MdiActiveDocument.Database; Database sourceDb = new Database(false, true); string sourceFileName; try { sourceFileName = "C:\\Users\\moogalm\\Documents\\CustomerData\\DynamicBlock.dwg"; sourceDb.ReadDwgFile(sourceFileName, System.IO.FileShare.Read, true, ""); ObjectIdCollection blockIds = new ObjectIdCollection(); Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = sourceDb.TransactionManager; using (Transaction myT = tm.StartTransaction()) { /*Handle of your Dynamic block reference*/ Handle handle = new Handle(0x215); ObjectId brefId = ObjectId.Null; sourceDb.TryGetObjectId(handle,out brefId); blockIds.Add(brefId); } IdMapping mapping = new IdMapping(); destDb.WblockCloneObjects(blockIds, destDb.CurrentSpaceId, mapping, DuplicateRecordCloning.Replace, false); } catch (Autodesk.AutoCAD.Runtime.Exception ex) { ed.WriteMessage("\nError during copy: " + ex.Message); } sourceDb.Dispose(); }
So to get it work done in your case when source drawing and destination drawing are opened in acad, we need to
1. Select entities in the current document and collect objetIds
2. Make the destination drawing as the current document
3. Call TransactionManager.QueueForGraphicsFlush() to queue for a graphic flush
4. Use Database.WblockCloneObjects()to copy the entities to this current document
Sample code :
/*When switching documents you need to be in session mode.*/ [CommandMethod("WBCLONE", CommandFlags.Session)] public void TestWBCLONE() { DocumentCollection docs = Application.DocumentManager; Document doc = docs.MdiActiveDocument; Database db = doc.Database; Editor Ed = doc.Editor; Document destDoc = null; foreach(Document tmpDoc in docs) { destDoc = tmpDoc; } try { PromptEntityResult entRes = Ed.GetEntity("Select Bref"); if (entRes.Status != PromptStatus.OK) { return; } ObjectIdCollection objIds = new ObjectIdCollection(); /*add bref id */ objIds.Add(entRes.ObjectId); /*This is the trick we need to make destination document as active one*/ Database destdb = destDoc.Database; docs.MdiActiveDocument = destDoc; using(DocumentLock docLock = destDoc.LockDocument()) { using(Transaction trans = destdb.TransactionManager.StartTransaction()) { /* Please note that you need to set the destination document as the current document to use TransactionManager.QueueForGraphicsFlush() * otherwise you will get an expectation. Also please lock/unlock the document appropriately.*/ trans.TransactionManager.QueueForGraphicsFlush(); IdMapping iMap = new IdMapping(); db.WblockCloneObjects(objIds, destdb.CurrentSpaceId, iMap, DuplicateRecordCloning.Ignore, false); trans.Commit(); } } } catch (System.Exception ex) { } }
IMHO ,
The wblock clone operation use object filing to clone an object. A new object is created, which will be the clone. Next, the original object is filed out to memory using dwgOut(). Finally, the data is filed into the new cloned object using dwgIn().
While processing the dwgOut() and dwgIn() operations the wblock clone engines identify all the references they have to process (clone/copy and translate) as the destination drawing is not yet active , filing part might be missing in hierarchy of cloning mechanism ,hence you're finding bref to be dissappeared or grey out in the destination drawing, and same explains why we 're able to see when we close and reopen the destination drawing.
Thanks,
Thank you Madhukar, this does seem to fix the issue. One thing I noticed is that because I was running a modal command I needed to set
Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.DocumentActivationEnabled = True before setting MdiActiveDocument to the destination document to which the entities are copied.
I need to do some additional testing, but this seems to be the solution to my issue. Thanks again.