Hello,
I'm inserting a block using ReadDwgFile(). The block has an extension dictionary which I want to preserve in the inserted block.
If I do it manually , for example, by dragging it from Design Center into Model Space, when I look at the block definition in the block table (using MgdDbg) the extension dictionary is there, which is what I want. When I try it in code the extension dictionary is not included.
Here's the code I am using.
using (Database sideDb = new Database(false, true)) { sideDb.ReadDwgFile(blkFile,FileOpenMode.OpenForReadAndReadShare, true, ""); newObjectId = targetDb.Insert(Path.GetFileNameWithoutExtension(blkFile), sideDb, false); }
What can I do to improve it to get the desired result?
Thanks
Craig
Solved! Go to Solution.
Solved by _gile. Go to Solution.
Hi,
when you say:
"I'm inserting a block using ReadDwgFile(). The block has an extension dictionary which I want to preserve in the inserted block."
Do you mean the Dwg file model space has an extension dictionary or the Dwg file contains a block definition which has an extension dictionary ?
The Database.Insert() method copies all the Model Space entities in the source database to a new BlockTableRecord in the target database BlockTable.
The file name was different to the block name so on insert I got two block table entries. One for filename and one for blockname. The entry for blockname had the extension dictionary, the entry for filename did not. The block reference in model space referred to the filename entry so no extension dictionary. (I'm listening for ObjectAppended and copy the extension dictionary from the block table entry to the block reference but the name was not expected so it did not get copied).
To overcome this manually using INSERT, I'd select my file, change the block name to blockname and opt to explode then I get a single block table entry, the block reference refers to blockname and my ObjectAppended handler copies the extension dictionary successfully.
So how to I replicate that in code?
I changed the insert line to use blockname instead of the filename but I get a self-reference error (which also occurs manually if you don't explode).
newObjectId = targetDb.Insert("blockname", sideDb, false);
I guess I need to tell it to explode it before calling insert somehow.
If I don't misundertand you try to import a block which exists in another file.
if so, I do not think Databse.Insert() is the good route. as I said Databse.Insert() creates a new BlockTableRecord in the Database BlockTable which contains all the entites in the model space of the source file, so you block in the source file is a block reference nested in the newly created BlockTablerecord.
If you want to import only the block from the external file, you may use WblockCloneObjects().
Here's a little sample:
private ObjectId ImportBlock(string fileName, string blockName) { if (!File.Exists(fileName)) throw new FileNotFoundException("File not found", fileName); Database targetDb = HostApplicationServices.WorkingDatabase; ObjectId owner = targetDb.BlockTableId; using (Database sourceDb = new Database()) { sourceDb.ReadDwgFile(fileName, System.IO.FileShare.Read, false, ""); using (Transaction tr = sourceDb.TransactionManager.StartOpenCloseTransaction()) { BlockTable bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead); if (!bt.Has(blockName)) return ObjectId.Null; ObjectId id = bt[blockName]; ObjectIdCollection ids = new ObjectIdCollection(); ids.Add(id); IdMapping idMap = new IdMapping(); sourceDb.WblockCloneObjects(ids, owner, idMap, DuplicateRecordCloning.Replace, false); return idMap[id].IsCloned ? idMap[id].Value : ObjectId.Null; } } }
Thank you for the sample. WblockCloneObjects is new to me and I have learnt something useful.
Only one issue I have now is if the source database is created using the default constructor I get eBrokenHandle error from WblockCloneObjects.
If I use the alternative constructor, new Database(false, true) , when I add a block reference using the new block it is drawn 25.4 times greater in size. I've checked the units in both the block's drawing and the target drawing; both set to millimeters. If I change both to unitless and set insertion default unit to millimeters I get the same result. When manually using INSERT, scale is left at 1,1,1, it is drawn at the correct size.
I tried setting source database Insunits to 0 but that made no difference.
There may be more thatn a single issue here.
Yes, indeed, on the block reference. I did make the link between 1 inch = 25.4 mm.
It must be me expecting it to be smaller when imported but the scale factor is not applied and is drawn correctly at 1:1.
I'll look into how to get the scaling back to 1 in the block drawing and see if that cures it.
Gilles and Mikko
Thank you both for making me aware of WblockCloneObjects.
I'll mark Gilles post as the answer for the follow through.
The scale issue was something else besides.
Cheers
Craig