Another day, another problem.
public void InsertBlock(ObjectId Blockid, int ISPOSP)
{
//this assumes that because the viewport block has been copied to the drawing, the other necessary blocks will have been too.
// Blockid = the id of the block we inserted using the jig.
// BlockPos = the position of the above block.
// Blockscale = the scale of the above block.
// BlockAngle = the rotation angle of the above block.
Database db = HostApplicationServices.WorkingDatabase;
Document dwg = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
Editor ed = dwg.Editor;
BlockTable bt = null;
BlockTableRecord btr = null;
Point3d BlockPos = new Point3d(0, 0, 0);
Scale3d BlockScale = new Scale3d(1);
Double BlockAngle = 0;
BlockReference blkref = null;
BlockReference frameref = null;
PromptStringOptions prso = null;
PromptKeywordOptions prko = null;
PromptResult res = null;
// this next section adds the ISPviewport-frame block on top of the already-inserted ISPViewport block.
#region InsertISPViewportframe
if (ISPOSP == 0) // Viewport = ISP
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead, false) as BlockTable;
foreach (ObjectId btrid in bt)
{
if (btrid == Blockid)
// we found the correct block?
{
btr = tr.GetObject(btrid, OpenMode.ForRead, false) as BlockTableRecord;
// normally we could filter out layouts, xrefs etc. but since we already know the objectid of the block
// we're looking for we don't need to bother.
if (btr.IsLayout || btr.IsFromExternalReference || !btr.IsDynamicBlock || btr.IsFromOverlayReference || !btr.HasAttributeDefinitions)
{
continue;
}
ObjectIdCollection blkrefIds = btr.GetBlockReferenceIds(true, false);
if (blkrefIds == null || blkrefIds.Count == 0)
break;
//int counter = 0;
foreach (ObjectId blkrefid in blkrefIds)
{
blkref = tr.GetObject(blkrefid, OpenMode.ForWrite, false) as BlockReference;
BlockPos = blkref.Position;
BlockScale = blkref.ScaleFactors;
BlockAngle = blkref.Rotation;
// Code should skip the next part if the block has already been inserted and has a blockref.AttributeCollection.Count greater than zero.
if (blkref.AttributeCollection.Count == 0)
{
//Start newly placed attribute start code.
//Maybe need to filter so this only runs once.
BlockTable newbt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
ObjectId bdid = bt[blkref.Name];
BlockTableRecord newbtr = (BlockTableRecord)tr.GetObject(bdid, OpenMode.ForRead);
//Add the attributes to the block definition otherwise we won't be able to edit them in blkref?
if (newbtr.HasAttributeDefinitions)
{
foreach (ObjectId attid in newbtr)
{
AttributeDefinition attdef = tr.GetObject(attid, OpenMode.ForRead) as AttributeDefinition;
if (attdef != null)
{
AttributeReference ar = new AttributeReference();
ar.SetAttributeFromBlock(attdef, blkref.BlockTransform);
blkref.AttributeCollection.AppendAttribute(ar);
tr.AddNewlyCreatedDBObject(ar, true);
}
}
}
OldBlockPos = BlockPos;
}
blkref = tr.GetObject(blkrefid, OpenMode.ForRead, false) as BlockReference;
AttributeCollection attrefids = blkref.AttributeCollection;
foreach (ObjectId attrefid in attrefids)
{
AttributeReference attref = tr.GetObject(attrefid, OpenMode.ForWrite, false) as AttributeReference;
switch (attref.Tag)
{
case "VIEWNO_NONVIS":
prso = new PromptStringOptions("\nWhat view number is this?");
res = ed.GetString(prso);
if (res.Status == PromptStatus.OK)
{
attref.UpgradeOpen();
string update = res.StringResult;
attref.TextString = update;
attref.DowngradeOpen();
}
break;
case "FULLORPARTIAL":
prko = new PromptKeywordOptions("\nWhat floor does this view depict?");
prko.Keywords.Add("FULL");
prko.Keywords.Add("PARTIAL");
prko.Keywords.Add("DC");
prko.Keywords.Add("ELEVATION");
res = ed.GetKeywords(prko);
if (res.Status == PromptStatus.OK)
{
attref.UpgradeOpen();
string update = res.StringResult;
attref.TextString = update;
attref.DowngradeOpen();
if (res.StringResult == "PARTIAL")
{
btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
frameref = new BlockReference(BlockPos, bt["ISPVIEWPORT-FRAME"]);
frameref.ScaleFactors = BlockScale;
frameref.Rotation = BlockAngle;
btr.AppendEntity(frameref);
tr.AddNewlyCreatedDBObject(frameref, true);
}
}
break;
case "FLOOR":
prko = new PromptKeywordOptions("\nWhat floor does this view depict?");
prko.Keywords.Add("GROUND");
prko.Keywords.Add("FIRST");
prko.Keywords.Add("SECOND");
prko.Keywords.Add("THIRD");
prko.Keywords.Add("FOURTH");
prko.Keywords.Add("OTHER");
PromptResult getWhichFloorResult = ed.GetKeywords(prko);
if (getWhichFloorResult.StringResult == "OTHER")
{
res = ed.GetString("\nEnter another floor that's not listed.");
}
else
{
res = getWhichFloorResult;
}
if (res.Status == PromptStatus.OK)
{
attref.UpgradeOpen();
string update = res.StringResult;
attref.TextString = update;
attref.DowngradeOpen();
}
break;
}
}
}
}
}
tr.Commit();
}
#endregion //InsertISPViewportframe
}
}
The above code allows me to insert the block(s) I require but for some reason it seems to go back into the previous inserted blocks and add the attributes again.
The line that isn't working as expected is: -
if (blkref.AttributeCollection.Count == 0)
After the first block is inserted, and the attributes filled out, it shouldn't then have an AttributeCollection count of 0, but for reasons that escape me it does. I can't for the life of me work out another check I could do to prevent the attributes being added again (short of moving the attribute editing part of this code into its' own function).
Any ideas?
(Incidentally, if I was doing this exact same thing in VBA I'd insert the block, then sendcommand "ATTSYNC" to sychronize the attributereferences with the blockdefinition.)