I am trying to insert a block that will not initially exist in the current drawing, but once inserted may be inserted multiple times. I have code that determines the name of the block and the insertion point I need to insert from a directory and returns the block name to the routine that will insert the block. It appears to work, except that the block never shows up. I don't know what I am missing and could some suggestions.
class BlockInsert { public void InsertBlock(AcGeo.Point3d InsPt, string BlkName) { AppSvc.Document cDoc = App.DocumentManager.MdiActiveDocument; DBSvc.Database cDB = cDoc.Database; AcEdIn.Editor cEd = cDoc.Editor; using (DBSvc.Transaction Trans1 = cDB.TransactionManager.StartTransaction()) { DBSvc.BlockTable blkTable; blkTable = Trans1.GetObject(cDB.BlockTableId, DBSvc.OpenMode.ForWrite) as DBSvc.BlockTable; DBSvc.BlockTableRecord blkTableRec = new DBSvc.BlockTableRecord(); if (!blkTable.Has(BlkName)) { blkTable.Add(blkTableRec); Trans1.AddNewlyCreatedDBObject(blkTableRec, true); blkTableRec.Name = BlkName; } // Insert support block at insertion point InsPt DBSvc.BlockTableRecord space = (DBSvc.BlockTableRecord)Trans1.GetObject(cDB.CurrentSpaceId, DBSvc.OpenMode.ForWrite); DBSvc.BlockReference rfml = new DBSvc.BlockReference(InsPt, blkTableRec.ObjectId); space.AppendEntity(rfml); Trans1.AddNewlyCreatedDBObject(rfml, true); Trans1.Commit(); } MessageBox.Show("\nThe block name is: " + BlkName, "BlockName", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); } }
Solved! Go to Solution.
Solved by _gile. Go to Solution.
Hi,
The code you show should work, but it creates an empty block, this is why you can't see it.
You can use this overload of the Database.Insert() method to add a new BlockTableRecord in the BlockTable containing the entities of the source database model space.
Thanks for the reply and help Giles. Unfortunately, I am not a good enough programmer to understand how to implement your suggestion in my program. I am really just a dabbler being tasked with improving over our current crop of LISP programs.
Try this:
public void InsertBlock(Point3d insPt, string blockName) { var doc = Application.DocumentManager.MdiActiveDocument; var db = doc.Database; var ed = doc.Editor; using (var tr = db.TransactionManager.StartTransaction()) { // check if the block table already has the 'blockName'" block var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); if (!bt.Has(blockName)) { try { // search for a dwg file named 'blockName' in AutoCAD search paths var filename = HostApplicationServices.Current.FindFile(blockName + ".dwg", db, FindFileHint.Default); // add the dwg model space as 'blockName' block definition in the current database block table using (var sourceDb = new Database(false, true)) { sourceDb.ReadDwgFile(filename, FileOpenMode.OpenForReadAndAllShare, true, ""); db.Insert(blockName, sourceDb, true); } } catch { ed.WriteMessage($"\nBlock '{blockName}' not found."); return; } } // create a new block reference using (var br = new BlockReference(insPt, bt[blockName])) { var space = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite); space.AppendEntity(br); tr.AddNewlyCreatedDBObject(br, true); } tr.Commit(); } }
Thank you Gilles, that did the trick. I am going to dig into your code to make sure I understand what you did. Seeing working code and trying to adapt it to my needs seems to be the best way for me to learn how to write better code.
Thanks again!!
Giles,
The code you sent me for inserting blocks has been working flawlessly and I am very grateful for your help.
Now, though, I need to modify your code so that if the block already exists in the block table, it will deepclone the existing block instead of inserting a new one or copying the existing one. I figured by extending your
"if (!blkTable.Has(BlkName))" statement with an else statement I would be able to excute the deepclone command instead of inserting the block.
So far, I replaced your original code:
create a new block reference
using (var br = new DBSvc.BlockReference(InsPt, blkTable[BlkName])){
var space = (DBSvc.BlockTableRecord)Trans1.GetObject(cDB.CurrentSpaceId, DBSvc.OpenMode.ForWrite);
space.AppendEntity(br);
Trans1.AddNewlyCreatedDBObject(br, true);}
with this:
else
{
DBSvc.IdMapping dupMap = new DBSvc.IdMapping();
DBSvc.BlockTableRecord dupBTR = blkTableRec.DeepClone(blkTable, dupMap, true);
dupBTR.Name = "duplicate";
blkTable.Add(dupBTR);
Trans1.AddNewlyCreatedDBObject(dupBTR, true);
}
Unfortunately it does not work. Any help is appreciated.
Hi,
It looks like you're confusing BlockTableRecord (i.e. a block definition which belongs to the BlockTable) and BlockReference (i.e. one or more inserted references in some space or other BlockTableRecord).
You can read this topic and the related ones.
Can't find what you're looking for? Ask the community or share your knowledge.