AutoCAD Blocks and Attributes
Use this skill when creating block definitions, inserting block references, working with attributes, or reading dynamic block properties.
Block Definition (BlockTableRecord)
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(
db.BlockTableId, OpenMode.ForWrite);
// Create a new block definition
BlockTableRecord blockDef = new BlockTableRecord();
blockDef.Name = "MyBlock";
blockDef.Origin = new Point3d(0, 0, 0);
blockDef.Comments = "A custom block";
blockDef.Units = UnitsValue.Millimeters;
blockDef.Explodable = true;
ObjectId blockId = bt.Add(blockDef);
tr.AddNewlyCreatedDBObject(blockDef, true);
// Add entities to the block definition
Line line = new Line(new Point3d(0, 0, 0), new Point3d(10, 10, 0));
blockDef.AppendEntity(line);
tr.AddNewlyCreatedDBObject(line, true);
Circle circle = new Circle(new Point3d(5, 5, 0), Vector3d.ZAxis, 3.0);
blockDef.AppendEntity(circle);
tr.AddNewlyCreatedDBObject(circle, true);
tr.Commit();
}
Iterating Block Contents
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(
blockId, OpenMode.ForRead);
foreach (ObjectId entId in btr)
{
Entity ent = (Entity)tr.GetObject(entId, OpenMode.ForRead);
ed.WriteMessage("Entity: {0}\n", ent.GetType().Name);
}
Block Reference (Inserting a Block)
BlockTableRecord space = (BlockTableRecord)tr.GetObject(
db.CurrentSpaceId, OpenMode.ForWrite);
BlockReference blockRef = new BlockReference(
new Point3d(100, 200, 0), // insertion point
blockDefId); // BlockTableRecord ObjectId
blockRef.Rotation = 0.0; // rotation in radians
blockRef.ScaleFactors = new Scale3d(1.0); // uniform scale
blockRef.Normal = Vector3d.ZAxis;
space.AppendEntity(blockRef);
tr.AddNewlyCreatedDBObject(blockRef, true);
Attributes
Attribute Definition (in block definition)
AttributeDefinition attDef = new AttributeDefinition(
new Point3d(5, -5, 0), // position
"Default Value", // default value
"TAG_NAME", // tag
"Enter value:", // prompt
textStyleId); // text style
attDef.Height = 2.5;
attDef.Invisible = false;
attDef.Constant = false;
attDef.Verifiable = false;
attDef.Preset = false;
attDef.LockPositionInBlock = false;
// MText attribute definition
attDef.IsMTextAttributeDefinition = true;
MText mtext = new MText();
mtext.Contents = "Multi\\Pline";
attDef.MTextAttributeDefinition = mtext;
attDef.UpdateMTextAttributeDefinition();
blockDef.AppendEntity(attDef);
tr.AddNewlyCreatedDBObject(attDef, true);
Attribute Reference (on block insert)
// After inserting a BlockReference, add attribute references
BlockTableRecord blockDef = (BlockTableRecord)tr.GetObject(
blockRef.BlockTableRecord, OpenMode.ForRead);
foreach (ObjectId entId in blockDef)
{
AttributeDefinition attDef = tr.GetObject(entId, OpenMode.ForRead)
as AttributeDefinition;
if (attDef == null || attDef.Constant) continue;
AttributeReference attRef = new AttributeReference();
attRef.SetAttributeFromBlock(attDef, blockRef.BlockTransform);
// Position does NOT auto-update from SetAttributeFromBlock — must set manually
attRef.Position = attDef.Position.TransformBy(blockRef.BlockTransform);
attRef.TextString = attDef.TextString; // or set custom value
blockRef.AttributeCollection.AppendAttribute(attRef);
tr.AddNewlyCreatedDBObject(attRef, true);
}
Reading Attribute Values
foreach (ObjectId attId in blockRef.AttributeCollection)
{
AttributeReference attRef = (AttributeReference)tr.GetObject(
attId, OpenMode.ForRead);
ed.WriteMessage("Tag: {0}, Value: {1}\n",
attRef.Tag, attRef.TextString);
}
Writing Attribute Values
foreach (ObjectId attId in blockRef.AttributeCollection)
{
AttributeReference attRef = (AttributeReference)tr.GetObject(
attId, OpenMode.ForWrite);
if (attRef.Tag == "TITLE")
attRef.TextString = "New Title";
}
Dynamic Block Properties
if (blockRef.IsDynamicBlock)
{
// Get the original (non-anonymous) block name
BlockTableRecord dynBtr = (BlockTableRecord)tr.GetObject(
blockRef.DynamicBlockTableRecord, OpenMode.ForRead);
string originalName = dynBtr.Name;
// Read and write dynamic properties
DynamicBlockReferencePropertyCollection props =
blockRef.DynamicBlockReferencePropertyCollection;
foreach (DynamicBlockReferenceProperty prop in props)
{
string name = prop.PropertyName;
object val = prop.Value;
bool readOnly = prop.ReadOnly;
bool show = prop.Show;
bool visible = prop.VisibleInCurrentVisibilityState;
short typeCode = prop.PropertyTypeCode;
DynamicBlockReferencePropertyUnitsType units = prop.UnitsType;
string desc = prop.Description;
// Get allowed values (for constrained properties)
object[] allowedValues = prop.GetAllowedValues();
ed.WriteMessage(" {0} = {1} (type: {2})\n", name, val, typeCode);
}
// Set a dynamic property value
foreach (DynamicBlockReferenceProperty prop in props)
{
if (prop.PropertyName == "Distance" && !prop.ReadOnly)
{
prop.Value = 500.0; // set new value
break;
}
}
}
Gotchas
BlockReference.Namereturns the anonymous block name for dynamic blocks (e.g., "*U42"); useDynamicBlockTableRecordto get the original name- Attribute references must be added AFTER the block reference is added to the space - call
AppendEntityandAddNewlyCreatedDBObjecton the block ref first SetAttributeFromBlock(attDef, blockRef.BlockTransform)is essential - it positions the attribute correctly based on the block's transform; without it, attributes appear at the wrong locationConstantattributes have fixed values and are NOT included inAttributeCollectionon the block reference- When iterating block definition entities to find AttributeDefinitions, not every entity is an AttDef - always check for null after cast
BlockTableRecord.ModelSpaceandPaperSpaceare string constants for the standard space names, not references to the blocks themselvesExplodeToOwnerSpace()adds exploded entities to the parent and erases the block reference; cannot be undone without transaction rollbackConvertToStaticBlock()on a dynamic block reference permanently freezes the current state - the reference can no longer access dynamic properties- Dynamic block property
Valueis typed asobject- cast to the appropriate type (double, string, Point3d, etc.) based onPropertyTypeCode GetBlockReferenceIds(true, false)returns only direct references; use(false, true)to include nested references and force validity checks
Related Skills
acad-layers— block references and entities within blocks inherit layer propertiesacad-editor-input— selecting block references with GetEntity or selection filters (DxfCode.Start"INSERT")acad-mleaders— block references as MLeader block content