CAD
Your add-in places the title block in every layout at the click of a button. The block looks fine – but drawing number, date and author are missing. Or the parts list counts fewer doors than the plan shows. Both have a simple cause.
Stamp and imprint
A block definition is like a company stamp: it describes once what the block consists of. Each block reference is an imprint that only says where the block is, how it is rotated and how large it is. Unlike in the office, recutting the stamp changes all imprints in AutoCAD, because the reference only points to the definition. Attributes work the same way:
| What | Definition (once) | Reference (any number) |
|---|---|---|
| Block | BlockTableRecord in the BlockTable |
BlockReference |
| Attribute | AttributeDefinition in the block definition |
AttributeReference on the block reference |
Note: BlockReference.BlockTableRecord is an ObjectId, not an object.
Creating a block definition
A definition is a BlockTableRecord like model space, except that it is not drawn itself. Three rules save trouble:
- Order: First the definition goes into the
BlockTablewithAddand into the transaction withAddNewlyCreatedDBObject, then the entities follow. The other way round, you getErrorStatus.NotInDatabase. - Layer 0: Entities without a layer end up on the current layer, even inside a block. Set
LayerId = db.LayerZeroso the block follows the layer of its reference. With the colour ByBlock (ColorIndex = 0), an entity follows the colour of the reference. - Base point: Draw the entities around the origin so that
Originstays at (0,0,0), as with_BLOCK.
Creating attributes yourself when inserting
This is the most common mistake. With _INSERT, AutoCAD creates an attribute on the reference for every attribute definition. Inserting a BlockReference in code gives you only the reference – you create the attributes yourself:
// Insert a block reference and create the attributes yourself – as _INSERT does
public static ObjectId InsertWithAttributes(Transaction tr, BlockTableRecord owner,
ObjectId blockId, Point3d position, IDictionary<string, string> values)
{
var reference = new BlockReference(position, blockId);
var result = owner.AppendEntity(reference);
tr.AddNewlyCreatedDBObject(reference, true);
var definition = (BlockTableRecord)tr.GetObject(blockId, OpenMode.ForRead);
foreach (ObjectId entityId in definition)
{
// Constant attributes stay in the definition; the reference gets none
if (tr.GetObject(entityId, OpenMode.ForRead) is AttributeDefinition attDef
&& !attDef.Constant)
{
var attribute = new AttributeReference();
// Copies tag, default, style and position – transformed into the drawing
attribute.SetAttributeFromBlock(attDef, reference.BlockTransform);
if (values.TryGetValue(attDef.Tag, out var value))
{
attribute.TextString = value;
}
reference.AttributeCollection.AppendAttribute(attribute);
tr.AddNewlyCreatedDBObject(attribute, true);
}
}
return result;
}
SetAttributeFromBlock copies tag, default value, text height, style and layer from the definition. It needs the reference's BlockTransform for the position, since the definition uses block coordinates and the attribute world coordinates. With the wrong matrix, the attributes end up around the drawing origin. Create the dictionary with StringComparer.OrdinalIgnoreCase, as tags are often spelled inconsistently.
Reading and changing values
The AttributeCollection of a reference does not contain attributes but their ObjectIds. You open each attribute via the transaction, find it by its tag – ignoring case – and open it for writing with UpgradeOpen. For centred or right-aligned attributes, call AdjustAlignment after setting TextString so the position is recalculated. Two special cases:
- Constant attributes have no
AttributeReference; their value exists only in the definition. To list all attributes of a reference, look there too. - New attribute definitions do not reach existing references by themselves. Only synchronising updates them, with
_ATTSYNCor your own code. If you match by tag, a renamed tag loses its value.
Dynamic blocks: the name is misleading
When the user changes a property of a dynamic block, such as the door width, AutoCAD creates an anonymous block – a copy with the modified geometry – and points the reference to it. Its name is then *U12, for example. The name the user sees is provided by DynamicBlockTableRecord. And GetBlockReferenceIds only finds the references with default values – which is how the door list ends up too short. You find all references via the anonymous blocks:
// All references of a dynamic block – including the modified ones (*U…)
var definition = (BlockTableRecord)tr.GetObject(definitionId, OpenMode.ForRead);
var all = definition.GetBlockReferenceIds(true, false).Cast<ObjectId>().ToList();
foreach (ObjectId anonymousId in definition.GetAnonymousBlockIds())
{
var anonymous = (BlockTableRecord)tr.GetObject(anonymousId, OpenMode.ForRead);
all.AddRange(anonymous.GetBlockReferenceIds(true, false).Cast<ObjectId>());
}
The dynamic properties are not in the AttributeCollection but in the DynamicBlockReferencePropertyCollection. A value is set with exactly its existing type: Double, Int16 or String, angles in radians. A dynamic block cannot be created via .NET; the add-in fetches it from a library drawing with WblockCloneObjects.
Typical mistakes
- Inserting a reference in code and forgetting the attributes.
- Calling
SetAttributeFromBlockwithMatrix3d.Identityinstead of theBlockTransform. - Creating the definition's entities without a layer – they end up on the current layer.
- Counting blocks by name and overlooking the anonymous blocks of dynamic blocks.
- Changing an entity of the block definition and assuming only one reference is affected.
How we help
- Training: In the “AutoCAD .NET API with C#” training, you program blocks, attributes and dynamic blocks with AutoCAD 2027.
- Add-in check: We check your add-in for these pitfalls and for AutoCAD 2027 – as a fixed-price starter package.
- Development: Parts lists, title blocks, block libraries – get in touch.
- The book: Everything is covered in detail in Ebi F. Eilber’s book “AutoCAD .NET API”, expected in 2027.
Source: Ebi F. Eilber, AutoCAD .NET API (book, expected 2027), chapters “Blocks”, “Attributes” and “Dynamic blocks”
