Announcements
Notice: Upload of PDF documents is currently unavailable across the Community due to an ongoing issue.

Add a new attribute to a block, using doc.Database instead of doc.Editor if possible

Add a new attribute to a block, using doc.Database instead of doc.Editor if possible

bsaidiDG51
Enthusiast Enthusiast
646 Views
2 Replies
Message 1 of 3

Add a new attribute to a block, using doc.Database instead of doc.Editor if possible

bsaidiDG51
Enthusiast
Enthusiast

My main goal is to add an attribute to all blocks named 8x11General found in a drawing. I found a way to do it using doc.Editor to add the new attribute definition, but this way of doing is not optimal for me, since eventually I will need to run this code on all drawing found within a folder and it would oblige me to open each one of them.

So I'm wondering if there is a way to add an attribute to a block definition using only the doc.Database or anything else that would not require the use of the doc.Editor (which requires the opening of the dwg file).

Thank you in advance for your time.

 

My current code that adds an attribute using the doc.Editor:

private readonly List<string> _blocksToProcess = new List<string> { "8x11General"};

[CommandMethod("AddAttribute")]
public void AddAttributeToBlocks()
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Database db = doc.Database;
    Editor ed = doc.Editor;

    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        var filter = new SelectionFilter(new[]
        {
            new TypedValue((int)DxfCode.Start, "INSERT")
        });

        PromptSelectionResult psr = ed.SelectAll(filter);

        if (psr.Status != PromptStatus.OK)
            return;

        foreach (SelectedObject so in psr.Value)
        {
            var br = (BlockReference)tr.GetObject(so.ObjectId, OpenMode.ForWrite);

            if (_blocksToProcess.Contains(br.Name))
            {
                AddAttributeToBlock(br, db, tr);
            }
            else
            {
                // Add code here to check for nested blocks and add attributes
                ProcessNestedBlocks(br, db, tr);
            }
        }

        tr.Commit();
    }
}

private void AddAttributeToBlock(BlockReference br, Database db, Transaction tr)
{
    br.Highlight();

    // Get the block's insertion point
    Point3d blockInsertionPoint = br.Position;

    // Calculate the top-right corner of the block
    Point3d p = blockInsertionPoint + new Vector3d((br.GeometricExtents.MaxPoint.X + br.GeometricExtents.MinPoint.X) / 2,
        (br.GeometricExtents.MaxPoint.Y + br.GeometricExtents.MinPoint.Y) / 2,
        0);

    var attRef = new AttributeReference(p, "SHMURRR", "BOBBY", db.Textstyle)
    {
        Invisible = true, //Make the attribute invisible
        LockPositionInBlock = false,
    };
    br.AttributeCollection.AppendAttribute(attRef);
    tr.AddNewlyCreatedDBObject(attRef, true);
    db.TransactionManager.QueueForGraphicsFlush();
    br.Unhighlight();
}

private void ProcessNestedBlocks(BlockReference br, Database db, Transaction tr)
{
    // Retrieve the block table record of the current block
    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead);

    foreach (ObjectId objectId in btr)
    {
        if (objectId.ObjectClass == RXClass.GetClass(typeof(BlockReference)))
        {
            var nestedBlock = (BlockReference)tr.GetObject(objectId, OpenMode.ForWrite);

            if (_blocksToProcess.Contains(nestedBlock.Name))
            {
                AddAttributeToBlock(nestedBlock, db, tr);
            }
            else
            {
                // Recursively check for nested blocks
                ProcessNestedBlocks(nestedBlock, db, tr);
            }
        }
    }
}

 

0 Likes
Accepted solutions (1)
647 Views
2 Replies
Replies (2)
Message 2 of 3

_gile
Consultant
Consultant
Accepted solution

Hi,

It looks like your adding an attribute reference to inserted block references without adding an attribute definition to the block definition. Doing so, all newly inserted blocks won't have this attribute and any attribute synchronization (ATTSYNC command) will erase the attribute references.

 

A better practice would be adding an attribute definition to the block definition and 'synchronize' all already inserted block references.

Here's a simple example you can start from:

        /// <summary>
        /// Adds an attribute definition to the block definition
        /// and synchronizes all inserted references.
        /// </summary>
        /// <param name="db">Database the block belongs to.</param>
        /// <param name="blockName">Name of the block.</param>
        /// <param name="position">Position of the attribute definition in the block definition.</param>
        /// <param name="value">Default value of the attribute.</param>
        /// <param name="tag">Tag of the attribute.</param>
        /// <param name="prompt">Prompt of the attribute.</param>
        public static void AddAttributeToBlock(
            Database db, string blockName, Point3d position, string value, string tag, string prompt)
        {
            using (var tr = db.TransactionManager.StartTransaction())
            {
                // Get the block definition
                var blockTable = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                if (!blockTable.Has(blockName))
                    return;
                var blockDefinition = (BlockTableRecord)tr.GetObject(blockTable[blockName], OpenMode.ForWrite);

                // Add an attribute definition to the block definition
                var attributeDefinition = new AttributeDefinition(position, value, tag, prompt, db.TextStyleTableId);
                blockDefinition.AppendEntity(attributeDefinition);
                tr.AddNewlyCreatedDBObject(attributeDefinition, true);

                // Get  all the inserted refrences to append the new attribute reference
                foreach (ObjectId id in blockDefinition.GetBlockReferenceIds(true, false))
                {
                    var blockReference = (BlockReference)tr.GetObject(id, OpenMode.ForWrite);
                    var attributeReference = new AttributeReference();
                    attributeReference.SetAttributeFromBlock(attributeDefinition, blockReference.BlockTransform);
                    blockReference.AttributeCollection.AppendAttribute(attributeReference);
                    tr.AddNewlyCreatedDBObject(attributeReference, true);
                }
                tr.Commit();
            }
        }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 3

bsaidiDG51
Enthusiast
Enthusiast
Thank you boss.
0 Likes