Author Topic: -={ Challenge }=- Making Xrecords Easier  (Read 3564 times)

0 Members and 1 Guest are viewing this topic.

Jeff H

  • Needs a day job
  • Posts: 6150
-={ Challenge }=- Making Xrecords Easier
« on: August 24, 2011, 05:13:32 PM »
Since most algorithms for most problems have been created.
I thought a challenge which focused on design and implementation would be a better idea to try.
 
The name pretty much explains it.
A way for adding and getting xrecords easier and more meaningful.
 
I just threw one together quickly and will do some quick testing and post but,
the basic idea was to use a class where you use reflection to create the values from the properties and to set the properties of the class from a DBDictionary
 

Jeff H

  • Needs a day job
  • Posts: 6150
Re: -={ Challenge }=- Making Xrecords Easier
« Reply #1 on: August 24, 2011, 05:33:55 PM »
Thrown together quickly for getting this challenge started, and has not been tested much.
Need to refactor it since it uses too much coupling and couple other things could be improved, but maybe good enough to get started
Attached the project which may be easier to understand.
 
Your class needs to implement the IXrecordProperties interface
Code: [Select]
    public interface IXrecordProperties
    {
        string DictionaryName { get; }
        List<string> PropertyNames { get; }
    }

The DictionaryName is the name of the Dictionary that will be created and PropertyNames is a list of strings which are the properties that you want to save to a DBDictionary.
 
Here would be an example
Code: [Select]
public class TestClass : IXrecordProperties
    {
        const string DICT_NAME = "Dictionary_Test";
        public string word { get; set; }
        public int integer { get; set; }
        public ObjectId id { get; set; }
        public List<string> properties = new List<string>() { "word", "integer", "id" };

        public TestClass()
        {
        }
        public TestClass(string s, int i)
        {
            word = s;
            integer = i;
        }

        public string DictionaryName
        {
            get { return DICT_NAME; }
        }

        public List<string> PropertyNames
        {
            get { return properties; }
        }
    }

You use this instead of a DBDictionary which inherits from a DBDictionary
 
Code: [Select]
public class XrecordDictionary : DBDictionary
    {
   
        public IXrecordProperties XrecordProperties { get; set; }
 
        public XrecordDictionary (IXrecordProperties xrecordProperties)
        {
            XrecordProperties = xrecordProperties;             
        }
        public void AddToNOD(Database db)
        {           
            Transaction trx = db.TransactionManager.TopTransaction;
            DBDictionary nod = (DBDictionary)trx.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForWrite);
            nod.SetAt(XrecordProperties.DictionaryName, this);
            trx.AddNewlyCreatedDBObject(this, true);
            XrecordFactory.CreateTypedValuesFromProperties(XrecordProperties, this);
        }
        public void AddToDbObject(Database db, DBObject dbObject)
        {
            if (!dbObject.IsTransactionResident)
            {
                Application.ShowAlertDialog("Please put in a TransAction");
            }
            if (!dbObject.IsPersistent)
            {
                Application.ShowAlertDialog("Please add to the Database");
            }
            Transaction trx = db.TransactionManager.TopTransaction;
            ObjectId extDictionaryId;
            extDictionaryId = dbObject.ExtensionDictionary;
            if (extDictionaryId == ObjectId.Null)
            {
                if (!dbObject.IsWriteEnabled)
                {
                    dbObject.UpgradeOpen();
                }
                dbObject.CreateExtensionDictionary();
                extDictionaryId = dbObject.ExtensionDictionary;
            }
            DBDictionary extDictionary = (DBDictionary)trx.GetObject(extDictionaryId, OpenMode.ForWrite);
            extDictionary.SetAt(XrecordProperties.DictionaryName, this);
            trx.AddNewlyCreatedDBObject(this, true);
            XrecordFactory.CreateTypedValuesFromProperties(XrecordProperties, this);
           

        }
        public IXrecordProperties GetFromNOD(Database db)
        {               
            Transaction trx = db.TransactionManager.TopTransaction;
            DBDictionary nod = (DBDictionary)trx.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
            ObjectId dicId = nod.GetAt(this.XrecordProperties.DictionaryName);
            DBDictionary dic = (DBDictionary)trx.GetObject(dicId, OpenMode.ForRead);
            XrecordFactory.SetPropertiesFromTypedValues(dic, this.XrecordProperties);
            return XrecordProperties;
        }
        public IXrecordProperties GetFromDbObject(Database db, DBObject dbObject)
        {
            if (!dbObject.IsTransactionResident)
            {
                Application.ShowAlertDialog("Please put in a TransAction");
            }
            if (!dbObject.IsPersistent)
            {
                Application.ShowAlertDialog("Please add to the Database");
            }
            Transaction trx = db.TransactionManager.TopTransaction;
            ObjectId extDictionaryId;
            extDictionaryId = dbObject.ExtensionDictionary;
            if (extDictionaryId == ObjectId.Null)
            {
                Application.ShowAlertDialog("Extension Dictionary does not exist");
            }
            DBDictionary extDictionary = (DBDictionary)trx.GetObject(extDictionaryId, OpenMode.ForRead);
            ObjectId dicId = extDictionary.GetAt(this.XrecordProperties.DictionaryName);
            DBDictionary dic = (DBDictionary)trx.GetObject(dicId, OpenMode.ForRead);
            XrecordFactory.SetPropertiesFromTypedValues(dic, this.XrecordProperties);
            return XrecordProperties;
 
        }
    }

 
 
