Adding attributes to block references in a side database

Adding attributes to block references in a side database

Anonymous
Not applicable
1,237 Views
5 Replies
Message 1 of 6

Adding attributes to block references in a side database

Anonymous
Not applicable

I'm trying to add a new attribute to all the block references of several drawings. Ideally this would be done as a side database to make it as clean and efficient as possible, however I keep hitting an ewrongdatabase error.

Could anyone please help.

Below is the code for a minimum working example, the code works find for the active document (uncomment all lines ending //comment out #2 and comment  out lines ending //comment out #1 to check) but fails on the btr.AppendEntity(attr); line when trying to run as a side database.

Many thanks

[CommandMethod("MWE", CommandFlags.Session)]
        public static void MWE()
        {
            var filenames = new List<string>();
            filenames.Add("C:\\temp\\test.dwg");

            var attributes = new List<string>();
            attributes.Add("Att1");

            var acDbase = new Database(false, true);

            foreach (var file in filenames) //comment out #1
            //foreach (Document acDoc in Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager) //commentout #2
            {
                acDbase.ReadDwgFile(file, System.IO.FileShare.ReadWrite, false, ""); //comment out #1
                //acDbase = acDoc.Database; //comment out #2
                //acDoc.LockDocument(); //comment out #2

                var acTrans = acDbase.TransactionManager.StartTransaction();

                var acBlkTbl = acTrans.GetObject(acDbase.BlockTableId, OpenMode.ForRead) as BlockTable;

                foreach (var btrId in acBlkTbl)
                {
                    var btr = (BlockTableRecord)acTrans.GetObject(btrId, OpenMode.ForWrite);

                    foreach (var item in attributes)
                    {
                        var attr = new AttributeDefinition()
                        {
                            Layer = "0",
                            ColorIndex = 0,
                            Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(ColorMethod.ByAci, 0),
                            Tag = item.ToUpper(),
                            Prompt = "Result" + item,
                            TextString = "",
                            Preset = false,
                            TextStyleId = acDbase.Textstyle,//<--   A2010
                            Height = 0.1250,
                            WidthFactor = 0.7500,
                            Justify = AttachmentPoint.MiddleCenter,
                            AlignmentPoint = new Point3d(0, 0.1047, 0),
                            LockPositionInBlock = true,
                            Invisible = true,
                        };
                        attr.SetDatabaseDefaults(acDbase);

                        if (false)
                        {
                            foreach (ObjectId ObjId in btr)
                            {
                                var obj = acTrans.GetObject(ObjId, OpenMode.ForWrite);
                                if (obj is BlockReference)
                                {

                                    var acBlock = obj as BlockReference;

                                    AttributeReference attRef = new AttributeReference();
                                    attRef.SetAttributeFromBlock(attr, acBlock.BlockTransform);

                                    acBlock.AttributeCollection.AppendAttribute(attRef);
                                    acTrans.AddNewlyCreatedDBObject(attRef, true);
                                }
                            }
                        }
                        else
                        {
                            btr.AppendEntity(attr);
                        }
                    }
                    
                    btr.SynchronizeAttributes();
                }

            }
        }



Additional Functions (SynchroniseAttributes)

public static class ExtensionMethods
    {
        static RXClass attDefClass = RXClass.GetClass(typeof(AttributeDefinition));

        public static void SynchronizeAttributes(this BlockTableRecord target)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            Transaction tr = target.Database.TransactionManager.TopTransaction;
            if (tr == null)
                throw new Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.NoActiveTransactions);
            List<AttributeDefinition> attDefs = target.GetAttributes(tr);
            foreach (ObjectId id in target.GetBlockReferenceIds(true, false))
            {
                BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForWrite);
                br.ResetAttributes(attDefs, tr);
            }
            if (target.IsDynamicBlock)
            {
                target.UpdateAnonymousBlocks();
                foreach (ObjectId id in target.GetAnonymousBlockIds())
                {
                    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
                    attDefs = btr.GetAttributes(tr);
                    foreach (ObjectId brId in btr.GetBlockReferenceIds(true, false))
                    {
                        BlockReference br = (BlockReference)tr.GetObject(brId, OpenMode.ForWrite);
                        br.ResetAttributes(attDefs, tr);
                    }
                }
            }
        }

        private static List<AttributeDefinition> GetAttributes(this BlockTableRecord target, Transaction tr)
        {
            List<AttributeDefinition> attDefs = new List<AttributeDefinition>();
            foreach (ObjectId id in target)
            {
                if (id.ObjectClass == attDefClass)
                {
                    AttributeDefinition attDef = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
                    attDefs.Add(attDef);
                }
            }
            return attDefs;
        }

        private static void ResetAttributes(this BlockReference br, List<AttributeDefinition> attDefs, Transaction tr)
        {
            int error_prot = 0;
            Dictionary<string, string> attValues = new Dictionary<string, string>();
            foreach (ObjectId id in br.AttributeCollection)
            {
                
                if (!id.IsErased)
                {
                    AttributeReference attRef = (AttributeReference)tr.GetObject(id, OpenMode.ForWrite);
                    try
                    {
                        attValues.Add(attRef.Tag,
                          attRef.IsMTextAttribute ? attRef.MTextAttribute.Contents : attRef.TextString);
                    }
                    catch
                    {
                        try
                        {
                            error_prot++;
                            attValues.Add(attRef.Tag + error_prot.ToString(),
                                attRef.IsMTextAttribute ? attRef.MTextAttribute.Contents : attRef.TextString);
                        }
                        catch { }
                    }
                    attRef.Erase();
                }
            }
            foreach (AttributeDefinition attDef in attDefs)
            {
                AttributeReference attRef = new AttributeReference();
                attRef.SetAttributeFromBlock(attDef, br.BlockTransform);
                if (attDef.Constant)
                {
                    attRef.TextString = attDef.IsMTextAttributeDefinition ?
                        attDef.MTextAttributeDefinition.Contents :
                        attDef.TextString;
                }
                else if (attValues.ContainsKey(attRef.Tag))
                {
                    attRef.TextString = attValues[attRef.Tag];
                }
                br.AttributeCollection.AppendAttribute(attRef);
                tr.AddNewlyCreatedDBObject(attRef, true);
            }
        }
    }



