I've recently been porting a batch processing application to work directly on the database instead of the Document so all processing can be done in the background.
As a part of this port I rewrote my generic block insert snippet to cope with just a database instead of a document and added 'forwarding methods' to maintain backwards compatibility:
public static ObjectId insertBlock(Document acDoc, Transaction acTrans, string blocknaam, DefaultBlock defBlock = DefaultBlock.None) { return InsertBlock(acDoc, acTrans, blocknaam, false, defBlock); } public static ObjectId InsertBlock(Document acDoc, Transaction acTrans, string blocknaam, bool overrideExisting = false, DefaultBlock defBlock = DefaultBlock.None) { return InsertBlock(acDoc.Database, acTrans, blocknaam, overrideExisting, defBlock); } public static ObjectId InsertBlock(Database db, Transaction acTrans, string blockName, bool overrideExisting = false, DefaultBlock defBlock = DefaultBlock.None) { ObjectId blkid = ObjectId.Null; BlockTable blktbl = acTrans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable; if ((blockName != BlockTableRecord.ModelSpace) && (!blktbl.Has(blockName) || overrideExisting)) { string fileName = null; //Insert the block try { fileName = HostApplicationServices.Current.FindFile(blockName + ".dwg", db, FindFileHint.Default); } catch { //Block hasn't been found. For now just return ObjectId.Null //return CreateBlock(db, acTrans, defBlock); return ObjectId.Null; } if (!string.IsNullOrEmpty(fileName)) { Database dbNew = new Database(false, false); dbNew.ReadDwgFile(fileName, System.IO.FileShare.Read, false, null); blkid = db.Insert(blockName, db, false); dbNew.Dispose(); } } else { blkid = blktbl[blockName]; } return blkid; } } internal enum DefaultBlock { None = -1, Point = 0, Cross = 1, Circle = 2, }
The old main block was as following (apologies for the few dutch terms)
public static ObjectId insertBlock(Document acDoc, Transaction acTrans, string blocknaam, DefaultBlock defBlock = DefaultBlock.None) { ObjectId blkid = ObjectId.Null; BlockTable blktbl = acTrans.GetObject(acDoc.Database.BlockTableId, OpenMode.ForRead) as BlockTable; if ((blocknaam != BlockTableRecord.ModelSpace) && (!blktbl.Has(blocknaam))) { string fileName = null; //We moeten inserten try { fileName = HostApplicationServices.Current.FindFile(blocknaam + ".dwg", acDoc.Database, FindFileHint.Default); #if DEBUG acDoc.Editor.WriteMessage("\nBlock {0} inserted from {1}", blocknaam, fileName); #endif } catch { //Block niet gevonden. Afhankelijk van instellingen moeten we 'm gaan maken return CreateBlock(acDoc, acTrans, defBlock, blocknaam); } if (!string.IsNullOrEmpty(fileName)) { Database db = new Database(false, false); db.ReadDwgFile(fileName, System.IO.FileShare.Read, false, null); blkid = acDoc.Database.Insert(blocknaam, db, false); db.Dispose(); } } else { blkid = blktbl[blocknaam]; } return blkid; }
The old code worked, and stills works, just fine. The new code however returns a valid ObjectId for the BlockTableRecord, but when a block with this blkid is inserted, the block is empty. When edited with the block editor, the BlockTableRecord seems to be empty too.
The bug seems to be in the following code:
public static ObjectId InsertBlock(Database db, Transaction acTrans, string blockName, bool overrideExisting = false, DefaultBlock defBlock = DefaultBlock.None) { if (!string.IsNullOrEmpty(fileName)) { Database dbNew = new Database(false, false); dbNew.ReadDwgFile(fileName, System.IO.FileShare.Read, false, null); blkid = db.Insert(blockName, db, false); dbNew.Dispose(); } }
Any ideas on how to solve this?
Hi,
This works for me:
public ObjectId ImportBlock(Database targetDb, string fileName, string blockName, bool overrideExisting) { if (targetDb == null) throw new ArgumentNullException("targetDb"); if (string.IsNullOrEmpty(fileName)) throw new ArgumentNullException("fileName"); if (!File.Exists(fileName)) throw new FileNotFoundException("File not found", fileName); using (Transaction tr = targetDb.TransactionManager.StartOpenCloseTransaction()) { BlockTable bt = (BlockTable)tr.GetObject(targetDb.BlockTableId, OpenMode.ForRead); if (bt.Has(blockName) && !overrideExisting) return bt[blockName]; } using (Database sourceDb = new Database()) { sourceDb.ReadDwgFile(fileName, FileShare.Read, false, null); return targetDb.Insert(blockName, sourceDb, true); } }
Can't find what you're looking for? Ask the community or share your knowledge.