2 helper classes that aid the XrecordDictionary
 
For getting the TypedValueCodes
 
Code: [Select]

   // A class for getting the TypedValue Code from the Type
   public class TypedValueCodes
    {
        public const int NONE = 0;
        public const int TEXT = 1;
        public const int POINT3D = 10;
        //public const int POINT2D = 11;
        //public const int VECTOR3D = 12;
        //public const int VECTOR2D = 13;
        public const int DOUBLE = 40;
        public const int SHORT = 60;
        public const int INT = 90;
        //public const int CONTROL_STRING = 102;
        public const int INT64 = 160;
        public const int BYTE = 280;
        //public const int BINARY_CHUNK = 310;
        public const int HANDLE = 320;
        public const int OBJECT_ID_SOFT = 330;
        //public const int OBJECT_ID_HARD = 340;
        private static Dictionary<Type, int> typedValueCodesDictionary = new Dictionary<Type, int>(){
           {typeof(string), TEXT},
           {typeof(Point3d), POINT3D},
           //{typeof(Point2d), POINT2D},
           //{typeof(Vector3d), VECTOR3D},
           //{typeof(Vector2d), VECTOR2D},
           {typeof(double), DOUBLE},
           {typeof(short), SHORT},
           {typeof(int), INT},
           {typeof(Int64), INT64},
           {typeof(byte), BYTE},
           {typeof(Handle), HANDLE},
           {typeof(ObjectId), OBJECT_ID_SOFT}};
        public static int GetTypedValueCode(Type typ)
        {
            int result;
            if (typedValueCodesDictionary.TryGetValue(typ, out result))
            {
                return result;
            }         
            return NONE;
        }
     
    }