0 Likes
Accepted solutions (1)
1,238 Views
5 Replies
Replies (5)
Message 2 of 6

_gile
Consultant
Consultant

Hi,

 

You should:

- create a new Database for each file name (within a using statement to insure Dispose is called for each)

- also use a using statement for the transaction

- call Snippet AddNewlyCreatedDBObject() to add the newly created attribute definition.

- not use: if (false) because it will never run

 

        [CommandMethod("MWE", CommandFlags.Session)]
        public static void MWE()
        {
            var filenames = new List<string>();
            filenames.Add("C:\\temp\\test.dwg");

            var attributes = new List<string>();
            attributes.Add("Att1");

            foreach (var file in filenames)
            {
                using (var db = new Database(false, true))
                {
                    db.ReadDwgFile(file, FileOpenMode.OpenForReadAndAllShare, false, "");
                    using (var tr = db.TransactionManager.StartTransaction())
                    {
                        var blockTable = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                        foreach (var btrId in blockTable)
                        {
                            var btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForWrite);
                            foreach (var item in attributes)
                            {
                                var attr = new AttributeDefinition()
                                {
                                    Layer = "0",
                                    ColorIndex = 0,
                                    Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(ColorMethod.ByAci, 0),
                                    Tag = item.ToUpper(),
                                    Prompt = "Result" + item,
                                    TextString = "",
                                    Preset = false,
                                    TextStyleId = db.Textstyle,
                                    Height = 0.1250,
                                    WidthFactor = 0.7500,
                                    Justify = AttachmentPoint.MiddleCenter,
                                    AlignmentPoint = new Point3d(0, 0.1047, 0),
                                    LockPositionInBlock = true,
                                    Invisible = true,
                                };
                                btr.AppendEntity(attr);
                                tr.AddNewlyCreatedDBObject(attr, true);
                            }
                            btr.SynchronizeAttributes();
                        }
                    }
                }
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 3 of 6

_gile
Consultant
Consultant

I forgot: do not call SetDatabaseDefaults() after having set the layer and color properties.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 4 of 6

Anonymous
Not applicable

Thank you for the help, however I am still seeing the same error when running your code. When the code reaches

btr.AppendEntity(attr);

i get an exception error for eWrongDatabase.

I think these lines are probably missing from your reply at the end of the using transaction/db as well

tr.Commit();
tr.Dispose();

db.CloseInput(true);
db.SaveAs(file, DwgVersion.Current);
0 Likes
Message 5 of 6

_gile
Consultant
Consultant
Accepted solution

It looks like you cannot set the attribute Layer property before adding it to the Database.

 

This works for me (tested)

 

        [CommandMethod("MWE")]
        public static void MWE()
        {
            var filenames = new List<string>();
            filenames.Add("C:\\temp\\test.dwg");

            var attributes = new List<string>();
            attributes.Add("Att1");

            foreach (var file in filenames)
            {
                using (var db = new Database(false, true))
                {
                    db.ReadDwgFile(file, FileOpenMode.OpenForReadAndAllShare, false, "");
                    using (var tr = db.TransactionManager.StartTransaction())
                    {
                        var blockTable = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                        foreach (var btrId in blockTable)
                        {
                            var btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForWrite);
                            if (!(btr.IsLayout || btr.IsFromExternalReference || btr.IsDependent))
                            {
                                foreach (var item in attributes)
                                {
                                    var attr = new AttributeDefinition()
                                    {
                                        Tag = item.ToUpper(),
                                        TextString = "",
                                        ColorIndex = 0,
                                        Prompt = "Result" + item,
                                        Preset = false,
                                        TextStyleId = db.Textstyle,
                                        Height = 0.1250,
                                        WidthFactor = 0.7500,
                                        Justify = AttachmentPoint.MiddleCenter,
                                        AlignmentPoint = new Point3d(0, 0.1047, 0),
                                        LockPositionInBlock = true,
                                        Invisible = true
                                    };
                                    btr.AppendEntity(attr);
                                    tr.AddNewlyCreatedDBObject(attr, true);
                                    attr.Layer = "0";
                                }
                                btr.SynchronizeAttributes();
                            }
                        }
                        tr.Commit();
                    }
                    db.SaveAs(file, DwgVersion.Current);
                }
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 6 of 6

Anonymous
Not applicable

Thanks so much more the help! I'm not sure I would have ever spotted that the layer property was the culprit!

0 Likes