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;
}
}