Getting and setting the Properties
Code: [Select]
//Not a good Name for it since it does not follow the Factory or AbstractFactory Pattern.
   public class XrecordFactory
    {
       
 
       public static void CreateTypedValuesFromProperties(IXrecordProperties xrecordProperties, DBDictionary dictionary)
       {
         
           Transaction trx = dictionary.Database.TransactionManager.TopTransaction;
           foreach (string str in xrecordProperties.PropertyNames)
           {
               PropertyInfo pi = xrecordProperties.GetType().GetProperty(str);
               if (!pi.CanRead)
               {
                   continue;
               }
               if (pi.PropertyType.IsValueType)
               {
                   object val = pi.GetValue(xrecordProperties, null);                 
                   int typedValueCode = TypedValueCodes.GetTypedValueCode(pi.PropertyType);
                   if (typedValueCode == TypedValueCodes.NONE)
                   {
                       continue;
                   }
                   Xrecord xr = new Xrecord();
                   ResultBuffer rb = new ResultBuffer(new TypedValue(typedValueCode, val));
                   xr.Data = rb;
                   dictionary.SetAt(pi.Name, xr);
                   trx.AddNewlyCreatedDBObject(xr, true);                 
               }
               else if (pi.PropertyType == typeof(string))
               {
                   object val = pi.GetValue(xrecordProperties, null);
                   Xrecord xr = new Xrecord();
                   ResultBuffer rb = new ResultBuffer(new TypedValue(TypedValueCodes.TEXT, val));
                   xr.Data = rb;
                   dictionary.SetAt(pi.Name, xr);
                   trx.AddNewlyCreatedDBObject(xr, true);               
             
               }

           }
       }
       public static void SetPropertiesFromTypedValues(DBDictionary dbDictionary, IXrecordProperties xrecordProperties)
       {
           Database db = HostApplicationServices.WorkingDatabase;
           Transaction trx = db.TransactionManager.TopTransaction;
           foreach (DBDictionaryEntry entry in dbDictionary)
           {
               PropertyInfo pi = xrecordProperties.GetType().GetProperty(entry.Key);
               Xrecord xr = (Xrecord)trx.GetObject(entry.Value, OpenMode.ForRead);
               object obj = xr.Data.AsArray()[0].Value;
               pi.SetValue(xrecordProperties, obj, null);
             
           }
       }
    }

Finally 2 Test Commands
Code: [Select]
[CommandMethod("TestCommand")]
        public void TestCommand()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            using (Transaction trx = db.TransactionManager.StartTransaction())
            {
         

                TestClass tc = new TestClass("TestStringNod", 40);
                tc.id = db.LayerTableId;
                XrecordDictionary xd = new XrecordDictionary(tc);
                xd.AddToNOD(db);
               
                BlockTableRecord model = (BlockTableRecord)trx.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite);
                Line lne = new Line(Point3d.Origin, new Point3d(100, 100, 0));
                model.AppendEntity(lne);
                trx.AddNewlyCreatedDBObject(lne, true);
                TestClass tc1 = new TestClass("TestStringExtDict", 1);
                tc1.id = lne.ObjectId;
                XrecordDictionary xd1 = new XrecordDictionary(tc1);
                xd1.AddToDbObject(db, lne);
                trx.Commit();
            }
        }
        [CommandMethod("TestCommandRead")]
        public void TestCommandRead()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            using (Transaction trx = db.TransactionManager.StartTransaction())
            {
                TestClass tc = new TestClass();               
                XrecordDictionary xd = new XrecordDictionary(tc);
                tc = (TestClass)xd.GetFromNOD(db);
                ed.WriteMessage("\n{0} {1} {2}", tc.word, tc.integer.ToString(), tc.id.ToString());
                ObjectId lineId = ed.GetEntity("\nSelect Line Created").ObjectId;
                Line lne = (Line)trx.GetObject(lineId, OpenMode.ForRead);
               
                TestClass tc1 = new TestClass();
                XrecordDictionary xd1 = new XrecordDictionary(tc1);
                xd1.GetFromDbObject(db, lne);
                ed.WriteMessage("\n{0} {1} {2}", tc1.word, tc1.integer.ToString(), tc1.id.ToString());

                trx.Commit();
            }
        }
 
    }

zoltan

  • Guest
Re: -={ Challenge }=- Making Xrecords Easier
« Reply #2 on: August 31, 2011, 09:24:45 AM »
This is really exciting, Jeff, because I happened to be doing the very same thing in a project, but I'm going about it in a much different way.

I have a base class called DictionaryObject that I can descend objects from.  It has a public method called SaveObjectData which you use to save the object's data into a dictionary.  I'm using reflection to get and set the values of properties in much the same way that you are, but I'm using an Attribute on the properties to get the TypedValue code.  The class also has a static method call CreateObject that is used to instantiate the object from the dictionary data using a special constructor, much like Serialization.

I'm in the process of re-writing this and cleaning it up a bit, so if it does not work, I apologize.

Everything below is in an abstract class called DictionaryObject.

Here are the methods to save the objects data to a dictionary given a transaction and the ObjectId of the dictionary.

