Writing and Reading Values to An Entity's Extended Dictionary

Writing and Reading Values to An Entity's Extended Dictionary

BKSpurgeon
Collaborator Collaborator
3,049 Views
3 Replies
Message 1 of 4

Writing and Reading Values to An Entity's Extended Dictionary

BKSpurgeon
Collaborator
Collaborator

I want to know if I’m doing this right:

  • In order to retrieve some data placed in a Result Buffer, I have to remember the order of the data placed in the result buffer?
  • Secondly, how does one store a vector3d in a result buffer which is to be placed in an entity’s extended dictionary?

 

Given Information:

Let’s suppose I have the following information:

  • Contact’s name (string)
  • Contact’s phone: (int)
  • Vector

 

What I want to do:

I want to add the above information to an entity’s Extension dictionary.

 

Am I doing this right?

 

Here’s the calling code:

 

        [CommandMethod("AddAndReadXRecord")]
        public void AddXAndReadRecord()
        {
            RecordAdderAndReader addAndRead = new RecordAdderAndReader(Application.DocumentManager.CurrentDocument);
            addAndRead.ReadEntityXRecord();
        }     

And here are the supporting code/classes:

 

    public class RecordAdderAndReader
    {
        private Document doc;
        private Database db;
        private Editor ed;
        private ObjectId entityId;

        // the name of the Xrecord which will be added
        private const string markNo = "MarkNo";

        public RecordAdderAndReader(Document doc)
        {
            this.doc = doc;
            this.db = doc.Database;
            this.ed = doc.Editor;

            PromptEntityResult entityResult = ed.GetEntity("Select entity to add the " + markNo + " Xrecord to it's extension dictionary. The Default No will be it's Handle.");

            if (entityResult.Status != PromptStatus.OK)
            {
                return;
            }
            else
            {
                // set the panel name - to it's handle.
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    DBObject entity = tr.GetObject(entityResult.ObjectId, OpenMode.ForRead) as DBObject;
                    this.entityId = entity.Id;
                    string defaultPanelName = entity.Handle.ToString();

                    XRecordAdderHelper xRecordAdder = new XRecordAdderHelper(entity.Id);
                    xRecordAdder.PersistDataToObject("MarkNo", entity.Handle.ToString());

                    tr.Commit();
                }
            }
        }

        public void ReadEntityXRecord()
        {
            XRecordReader reader = new XRecordReader(markNo);
            reader.readValue(entityId);
        }
    }

    internal class XRecordAdderHelper
    {
        private readonly ObjectId id;
        private ObjectId extensionDictionaryId;

        public XRecordAdderHelper(ObjectId id)
        {
            this.id = id;
            addExtensionDictionaryIfItDoesNotExist(id);
        }

        private void addExtensionDictionaryIfItDoesNotExist(ObjectId id)
        {
            Database db = id.Database;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                DBObject dbObj = tr.GetObject(id, OpenMode.ForRead);

                this.extensionDictionaryId = dbObj.ExtensionDictionary;

                if (extensionDictionaryId == ObjectId.Null)
                {
                    dbObj.UpgradeOpen();
                    dbObj.CreateExtensionDictionary();
                    extensionDictionaryId = dbObj.ExtensionDictionary;
                }

                tr.Commit();
            }
        }

        public void PersistDataToObject(string xRecordName, string dataValue)
        {
            Database db = id.Database;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                // get the extension dictionary
                DBDictionary extensionDictionary = tr.GetObject(this.extensionDictionaryId, OpenMode.ForWrite) as DBDictionary;

                // set up the data.
                List<TypedValue> typedValues = new List<TypedValue>
                {
                    new TypedValue((int)DxfCode.ExtendedDataAsciiString, "Freddie Mercury")
                    , new TypedValue((int)DxfCode.Int32, 123456)
                    , new TypedValue((int)DxfCode.Real, 1)
                    , new TypedValue((int)DxfCode.Real, 0)
                    , new TypedValue((int)DxfCode.Real, 0)
                }; // If I want to add a Vector, am I doing this right?

                ResultBuffer rb = new ResultBuffer(typedValues.ToArray());

                // add the data to the XRecord
                Xrecord xrecord = new Xrecord();
                xrecord.Data = rb;

                // add the Xrecord to the ExtensionDictionary
                // what if the record already exists? Add error checking for this.
                extensionDictionary.SetAt(xRecordName, xrecord);
                tr.AddNewlyCreatedDBObject(xrecord, true);
                tr.Commit();
            }
        }
    }

    public class XRecordReader
    {
        private readonly string xRecordEntryNane;
        private Editor ed;

        public XRecordReader(string xRecordEntryNane)
        {
            this.xRecordEntryNane = xRecordEntryNane;
            this.ed = Application.DocumentManager.CurrentDocument.Editor;
        }

        public void readValue(ObjectId objectId)
        {
            string name = "";
            int phoneNumber = 0;
            double vectorX = 0;
            double vectorY = 0;
            double vectorZ = 0;

            using (Transaction tr = objectId.Database.TransactionManager.StartTransaction())
            {
                DBObject dBObject = tr.GetObject(objectId, OpenMode.ForRead) as DBObject;

                DBDictionary extensionDictionary = tr.GetObject(dBObject.ExtensionDictionary, OpenMode.ForRead) as DBDictionary;

                if (extensionDictionary.Contains(xRecordEntryNane))
                {
                    Xrecord xrecord = tr.GetObject(extensionDictionary.GetAt(xRecordEntryNane), OpenMode.ForRead, false) as Xrecord;
                    if (xrecord != null)
                    {
                        ResultBuffer rb = xrecord.Data;

                        if (rb != null)
                        {
                            TypedValue[] tvArray = rb.AsArray();

                            for (int i = 0; i < tvArray.Length; i++)
                            {
                                if (i == 0)
                                {
                                    name = (string)tvArray[i].Value;
                                }
                                else if (i == 1)
                                {
                                    phoneNumber = (int)tvArray[i].Value;
                                }
                                else if (i == 2)
                                {
                                    vectorX = (double)tvArray[i].Value;
                                }
                                else if (i == 3)
                                {
                                    vectorY = (double)tvArray[i].Value;
                                }
                                else if (i == 4)
                                {
                                    vectorZ = (double)tvArray[i].Value;
                                }
                            }

                            rb.Dispose();
                        }
                    }
                }

                // print all the results
                ed.WriteMessage("\nName: " + name);
                ed.WriteMessage("\nPhone: " + phoneNumber.ToString());
                ed.WriteMessage("\nVector Values: X:" + vectorX.ToString() + ", V: " + vectorY.ToString() + " Z: " + vectorZ.ToString());

                tr.Commit();
            }
        }
    }

