ADN Open CIS
Сообщество программистов Autodesk в СНГ

28/04/2014

Серилизация класса .NET в базу чертежа AutoCAD

Вопрос:

Я хотел бы выполнить серилизацияю моего .NET класса в чертеж AutoCAD, так чтобы я мог воссоздать этот класс (десерилизация его), когда чертеж снова открывается. Как можно это сделать?

Ответ:
Вы можете использовать средства серилизации .NET вашего класса в двоичный поток, а затем можно сохранить в кучу бинарных кусков. Вы можете сохранить в XData объекта или в Xrecord.Data примитива или в объект в Словаря Именованных Объектов (NOD). DevNote TS2563 рассказывает нам отличия в использовании XData и Xrecord. Если вы сохраняете в XData, тогда ResultBuffer должен начинаться с имени зарегистрированного приложения REGAPP. Вот пример, который это показывает:

Код - C#: [Выделить]
  1. using System;
  2. using System.Runtime.Serialization;
  3. using System.Runtime.Serialization.Formatters.Binary;
  4. using System.IO;
  5. using System.Security.Permissions;
  6.  
  7. using Autodesk.AutoCAD.Runtime;
  8. using acApp = Autodesk.AutoCAD.ApplicationServices.Application;
  9. using Autodesk.AutoCAD.DatabaseServices;
  10. using Autodesk.AutoCAD.EditorInput;
  11.  
  12. [assembly: CommandClass(typeof(MyClassSerializer.Commands))]
  13.  
  14. namespace MyClassSerializer
  15. {
  16.   // Нам нужна помощь с десерилизацией
  17.  
  18.   public sealed class MyBinder : SerializationBinder
  19.   {
  20.     public override System.Type BindToType(
  21.       string assemblyName,
  22.       string typeName)
  23.     {
  24.       return Type.GetType(string.Format("{0}, {1}",
  25.         typeName, assemblyName));
  26.     }
  27.   }
  28.  
  29.   // Вспомогательный класс для записи/чтения ResultBuffer
  30.  
  31.   public class MyUtil
  32.   {
  33.     const int kMaxChunkSize = 127;
  34.  
  35.     public static ResultBuffer StreamToResBuf(
  36.       MemoryStream ms, string appName)
  37.     {
  38.       ResultBuffer resBuf =
  39.         new ResultBuffer(
  40.           new TypedValue(
  41.             (int)DxfCode.ExtendedDataRegAppName, appName));
  42.  
  43.       for (int i = 0; i < ms.Length; i += kMaxChunkSize)
  44.       {
  45.         int length = (int)Math.Min(ms.Length - i, kMaxChunkSize);
  46.         byte[] datachunk = new byte[length];
  47.         ms.Read(datachunk, 0, length);
  48.         resBuf.Add(
  49.           new TypedValue(
  50.             (int)DxfCode.ExtendedDataBinaryChunk, datachunk));
  51.       }
  52.  
  53.       return resBuf;
  54.     }
  55.  
  56.     public static MemoryStream ResBufToStream(ResultBuffer resBuf)
  57.     {
  58.       MemoryStream ms = new MemoryStream();
  59.       TypedValue[] values = resBuf.AsArray();
  60.  
  61.       // Начинаем с 1 чтобы пропустить REGAPP
  62.  
  63.       for (int i = 1; i < values.Length; i++)
  64.       {
  65.         byte[] datachunk = (byte[])values[i].Value;
  66.         ms.Write(datachunk, 0, datachunk.Length);
  67.       }
  68.       ms.Position = 0;
  69.  
  70.       return ms;
  71.     }
  72.   }
  73.  
  74.   [Serializable]
  75.   public abstract class MyBaseClass : ISerializable
  76.   {
  77.     public const string appName = "MyApp";
  78.  
  79.     public MyBaseClass()
  80.     {
  81.     }
  82.  
  83.     public static object NewFromResBuf(ResultBuffer resBuf)
  84.     {
  85.       BinaryFormatter bf = new BinaryFormatter();
  86.       bf.Binder = new MyBinder();
  87.  
  88.       MemoryStream ms = MyUtil.ResBufToStream(resBuf);
  89.  
  90.       MyBaseClass mbc = (MyBaseClass)bf.Deserialize(ms);
  91.  
  92.       return mbc;
  93.     }
  94.  
  95.     public static object NewFromEntity(Entity ent)
  96.     {
  97.       using (
  98.         ResultBuffer resBuf = ent.GetXDataForApplication(appName))
  99.       {
  100.         return NewFromResBuf(resBuf);
  101.       }
  102.     }
  103.  
  104.     public ResultBuffer SaveToResBuf()
  105.     {
  106.       BinaryFormatter bf = new BinaryFormatter();
  107.       MemoryStream ms = new MemoryStream();
  108.       bf.Serialize(ms, this);
  109.       ms.Position = 0;
  110.  
  111.       ResultBuffer resBuf = MyUtil.StreamToResBuf(ms, appName);
  112.  
  113.       return resBuf;
  114.     }
  115.  
  116.     public void SaveToEntity(Entity ent)
  117.     {
  118.       // Вы должны быть уверены, что приложение зарегистрировано
  119.       // Если вы сохраняете ResultBuffer в Xrecord.Data,
  120.       // то приложение необязательно регистрировать
  121.  
  122.       Transaction tr =
  123.         ent.Database.TransactionManager.TopTransaction;
  124.  
  125.       RegAppTable regTable =
  126.         (RegAppTable)tr.GetObject(
  127.           ent.Database.RegAppTableId, OpenMode.ForWrite);
  128.       if (!regTable.Has(MyClass.appName))
  129.       {
  130.         RegAppTableRecord app = new RegAppTableRecord();
  131.         app.Name = MyClass.appName;
  132.         regTable.Add(app);
  133.         tr.AddNewlyCreatedDBObject(app, true);
  134.       }
  135.  
  136.       using (ResultBuffer resBuf = SaveToResBuf())
  137.       {
  138.         ent.XData = resBuf;
  139.       }
  140.     }
  141.  
  142.     [SecurityPermission(SecurityAction.LinkDemand,
  143.        Flags = SecurityPermissionFlag.SerializationFormatter)]
  144.     public abstract void GetObjectData(
  145.       SerializationInfo info, StreamingContext context);
  146.   }
  147.  
  148.   [Serializable]
  149.   public class MyClass : MyBaseClass
  150.   {
  151.     public string myString;
  152.     public double myDouble;
  153.  
  154.     public MyClass()
  155.     {
  156.     }
  157.  
  158.     protected MyClass(
  159.       SerializationInfo info, StreamingContext context)
  160.     {
  161.       if (info == null)
  162.         throw new System.ArgumentNullException("info");
  163.  
  164.       myString = (string)info.GetValue("MyString", typeof(string));
  165.       myDouble = (double)info.GetValue("MyDouble", typeof(double));
  166.     }
  167.  
  168.     [SecurityPermission(SecurityAction.LinkDemand,
  169.        Flags = SecurityPermissionFlag.SerializationFormatter)]
  170.     public override void GetObjectData(
  171.       SerializationInfo info, StreamingContext context)
  172.     {
  173.       info.AddValue("MyString", myString);
  174.       info.AddValue("MyDouble", myDouble);
  175.     }
  176.  
  177.     // Только для тестирования
  178.  
  179.     public override string ToString()
  180.     {
  181.       return base.ToString() + "," +
  182.         myString + "," + myDouble.ToString();
  183.     }
  184.   }
  185.  
  186.   public class Commands
  187.   {
  188.     [CommandMethod("SaveClassToEntityXData")]
  189.     static public void SaveClassToEntityXData()
  190.     {
  191.       Database db = acApp.DocumentManager.MdiActiveDocument.Database;
  192.       Editor ed = acApp.DocumentManager.MdiActiveDocument.Editor;
  193.  
  194.       PromptEntityResult per =
  195.         ed.GetEntity("Выберите примитив для сохранения класса:\n");
  196.       if (per.Status != PromptStatus.OK)
  197.         return;
  198.  
  199.       // Создаем объект
  200.  
  201.       MyClass mc = new MyClass();
  202.       mc.myDouble = 1.2345;
  203.       mc.myString = "Some text";
  204.  
  205.       // Сохраняем в документе
  206.  
  207.       using (
  208.         Transaction tr = db.TransactionManager.StartTransaction())
  209.       {
  210.         Entity ent =
  211.           (Entity)tr.GetObject(per.ObjectId, OpenMode.ForWrite);
  212.  
  213.         mc.SaveToEntity(ent);
  214.  
  215.         tr.Commit();
  216.       }
  217.  
  218.       // Напечатаем результаты
  219.  
  220.       ed.WriteMessage(
  221.         "Содержимое MyClass, который мы серилизовали:\n {0} \n", mc.ToString());
  222.     }
  223.  
  224.     [CommandMethod("GetClassFromEntityXData")]
  225.     static public void GetClassFromEntityXData()
  226.     {
  227.       Database db = acApp.DocumentManager.MdiActiveDocument.Database;
  228.       Editor ed = acApp.DocumentManager.MdiActiveDocument.Editor;
  229.  
  230.       PromptEntityResult per =
  231.         ed.GetEntity("Выберите примитив из которого получим класс:\n");
  232.       if (per.Status != PromptStatus.OK)
  233.         return;
  234.  
  235.       // Восстанавливаем класс
  236.  
  237.       using (
  238.         Transaction tr = db.TransactionManager.StartTransaction())
  239.       {
  240.         Entity ent =
  241.           (Entity)tr.GetObject(per.ObjectId, OpenMode.ForRead);
  242.  
  243.         MyClass mc = (MyClass)MyClass.NewFromEntity(ent);
  244.  
  245.         // Напечатаем результаты
  246.  
  247.         ed.WriteMessage(
  248.           "Содержимое класса MyClass десериализировано:\n {0} \n",
  249.           mc.ToString());
  250.  
  251.         tr.Commit();
  252.       }
  253.     }
  254.   }
  255. }

 

Источник: http://adndevblog.typepad.com/autocad/2012/05/serialize-a-net-class-into-an-autocad-drawing-database.html

Обсуждение: http://adn-cis.org/forum/index.php?topic=704

Опубликовано 28.04.2014