Code: [Select]
        public virtual ObjectId SaveObjectData(Transaction trans, ObjectId dictionary)
        {
            return SaveData(trans, dictionary, this.GetType().Namespace.Split('.'), this.GetType().Name, GetObjectData());
        }

        public virtual ObjectId SaveObjectData(Transaction trans, ObjectId dictionary, string[] dictNames, string recordName)
        {
            return SaveData(trans, dictionary, dictNames, recordName, GetObjectData());
        }

It uses a static method on the class to save the data into the dictionary and can optionally specify the name of the Xrecord and an array of dictionary names which create a tree structure.  The data is retreived from the object using the private method GetObjectData.

Code: [Select]
        protected ResultBuffer GetObjectData()
        {
            ResultBuffer resultBuffer = new ResultBuffer();

            if (this.GetType().IsGenericType)
            {
                resultBuffer.Add(new TypedValue(100, this.GetType().GetGenericTypeDefinition().FullName));

                foreach (Type type in this.GetType().GetGenericArguments())
                {
                    resultBuffer.Add(new TypedValue(102, type.FullName));
                }
            }
            else
            {
                resultBuffer.Add(new TypedValue(100, this.GetType().FullName));
            }

            PropertyInfo[] propertyInfos = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                DictionaryDataCodeAttribute[] dictionaryDataAttributes = propertyInfo.GetCustomAttributes(typeof(DictionaryDataCodeAttribute), false) as DictionaryDataCodeAttribute[];

                foreach (DictionaryDataCodeAttribute dictionaryDataAttribute in dictionaryDataAttributes)
                {
                    resultBuffer.Add(new TypedValue(dictionaryDataAttribute.Code, propertyInfo.GetValue(this, null)));
                }
            }

            return resultBuffer;
        }

The name of the type and the name of the type's generic parameters are stored in a ResultBuffer as well as any property that is attributed with the DictionaryDataCodeAttribute.

Code: [Select]
    [AttributeUsage(AttributeTargets.Property)]
    internal class DictionaryDataCodeAttribute : Attribute
    {
        public DictionaryDataCodeAttribute(int code)
        {
            Code = code;
        }

        public int Code { get; private set; }
    }

Here is the static method which does the work:

Code: [Select]
        protected static ObjectId SaveData(Transaction trans, ObjectId dictionaryId, string[] dictNames, string recordName, ResultBuffer data)
        {
            ObjectId xRecordId = ObjectId.Null;

            DBDictionary lastDictionary = (DBDictionary)trans.GetObject(dictionaryId, OpenMode.ForRead);
            if (dictNames != null)
            {
                for (int i = 0; i < dictNames.Length; i++)
                {
                    DBDictionary dictionary;
                    if (lastDictionary.Contains(dictNames[i]))
                    {
                        dictionary = (DBDictionary)trans.GetObject(lastDictionary.GetAt(dictNames[i]), OpenMode.ForRead);
                    }
                    else
                    {
                        dictionary = new DBDictionary();

                        dictionary.TreatElementsAsHard = true;

                        if (!lastDictionary.IsWriteEnabled)
                        {
                            lastDictionary.UpgradeOpen();
                        }

                        lastDictionary.SetAt(dictNames[i], dictionary);

                        trans.AddNewlyCreatedDBObject(dictionary, true);
                    }

                    lastDictionary = dictionary;
                }
            }

            Xrecord xrecord;

            if (lastDictionary.Contains(recordName))
            {
                xRecordId = lastDictionary.GetAt(recordName);

                xrecord = (Xrecord)trans.GetObject(xRecordId, OpenMode.ForWrite);

                xrecord.Data = data;
            }
            else
            {
                xrecord = new Xrecord();

                xrecord.Data = data;

                if (!lastDictionary.IsWriteEnabled)
                {
                    lastDictionary.UpgradeOpen();
                }

                xRecordId = lastDictionary.SetAt(recordName, xrecord);

                trans.AddNewlyCreatedDBObject(xrecord, true);
            }

            return xRecordId;
        }

A complimentary static method exist to load the data from the dictionary into a ResultBuffer.

