Работа с XRecord и XData

Существует 2 механизма хранения произвольных данных у объекта - с помощью Xrecord и XData. Принципиальное отличие вариантов в объеме хранимых данных. Если XRecord имеет лимит до 2 Гб данных, то XData ограничено 16 Кб.

XData само по себе не является классом или структурой, это лишь название свойства, значением которого выступает ResultBuffer. Свойство XData имеют все объекты, унаследованные от DBObject и именно данные в нём имеют ограничение на 16 Кб. Xrecord кстати тоже имеет свойство Xdata, и там такого ограничения нет (т.к. свойство XData у DBObject имеет модификатор virtual, что означает, что оно переопределено у Xrecord).

Xrecord хранятся в словарях, а словари хранятся как при объектах, также унаследованные от DBObject (идентификатор словаря в значении свойства ExtensionDictionary), так и на уровне базы данных.

И XRecord и XData апеллириют набором данных, представленных в виде ResultBuffer. Для того, чтобы сохранить некоторую информацию в ResultBuffer, в чертеже должно быть зарегистрировано приложение (иметься запись RegAppTableRecord), для которого можно сохранить перечень данных разного типа, в отличие от стандартных DxfCode.

В примере ниже получается набор объектов из пользовательского выбора, и в свойство XData каждого из объектов добавляется ResultBuffer из пары значений -- имени приложения и некоторой текстовой строки (или иного типа данных для ResultBuffer, см. соответствующую статью.

Пример работы с XRecord в составе словарей см. в статье про словари.

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;

[CommandMethod("AttachXDataToSelectionSetObjects")]
public void AttachXDataToSelectionSetObjects()
{
    // Get the current database and start a transaction
    Database acCurDb;
    acCurDb = Application.DocumentManager.MdiActiveDocument.Database;

    Document acDoc = Application.DocumentManager.MdiActiveDocument;

    string appName = "MY_APP";
    string xdataStr = "This is some xdata";

    using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
    {
        // Request objects to be selected in the drawing area
        PromptSelectionResult acSSPrompt = acDoc.Editor.GetSelection();

        // If the prompt status is OK, objects were selected
        if (acSSPrompt.Status == PromptStatus.OK)
        {
            // Open the Registered Applications table for read
            RegAppTable acRegAppTbl;
            acRegAppTbl = acTrans.GetObject(acCurDb.RegAppTableId, OpenMode.ForRead) as RegAppTable;

            // Check to see if the Registered Applications table record for the custom app exists
            if (acRegAppTbl.Has(appName) == false)
            {
                using (RegAppTableRecord acRegAppTblRec = new RegAppTableRecord())
                {
                    acRegAppTblRec.Name = appName;

                    acTrans.GetObject(acCurDb.RegAppTableId, OpenMode.ForWrite);
                    acRegAppTbl.Add(acRegAppTblRec);
                    acTrans.AddNewlyCreatedDBObject(acRegAppTblRec, true);
                }
            }

            // Define the Xdata to add to each selected object
            using (ResultBuffer rb = new ResultBuffer())
            {
                rb.Add(new TypedValue((int)DxfCode.ExtendedDataRegAppName, appName));
                rb.Add(new TypedValue((int)DxfCode.ExtendedDataAsciiString, xdataStr));

                SelectionSet acSSet = acSSPrompt.Value;

                // Step through the objects in the selection set
                foreach (SelectedObject acSSObj in acSSet)
                {
                    // Open the selected object for write
                    Entity acEnt = acTrans.GetObject(acSSObj.ObjectId,
                                                        OpenMode.ForWrite) as Entity;

                    // Append the extended data to each object
                    acEnt.XData = rb;
                }
            }
        }

        // Save the new object to the database
        acTrans.Commit();

        // Dispose of the transaction
    }
}

В примере ниже сохраненная в примере выше информация выводится в командную строку для каждого из объектов из пользовательского выбора

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;

[CommandMethod("ViewXData")]
public void ViewXData()
{
    // Get the current database and start a transaction
    Database acCurDb;
    acCurDb = Application.DocumentManager.MdiActiveDocument.Database;

    Document acDoc = Application.DocumentManager.MdiActiveDocument;

    string appName = "MY_APP";
    string msgstr = "";

    using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
    {
        // Request objects to be selected in the drawing area
        PromptSelectionResult acSSPrompt = acDoc.Editor.GetSelection();

        // If the prompt status is OK, objects were selected
        if (acSSPrompt.Status == PromptStatus.OK)
        {
            SelectionSet acSSet = acSSPrompt.Value;

            // Step through the objects in the selection set
            foreach (SelectedObject acSSObj in acSSet)
            {
                // Open the selected object for read
                Entity acEnt = acTrans.GetObject(acSSObj.ObjectId,
                                                 OpenMode.ForRead) as Entity;

                // Get the extended data attached to each object for MY_APP
                ResultBuffer rb = acEnt.GetXDataForApplication(appName);

                // Make sure the Xdata is not empty
                if (rb != null)
                {
                    // Get the values in the xdata
                    foreach (TypedValue typeVal in rb)
                    {
                        msgstr = msgstr + "\n" + typeVal.TypeCode.ToString() + ":" + typeVal.Value;
                    }
                }
                else
                {
                    msgstr = "NONE";
                }

                // Display the values returned
                Application.ShowAlertDialog(appName + " xdata on " + acEnt.GetType().ToString() + ":\n" + msgstr);

                msgstr = "";
            }
        }

        // Ends the transaction and ensures any changes made are ignored
        acTrans.Abort();

        // Dispose of the transaction
    }
}