Your ideas/assistance is much appreciated.

0 Likes
Accepted solutions (1)
3,050 Views
3 Replies
Replies (3)
Message 2 of 4

_gile
Consultant
Consultant
Accepted solution

hi,

 

I'd rather use some more generic extension methods to set or get Xrecords in (extension) dictionaries.

 

    static class Extension
    {
        public static void Check(this ErrorStatus es, bool condition, string msg = null)
        {
            if (!condition)
            {
                if (msg == null)
                    throw new Exception(es);
                else
                    throw new Exception(es, msg);
            }
        }

        public static T GetObject<T>(
            this ObjectId id,
            OpenMode mode = OpenMode.ForRead,
            bool openErased = false,
            bool forceOpenOnLockedLayer = false)
            where T : DBObject
        {
            ErrorStatus.NullObjectId.Check(!id.IsNull);
            Transaction tr = id.Database.TransactionManager.TopTransaction;
            ErrorStatus.NoActiveTransactions.Check(tr != null);

            return (T)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayer);
        }

        public static DBDictionary TryGetExtensionDictionary(this DBObject source)
        {
            Assert.IsNotNull(source, nameof(source));
            ObjectId dictId = source.ExtensionDictionary;
            if (dictId == ObjectId.Null)
            {
                return null;
            }
            return dictId.GetObject<DBDictionary>();
        }

        public static DBDictionary GetOrCreateExtensionDictionary(this DBObject source)
        {
            Assert.IsNotNull(source, nameof(source));
            if (source.ExtensionDictionary == ObjectId.Null)
            {
                source.UpgradeOpen();
                source.CreateExtensionDictionary();
            }
            return source.ExtensionDictionary.GetObject<DBDictionary>();
        }

        public static ResultBuffer GetXDictionaryXrecordData(this DBObject source, string key)
        {
            Assert.IsNotNull(source, nameof(source));
            Assert.IsNotNullOrWhiteSpace(key, nameof(key));
            DBDictionary xdict = source.TryGetExtensionDictionary();
            if (xdict == null)
            {
                return null;
            }
            return xdict.GetXrecordData(key);
        }

        public static void SetXDictionaryXrecordData(this DBObject target, string key, params TypedValue[] values)
        {
            target.SetXDictionaryXrecordData(key, new ResultBuffer(values));
        }

        public static void SetXDictionaryXrecordData(this DBObject target, string key, ResultBuffer data)
        {
            Assert.IsNotNull(target, nameof(target));
            Assert.IsNotNullOrWhiteSpace(key, nameof(key));
            target.GetOrCreateExtensionDictionary().SetXrecordData(key, data);
        }

        public static ResultBuffer GetXrecordData(this DBDictionary dict, string key)
        {
            Assert.IsNotNull(dict, nameof(dict));
            if (!dict.Contains(key))
                return null;
            ObjectId id = (ObjectId)dict[key];
            return id.GetObject<Xrecord>().Data;
        }

        public static void SetXrecordData(this DBDictionary dict, string key, params TypedValue[] values)
        {
            dict.SetXrecordData(key, new ResultBuffer(values));
        }

        public static void SetXrecordData(this DBDictionary dict, string key, ResultBuffer data)
        {
            Assert.IsNotNull(dict, nameof(dict));
            Assert.IsNotNullOrWhiteSpace(key, nameof(key));
            Xrecord xrec;
            if (dict.Contains(key))
            {
                xrec = ((ObjectId)dict[key]).GetObject<Xrecord>(OpenMode.ForWrite);
            }
            else
            {
                dict.UpgradeOpen();
                xrec = new Xrecord();
                dict.SetAt(key, xrec);
                dict.Database.TransactionManager.TopTransaction.AddNewlyCreatedDBObject(xrec, true);
            }
            xrec.Data = data;
        }
    }

    static class Assert
    {
        public static void IsNotNull<T>(T obj, string paramName) where T : class
        {
            if (obj == null)
                throw new System.ArgumentNullException(paramName);
        }

        public static void IsNotNullOrWhiteSpace(string str, string paramName)
        {
            if (string.IsNullOrWhiteSpace(str))
                throw new System.ArgumentException("eNullOrWhiteSpace", paramName);
        }
    }

 