Code: [Select]
        protected static bool LoadData(Transaction trans, ObjectId dictionaryId, string[] dictNames, string recordName, out ResultBuffer objectData)
        {
            try
            {
                DBDictionary lastDictionary = (DBDictionary)trans.GetObject(dictionaryId, OpenMode.ForRead);
                if (dictNames != null)
                {
                    for (int i = 0; i < dictNames.Length; i++)
                    {
                        DBDictionary dictionary = (DBDictionary)trans.GetObject(lastDictionary.GetAt(dictNames[i]), OpenMode.ForRead);

                        lastDictionary = dictionary;
                    }
                }

                if (lastDictionary.Contains(recordName))
                {
                    Xrecord xRecord = (Xrecord)trans.GetObject(lastDictionary.GetAt(recordName), OpenMode.ForRead);

                    objectData = xRecord.Data;

                    return true;
                }
                else
                {
                    objectData = null;

                    return false;
                }
            }
            catch
            {
                objectData = null;

                return false;
            }
        }

To get the object back from the data, we use a static generic method to instantiate an object of a type from the dictionary.  There must be a special constrictor to create the object.

Code: [Select]
        public static bool CreateObject<OutObject>(Transaction trans, ObjectId dictionary, out OutObject drawingObject) where OutObject : DictionaryObject
        {
            return CreateObject<OutObject>(trans, dictionary, null, typeof(OutObject).Name, out drawingObject);
        }

        public static bool CreateObject<OutObject>(Transaction trans, ObjectId dictionary, string[] dictNames, string recordName, out OutObject drawingObject) where OutObject : DictionaryObject
        {
            drawingObject = null;

            ResultBuffer data;
            if (LoadData(trans, dictionary, dictNames, recordName, out data))
            {
                Assembly assembly = Assembly.GetCallingAssembly();

                Type mainType = typeof(OutObject);

                List<Type> subTypes = new List<Type>();

                foreach (TypedValue value in data)
                {
                    switch (value.TypeCode)
                    {
                        case 100:
                            mainType = assembly.GetType((string)value.Value);
                            break;

                        case 102:
                            subTypes.Add(assembly.GetType((string)value.Value));
                            break;
                    }
                }

                if (subTypes.Count > 0)
                {
                    Type genericType = mainType.MakeGenericType(subTypes.ToArray());

                    drawingObject = (OutObject)Activator.CreateInstance(genericType, new object[] { trans, data });
                }
                else
                {
                    drawingObject = (OutObject)Activator.CreateInstance(mainType, new object[] { trans, data });
                }

                drawingObject.SetObjectData(data);

                drawingObject.OnObjectRestored(trans, dictionary);

                return true;
            }
           
            return false;
        }

After the object is created, the method calls SetObjectData on the object to restore the property values from the ResultBuffer.

Code: [Select]
        protected void SetObjectData(ResultBuffer data)
        {
            PropertyInfo[] propertyInfos = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
               DictionaryDataCodeAttribute[] attributes = propertyInfo.GetCustomAttributes(typeof(DictionaryDataCodeAttribute), false) as DictionaryDataCodeAttribute[];

                foreach (DictionaryDataCodeAttribute dictionaryDataAttribute in attributes)
                {
                    object value;
                    if (data.TryGetValue(dictionaryDataAttribute.Code, out value))
                    {
                        try
                        {
                            propertyInfo.SetValue(this, value, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance, null, null, System.Globalization.CultureInfo.CurrentCulture);
                        }
                        catch
                        {
                        }
                    }
                }
            }
        }

After the object has been restored, a virtual call-back method is called so the consumer can do some initialization.

Code: [Select]
        protected virtual void OnObjectRestored(Transaction trans, ObjectId dictionaryId)
        {
        }

« Last Edit: August 31, 2011, 10:10:13 AM by zoltan »

zoltan

  • Guest
Re: -={ Challenge }=- Making Xrecords Easier
« Reply #3 on: August 31, 2011, 10:02:14 AM »
This class can be expanded to create an object that sores it's data in the extension dictionary of an DBObject.  It is implemented the same way, except the constructor is different.

