1

I'm programmatically inserting 1,000+ dynamic blocks of the same type into AutoCAD using C#. Each block has multiple attributes and dynamic properties (e.g., scale, rotation, custom values).

The insertion routine works quite efficiently — about 15 blocks per second — as long as I don't use ATTSYNC.

However, running ATTSYNC (via command call) after the insertions causes a massive slowdown:

It adds 7 to 10 minutes to the total execution time. Sometimes it even causes AutoCAD to freeze or become unresponsive.

I understand that ATTSYNC is required to refresh the attributes so that they appear correctly, but this is becoming a serious bottleneck.

Is there any way to avoid using ATTSYNC when inserting dynamic blocks programmatically? Or is there a faster or safer method to force the attributes to show up immediately after block insertion?

Any tips or workarounds would be greatly appreciated.

public object[,] DibujarDB(string blkName, string[] propsName, object[,] propsValue, ActualizadorFormulario actualizador)
{
    var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
    var db = doc.Database;
    var ed = doc.Editor;

    using (var trans = db.TransactionManager.StartTransaction())
    {
        try
        {
            var bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
            if (!bt.Has(blkName))
            {
                ed.WriteMessage($"\nEl bloque '{blkName}' no existe.");
                return null;
            }

            var btr = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
            var lt = (LayerTable)trans.GetObject(db.LayerTableId, OpenMode.ForRead);

            int rows = propsValue.GetLength(0);
            int insertedCount = 0;
            string miEstado;
            var blkId = bt[blkName];
            var propIndices = propsName
                .Select((name, index) => new { name, index })
                .ToDictionary(p => p.name, p => p.index);

            int idxDibujar = propIndices["DIBUJAR"];
            int idxHandler = propIndices["HANDLER"];
            int idxCX = propIndices["CX"];
            int idxCY = propIndices["CY"];
            int idxCZ = propIndices["CZ"];
            int idxANG = propIndices["ANG"];
            int idxCAPA = propIndices["CAPA"];
            int idxESCX = propIndices["ESCX"];
            int idxESCY = propIndices["ESCY"];
            int idxESCZ = propIndices["ESCZ"];

            RevisionCapas(trans, lt, idxCAPA, propsValue);

            string[] dynPropNames = propsName.Skip(11).ToArray();

            for (int i = 0; i < rows; i++)
            {
                var dibujarVal = propsValue[i, idxDibujar]?.ToString();
                if (!string.Equals(dibujarVal, "SI", StringComparison.OrdinalIgnoreCase) &&
                    !string.Equals(dibujarVal, "TRUE", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                if (!double.TryParse(propsValue[i, idxCX]?.ToString(), out double cx) ||
                    !double.TryParse(propsValue[i, idxCY]?.ToString(), out double cy) ||
                    !double.TryParse(propsValue[i, idxCZ]?.ToString(), out double cz) ||
                    !double.TryParse(propsValue[i, idxANG]?.ToString(), out double ang) ||
                    !double.TryParse(propsValue[i, idxESCX]?.ToString(), out double escX) ||
                    !double.TryParse(propsValue[i, idxESCY]?.ToString(), out double escY) ||
                    !double.TryParse(propsValue[i, idxESCZ]?.ToString(), out double escZ))
                {
                    ed.WriteMessage($"\nError: Datos inválidos en la fila {i}");
                    continue;
                }

                string capa = propsValue[i, idxCAPA]?.ToString() ?? "0";

                var blkRef = new BlockReference(new Point3d(cx, cy, cz), blkId)
                {
                    Rotation = ang,
                    ScaleFactors = new Scale3d(escX, escY, escZ),
                    Layer = capa
                };

                btr.AppendEntity(blkRef);
                trans.AddNewlyCreatedDBObject(blkRef, true);
                propsValue[i, idxHandler] = blkRef.Handle.ToString();

                foreach (var propName in dynPropNames)
                {
                    DynamicBlockReferenceProperty prop = blkRef.DynamicBlockReferencePropertyCollection
                        .Cast<DynamicBlockReferenceProperty>()
                        .FirstOrDefault(p => p.PropertyName == propName);

                    if (prop != null)
                    {
                        var valStr = propsValue[i, propIndices[propName]]?.ToString();
                        if (valStr != null && prop.Value.ToString() != valStr)
                        {
                            try
                            {
                                prop.Value = Convert.ChangeType(valStr, prop.Value.GetType());
                            }
                            catch
                            {
                                ed.WriteMessage($"\nAdvertencia: No se pudo asignar '{valStr}' a la propiedad '{propName}' en fila {i}");
                            }
                        }
                    }
                }

                insertedCount++;
                actualizador.ActualizarProgresoProceso();
            }

            trans.Commit();

            miEstado = "Toca sincronizar el bloque y eso demora, pa'.";
            actualizador.ActualizarEstado(miEstado);
            ed.Command("._ATTSYNC", "_N", blkName);
            miEstado = "Mucho atributo, llave. Mucho hijueputa atributo.";
            actualizador.ActualizarEstado(miEstado);
            return propsValue;
        }
        catch (System.Exception ex)
        {
            ed.WriteMessage($"\nError: {ex.Message}");
        }

        return null;
    }
}

1 Answer 1

1

You should explicitly add the attribute references to each inserted block reference instead of calling ATTSYNC.

Get the attribute definitions from the block definition:

// [...]
var blkId = bt[blkName];
var propIndices = propsName
    .Select((name, index) => new { name, index })
    .ToDictionary(p => p.name, p => p.index);

var blkDef = (BlockTableRecord)trans.GetObject(blkId, OpenMode.ForRead);
var attDefs = blkDef
    .Cast<ObjectId>()
    .Where(id => id.ObjectClass.Name == "AcDbAttributeDefinition")
    .Select(id => (AttributeDefinition)trans.GetObject(id, OpenMode.ForRead))
    .Where(attDef => !attDef.Constant)
    .ToArray();
// [...]

Add the attribute references for each newly created block reference:

// [...]
btr.AppendEntity(blkRef);
trans.AddNewlyCreatedDBObject(blkRef, true);
propsValue[i, idxHandler] = blkRef.Handle.ToString();

foreach (var attDef in attDefs)
{
    var attRef = new AttributeReference();
    attRef.SetAttributeFromBlock(attDef, blkRef.BlockTransform);
    blkRef.AttributeCollection.AppendAttribute(attRef);
    trans.AddNewlyCreatedDBObject(attRef, true);
}
// [...]
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot for your answer. It worked perfectly. Now i'm having issues with the attribute value because I need to use some fields from the blockplaceholder but I will ask another question for that! Thanks a lot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.