Then you can simply use these extension methods in specific contexts.

To add a vector to a resultbuffer, a trick is to convert it into a point (this can be done by adding the vector to the Point3d.Origin). To get the vector from the point, you can use the getAsvector method.

        [CommandMethod("AddMarkNo")]
        public static void AddMarkNo()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            var per = ed.GetEntity("\nSelect entity: ");
            if (per.Status != PromptStatus.OK)
                return;
            var name = "Freddie Mercury";
            var phone = 123456;
            var vector = new Vector3d(1.0, 0.0, 0.0);
            using (var tr = db.TransactionManager.StartTransaction())
            {
                var ent = (Entity)tr.GetObject(per.ObjectId, OpenMode.ForRead);
                ent.SetXDictionaryXrecordData(
                    "MarkNo",
                    new TypedValue(1, name),
                    new TypedValue(90, phone),
                    new TypedValue(10, Point3d.Origin + vector)); 
                tr.Commit();
            }
        }

        [CommandMethod("ReadMarkNo")]
        public static void ReadMarkNo()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            var per = ed.GetEntity("\nSelect entity: ");
            if (per.Status != PromptStatus.OK)
                return;
            using (var tr = db.TransactionManager.StartTransaction())
            {
                var ent = tr.GetObject(per.ObjectId, OpenMode.ForRead);
                var resbuf = ent.GetXDictionaryXrecordData("MarkNo");
                if (resbuf != null)
                {
                    var data = resbuf.AsArray();
                    string name = (string)data[0].Value;
                    int phone = (int)data[1].Value;
                    Vector3d vector = ((Point3d)data[2].Value).GetAsVector();
                    ed.WriteMessage($"\nName: {name}");
                    ed.WriteMessage($"\nPhone: {phone}");
                    ed.WriteMessage($"\nVector: {vector}");
                }
                else
                {
                    ed.WriteMessage($"\nMarkNo not found");
                }
                tr.Commit();
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 4

dgorsman
Consultant
Consultant

If order is a consideration, you might consider putting different data in different XRecords so you can call them by name.  It makes it easier to do things like use const strings for names.

 

I generally try to avoid dependency on the order of data as it makes further development a bit easier e.g. removing obsolete data doesn't require a mass reshuffling of index values.

----------------------------------
If you are going to fly by the seat of your pants, expect friction burns.
"I don't know" is the beginning of knowledge, not the end.


Message 4 of 4

BKSpurgeon
Collaborator
Collaborator

hi Gilles

 

having some issues here:

 

        public static T GetObject<T>(
            this ObjectId id,
            OpenMode mode = OpenMode.ForRead,
            bool openErased = false,
            bool forceOpenOnLockedLayer = false)
            where T : DBObject
        {
            ErrorStatus.NullObjectId.Check(!id.IsNull); // ErrorStatus does not contain a definition for Null ObjectId - is this 
            Transaction tr = id.Database.TransactionManager.TopTransaction;
            ErrorStatus.NoActiveTransactions.Check(tr != null);

            return (T)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayer);
        }

 

 

Please ignore  - This has been fixed:

 

The problem was a using statement: to using Autodesk.AutoCAD.Runtime;

0 Likes