Code: [Select]
    internal abstract class DrawingObject<T> : DictionaryObject where T : DBObject
    {
        public virtual ObjectId SaveObjectData(Transaction trans, T obj)
        {
            return SaveObjectData(trans, obj, this.GetType().Namespace.Split('.'), this.GetType().Name, GetObjectData());
        }

        public static ObjectId SaveObjectData(Transaction trans, T obj, string[] dictNames, string recordName, ResultBuffer data)
        {
            try
            {
                obj.CreateExtensionDictionary();
            }
            catch
            {
            }

            return SaveData(trans, obj.ExtensionDictionary, dictNames, recordName, data);
        }

        public static bool CreateObject<OutObject>(Transaction trans, T obj, out OutObject drawingObject) where OutObject : DrawingObject<T>
        {
            return CreateObject(trans, project, obj, typeof(OutObject).Namespace.Split('.'), typeof(OutObject).Name, out drawingObject);
        }

        public static bool CreateObject<OutObject>(Transaction trans, T obj, string[] dictNames, string recordName, out OutObject drawingObject) where OutObject : DrawingObject<T>
        {
            drawingObject = null;

            ResultBuffer data;
            if (LoadData(trans, obj.ExtensionDictionary, dictNames, recordName, out data))
            {
                Assembly assembly = Assembly.GetCallingAssembly();

                Type mainType = typeof(OutObject);

                List<Type> subTypes = new List<Type>();

                foreach (TypedValue value in data)
                {
                    switch (value.TypeCode)
                    {
                        case 100:
                            mainType = assembly.GetType((string)value.Value);
                            break;

                        case 102:
                            subTypes.Add(assembly.GetType((string)value.Value));
                            break;
                    }
                }

                if (subTypes.Count > 0)
                {
                    Type genericType = mainType.MakeGenericType(subTypes.ToArray());

                    drawingObject = (OutObject)Activator.CreateInstance(genericType, new object[] { trans, obj, data });
                }
                else
                {
                    drawingObject = (OutObject)Activator.CreateInstance(mainType, new object[] { trans, obj, data });
                }

                drawingObject.SetObjectData(data);

                drawingObject.OnObjectRestored(trans, obj.ExtensionDictionary);

                return true;
            }

            return false;
        }
    }

Here is an example of how it would be used.

Code: [Select]
    internal class BouncyBall : DrawingObject<Circle>
    {
        public BouncyBall(Point3d center, double radius, string color, double price, int bouncyness)
        {
            Center = center;
            Radius = radius;
            Color = color;
            Price = price;
            Bouncyness = bouncyness;
        }

        // Special Construictor
        public BouncyBall(Transaction trans, Circle circle, ResultBuffer data)
        {
            Center = circle.Center;
            Radius = circle.Radius;
        }

        protected override void OnObjectRestored(Transaction trans, ObjectId dictionaryId)
        {
            Application.ShowAlertDialog("You have a " + Color + " bouncy ball.");
        }

        public Point3d Center { get; set; }

        public double Radius { get; set; }

        [DictionaryDataCode(1)]
        public string Color { get; set; }

        [DictionaryDataCode(40)]
        public double Price { get; set; }

        [DictionaryDataCode(90)]
        public int Bouncyness { get; set; }
    }

Let's test it:

Code: [Select]
        [CommandMethod("MakeTestBall", "MakeTestBall", "MakeTestBall", CommandFlags.Modal)]
        public void MakeTestBall()
        {
            Document acadDocument = Application.DocumentManager.MdiActiveDocument;
            Database acadDatabase = acadDocument.Database;
            Editor acadEditor = acadDocument.Editor;

            PromptEntityResult entityResult = acadEditor.GetEntity("Select a Circle");

            if (entityResult.Status == PromptStatus.OK)
            {
                PromptResult colorResult = acadEditor.GetString("Color:");

                using (Transaction trans = acadDatabase.TransactionManager.StartTransaction())
                {
                    Circle circle = trans.GetObject(entityResult.ObjectId, OpenMode.ForWrite) as Circle;

                    if (circle != null)
                    {
                        BouncyBall ball = new BouncyBall(circle.Center, circle.Radius, colorResult.StringResult, 19.95, 2);

                        ball.SaveObjectData(trans, circle);

                        trans.Commit();
                    }
                }
            }
        }

        [CommandMethod("TestGetBall", "TestGetBall", "TestGetBall", CommandFlags.Modal)]
        public void TestGetBall()
        {
            Document acadDocument = Application.DocumentManager.MdiActiveDocument;
            Database acadDatabase = acadDocument.Database;
            Editor acadEditor = acadDocument.Editor;

            PromptEntityResult entityResult = acadEditor.GetEntity("Select a Circle");

            if (entityResult.Status == PromptStatus.OK)
            {
                using (Transaction trans = acadDatabase.TransactionManager.StartTransaction())
                {
                    Circle circle = trans.GetObject(entityResult.ObjectId, OpenMode.ForRead) as Circle;

                    if (circle != null)
                    {
                        BouncyBall ball;
                        if (DrawingObject<Circle>.CreateObject<BouncyBall>(trans, circle, out ball))
                        {
                            acadEditor.WriteMessage("Ball: " + ball.Color + " Price: " + ball.Price);
                        }
                    }
                }
            }
        }
« Last Edit: August 31, 2011, 10:05:29 AM by zoltan »

Jeff H

  • Needs a day job
  • Posts: 6150
Re: -={ Challenge }=- Making Xrecords Easier
« Reply #4 on: August 31, 2011, 10:03:39 AM »
Cool Zoltan,
I had another idea of inheriting a xrecord and using a setup with its extension dictionary that could store its collection entries or used for key value pair lookup I will post later.
 
Glad to see someone intrested.



zoltan

  • Guest
Re: -={ Challenge }=- Making Xrecords Easier
« Reply #5 on: August 31, 2011, 10:40:13 AM »
I am also working on saving other objects and collections into nested dictionaries under the main dictionary.  My plan is to create a system for serializing an entire object graph into a DbDictionary.  I'm looking forward to seeing what you come up with.  Let's bounce ideas off of each other.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: -={ Challenge }=- Making Xrecords Easier
« Reply #6 on: September 01, 2011, 11:02:37 AM »
Adding to Tony's TypedValueList http://www.theswamp.org/index.php?topic=14495.msg186823#msg186823

 with some thing like
Code: [Select]
    // With thanks to Tony Tanzillo and extending his class
    // http://www.theswamp.org/index.php?topic=14495.msg186823#msg186823

    public class TypedValueList : List<TypedValue>
    {
        //private List<string> searchKeys;
        public TypedValueList(params TypedValue[] args)
        {
            AddRange(args);
        }
        // Make it a bit easier to add items:
        public void Add(int typecode, object value)
        {
            base.Add(new TypedValue(typecode, value));
        }
        public void Add(string value)
        {
            if (value == "{" || value == "}")
            {
                base.Add(new TypedValue(TypedValueCodes.CONTROL_STRING, value));
            }
            else
            {
                base.Add(new TypedValue(TypedValueCodes.TEXT, value));
            }
       
        }
        public void Add(int value)
        {
            base.Add(new TypedValue(TypedValueCodes.INT, value));
           
        }
        public void Add(Point3d value)
        {
            base.Add(new TypedValue(TypedValueCodes.POINT3D, value));
        }
        public void Add(Point2d value)
        {
            Point3d pnt = new Point3d(value.X, value.Y, 0);
            base.Add(new TypedValue(TypedValueCodes.POINT2D, pnt));
        }
        public void Add(Vector3d value)
        {
            Point3d pnt = new Point3d(value.X, value.Y, value.Z);
            base.Add(new TypedValue(TypedValueCodes.POINT3D, pnt));
        }

        public void Add(Vector2d value)
        {
            Point3d pnt = new Point3d(value.X, value.Y, 0);
            base.Add(new TypedValue(TypedValueCodes.POINT2D, pnt));
        }
        public void Add(double value)
        {
            base.Add(new TypedValue(TypedValueCodes.DOUBLE, value));
        }
        public void Add(short value)
        {
            base.Add(new TypedValue(TypedValueCodes.SHORT, value));
        }
        public void Add(Int64 value)
        {
            base.Add(new TypedValue(TypedValueCodes.INT64, value));
        }
        public void Add(byte value)
        {
            base.Add(new TypedValue(TypedValueCodes.BYTE, value));
        }
        public void Add(byte[] value)
        {
            base.Add(new TypedValue(TypedValueCodes.BINARY_CHUNK, value));
        }
        public void Add(Handle value)
        {
            base.Add(new TypedValue(TypedValueCodes.HANDLE, value));
        }
        public void Add(ObjectId value)
        {
            base.Add(new TypedValue(TypedValueCodes.OBJECT_ID_SOFT, value));
        }
        public void Add(ObjectId value, bool addAsHard)
        {
            if (addAsHard)
            {
                base.Add(new TypedValue(TypedValueCodes.OBJECT_ID_HARD, value));
            }
            else
            {
                base.Add(new TypedValue(TypedValueCodes.OBJECT_ID_SOFT, value));
            }
        }
        public void Add(string searchKey, dynamic value)
        {
            this.Add(value);
        }
        // Implicit conversion to SelectionFilter
 
        public static implicit operator SelectionFilter(TypedValueList src)
        {
     
            return src != null ? new SelectionFilter(src) : null;
        }
        // Implicit conversion to ResultBuffer
        public static implicit operator ResultBuffer(TypedValueList src)
        {
            return src != null ? new ResultBuffer(src) : null;
        }
        // Implicit conversion to TypedValue[]
        public static implicit operator TypedValue[](TypedValueList src)
        {
            return src != null ? src.ToArray() : null;
        }
        // Implicit conversion from TypedValue[]
        public static implicit operator TypedValueList(TypedValue[] src)
        {
            return src != null ? new TypedValueList(src) : null;
        }
        // Implicit conversion from SelectionFilter
        public static implicit operator TypedValueList(SelectionFilter src)
        {
            return src != null ? new TypedValueList(src.GetFilter()) : null;
        }
        // Implicit conversion from ResultBuffer
        public static implicit operator TypedValueList(ResultBuffer src)
        {
            return src != null ? new TypedValueList(src.AsArray()) : null;
        }
    }


Since it errors out on Vectors and point2d would this cause a problem since the point3d is not transaction aware or does it become aware when the Result Buffer is added and made known to the transaction(Speaking of being disposed properly)?
Code: [Select]
public void Add(Vector2d value)
        {
            Point3d pnt = new Point3d(value.X, value.Y, 0);
            base.Add(new TypedValue(TypedValueCodes.POINT2D, pnt));
        }


 
 

Irvin

  • Guest
Re: -={ Challenge }=- Making Xrecords Easier
« Reply #7 on: September 16, 2011, 09:10:24 AM »
Hi there Jeff,

Great post great example. But recently i found this Autodesk university class http://au.autodesk.com/?nd=class&session_id=2865.
Here the make use of serilsation to store data as an xrecord. It's a great class. I found it to be verry usefull.

Kind regards,

Irvin

zoltan

  • Guest
Re: -={ Challenge }=- Making Xrecords Easier
« Reply #8 on: September 16, 2011, 01:36:50 PM »
I had thought about doing XML serialization and storing it as a string in the Xrecord.  I decided to go with my own kind of "Serialization" because it gave me more control over how the data is stored and would allow me to use the properties of the DBObjects to restore the classes. Like in the BouncyBall example, the Center and Radius properties come directly from the Circle object.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: -={ Challenge }=- Making Xrecords Easier
« Reply #9 on: September 16, 2011, 02:20:13 PM »
How is the performance if the object needs to be grabbed multiple times or updated many times in a session?
 
 
 
 

Irvin

  • Guest
Re: -={ Challenge }=- Making Xrecords Easier
« Reply #10 on: September 20, 2011, 09:03:11 AM »
Jeff Changing and reading the xrecord is not slower the getting the typed value and casting it to it's type.
But i don't automate updating the xrecords. It's a users command to change the values. And I only read the xrecords
to fill a datagrid.

So i can't give you any performace info about your situation you described.

Kind regards,

Irvin