Создание и настройка динамических блоков в чертеже без его открытия

Автор Тема: Создание и настройка динамических блоков в чертеже без его открытия  (Прочитано 13501 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Всем хороших выходных!
Столкнулся с очередной проблемой. Приложение открывает существующие чертежи в фоне (создаю новую базу данных и читаю в нее чертеж), копирует в них определения динамических блоков из чертежа-шаблона и настраивает их динамические параметры. Так вот, если использовать обыкновенную транзакцию при работе с блоками, то блоки выглядят после этого "как надо". Но если обрабатывать блоки без транзакции, то при открытии обработанного чертежа можно увидеть такую картину: параметры блокам заданы, но их отображение не изменилось. Оно остается таким, как будто динамический блок только что вставили. При попытке изменить динпараметры, блок просто "разваливается". Казалось бы, никакой проблемы - используем транзакцию и радуемся. Но! При обработке больших чертежей, в какой-то случайный момент вываливается исключение System.AccessViolationException без указания места, в котором это исключение возникло. Без транзакции исключений не возникает, но и результат обработки не тот, что нужен. Как быть? Возможно ли такое, что нельзя в фоне работать с динамическими блоками?
Я пока вижу два решения:
Первое - открывать каждый обрабатываемый чертеж как документ. Это решило бы проблему, но время обработки увеличится очень сильно.
Второе - использовать AcCoreConsole. Но нет уверенности, что в нем не будет каких-то еще проблем.
Возможно, есть какое-то еще решение этой проблемы?

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Понял. Сделаю тестовый проект с примерами чертежей. Но уже не сегодня :)

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Вы не поверите... В тестовом проекте и чертеже все работает без проблем. Что с транзакцией, что с эмуляцией - динпараметры задаются корректно. Буду искать, где намудрил в рабочем проекте.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
А нет! Таки нашел сочетание сбойное! Оказывается, работу рушат атрибуты.
Как это выглядит:

Тестовый код:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Geometry;
  5. using Autodesk.AutoCAD.Runtime;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.IO;
  9. using System.Linq;
  10.  
  11. namespace AcadTest
  12. {
  13.     public class DynBlockTest
  14.     {
  15.         public static RXClass AttDefRXCLass = RXClass.GetClass(typeof(AttributeDefinition));
  16.  
  17.         static int counter = 0;        
  18.  
  19.         [CommandMethod("TestDynBlockBackgroundPaste")]
  20.         public void InsertAndSettings()
  21.         {
  22.             Document adoc = Application.DocumentManager.MdiActiveDocument;
  23.             Editor ed = adoc.Editor;
  24.             Database db = adoc.Database;
  25.  
  26.             PromptEntityOptions entOpts = new PromptEntityOptions("\nSelect dynamic block: ");
  27.             entOpts.SetRejectMessage("This is not block!");
  28.             entOpts.AddAllowedClass(typeof(BlockReference), true);
  29.  
  30.             PromptEntityResult entRes = ed.GetEntity(entOpts);
  31.             if (entRes.Status != PromptStatus.OK) return;
  32.  
  33.             ObjectId bTabRecId = ObjectId.Null;
  34.             Dictionary<string, object> blkDynProps = new Dictionary<string, object>();
  35.             Dictionary<string, string> attribs = new Dictionary<string, string>();
  36.  
  37.             using (Transaction tr = db.TransactionManager.StartTransaction())
  38.             {
  39.                 BlockReference bref = tr.GetObject
  40.                     (entRes.ObjectId, OpenMode.ForRead) as BlockReference;
  41.                 if (bref.IsDynamicBlock)
  42.                 {
  43.                     bTabRecId = bref.DynamicBlockTableRecord;
  44.                     foreach (DynamicBlockReferenceProperty dynProp
  45.                         in bref.DynamicBlockReferencePropertyCollection)
  46.                     {
  47.                         blkDynProps[dynProp.PropertyName] = dynProp.Value;
  48.                     }
  49.  
  50.                     foreach (ObjectId attRefId in bref.AttributeCollection)
  51.                     {
  52.                         AttributeReference attRef = tr.GetObject
  53.                             (attRefId, OpenMode.ForRead) as AttributeReference;
  54.                         attribs[attRef.Tag] = attRef.TextString;
  55.                     }
  56.                 }
  57.  
  58.                 tr.Commit();
  59.             }
  60.  
  61.             if (bTabRecId.IsNull || blkDynProps.Count == 0)
  62.             {
  63.                 ed.WriteMessage("\nBlock without dynamic props! Exit.");
  64.                 return;
  65.             }
  66.  
  67.             if (attribs.Count == 0)
  68.             {
  69.                 ed.WriteMessage("\nBlock without attribs! Exit.");
  70.                 return;
  71.             }
  72.  
  73.             string dir = Path.GetDirectoryName(adoc.Name);
  74.  
  75.             PromptSaveFileOptions saveFileOpt = new PromptSaveFileOptions("Drawing for save: ");
  76.             saveFileOpt.Filter = "Drawing (*.dwg)|*.dwg";
  77.             saveFileOpt.InitialDirectory = dir;
  78.             saveFileOpt.InitialFileName = $"DynBlkTarget{++counter}.dwg";
  79.             PromptFileNameResult saveFileRes = ed.GetFileNameForSave(saveFileOpt);
  80.  
  81.             //PromptOpenFileOptions openFileOpt = new PromptOpenFileOptions("Drawing for paste block: ");
  82.             //openFileOpt.Filter = "Drawing (*.dwg)|*.dwg";
  83.             //openFileOpt.InitialDirectory = dir;
  84.             //openFileOpt.InitialFileName = "DynBlkTarget.dwg";
  85.             //PromptFileNameResult openFileRes = ed.GetFileNameForOpen(openFileOpt);
  86.  
  87.             //string openFileName = openFileRes.StringResult;
  88.             string newFilePath =
  89.                 //Path.Combine
  90.                 //    (Path.GetDirectoryName(openFileName),
  91.                 //    Path.GetFileNameWithoutExtension(openFileName) + "1.dwg");
  92.                 saveFileRes.StringResult;
  93.  
  94.             PromptKeywordOptions keyOpts = new PromptKeywordOptions("\nUse transaction?");
  95.             keyOpts.Keywords.Add("Yes");
  96.             keyOpts.Keywords.Add("No");
  97.             keyOpts.Message += keyOpts.Keywords.GetDisplayString(true);
  98.  
  99.             PromptResult keyRes = ed.GetKeywords(keyOpts);
  100.             if (keyRes.Status != PromptStatus.OK) return;
  101.  
  102.             bool useTrans = keyRes.StringResult == "Yes";
  103.  
  104.             using (Database newDb = new Database(true, true))
  105.             {
  106.                 //newDb.ReadDwgFile(openFileName,
  107.                 //        FileOpenMode.OpenForReadAndAllShare, true, "");
  108.                 ObjectIdCollection ids = new ObjectIdCollection();
  109.                 ids.Add(bTabRecId);
  110.                 IdMapping mapping = new IdMapping();
  111.                 newDb.WblockCloneObjects(ids, newDb.BlockTableId,
  112.                     mapping, DuplicateRecordCloning.Replace, false);
  113.  
  114.                 ObjectId newBTabRecId = mapping[bTabRecId].Value;
  115.  
  116.                 Transaction tr = useTrans ?
  117.                     newDb.TransactionManager.StartTransaction()
  118.                     : newDb.TransactionManager.StartOpenCloseTransaction();
  119.  
  120.                 using (tr)
  121.                 {
  122.                     BlockReference blkRef = new BlockReference(Point3d.Origin, newBTabRecId);
  123.  
  124.                     ObjectId mSpaceId = SymbolUtilityServices.GetBlockModelSpaceId(newDb);
  125.                     BlockTableRecord mSpace = tr.GetObject
  126.                         (mSpaceId, OpenMode.ForWrite) as BlockTableRecord;
  127.                     mSpace.AppendEntity(blkRef);
  128.                     tr.AddNewlyCreatedDBObject(blkRef, true);
  129.  
  130.                     BlockTableRecord blkRec = tr.GetObject
  131.                         (newBTabRecId, OpenMode.ForRead) as BlockTableRecord;
  132.  
  133.                     foreach (ObjectId attDefId in blkRec)
  134.                     {
  135.                         if (!attDefId.ObjectClass.Equals(AttDefRXCLass)) continue;
  136.  
  137.                         AttributeDefinition attDef = tr.GetObject
  138.                             (attDefId, OpenMode.ForRead) as AttributeDefinition;
  139.  
  140.                         if (!attDef.Constant)
  141.                         {
  142.                             AttributeReference attRef = new AttributeReference();
  143.                             attRef.SetAttributeFromBlock(attDef, blkRef.BlockTransform);
  144.                             if (!attDef.HasFields
  145.                                 && attribs.ContainsKey(attDef.Tag))
  146.                             {
  147.                                 attRef.TextString = attribs[attDef.Tag];
  148.                             }
  149.                             blkRef.AttributeCollection.AppendAttribute(attRef);
  150.                             tr.AddNewlyCreatedDBObject(attRef, true);
  151.                         }
  152.  
  153.                     }
  154.  
  155.                     foreach (DynamicBlockReferenceProperty dynProp
  156.                         in blkRef.DynamicBlockReferencePropertyCollection)
  157.                     {
  158.                         KeyValuePair<string, object> propData = blkDynProps
  159.                             .FirstOrDefault(item => item.Key.Equals
  160.                             (dynProp.PropertyName, StringComparison.InvariantCultureIgnoreCase));
  161.                         if (propData.Value != null && dynProp.PropertyName != "Origin")
  162.                         {
  163.                             try
  164.                             {
  165.                                 dynProp.Value = propData.Value;
  166.                             }
  167.                             catch
  168.                             {
  169.  
  170.                             }
  171.                         }
  172.                     }
  173.  
  174.                     tr.Commit();
  175.                 }
  176.                 newDb.SaveAs(newFilePath, DwgVersion.Current);
  177.             }
  178.  
  179.             Document newDoc = Application.DocumentManager.Open(newFilePath, false);
  180.             Application.DocumentManager.MdiActiveDocument = newDoc;
  181.         }
  182.     }
  183. }
  184.  
Тестовый чертеж с блоком - во вложении

Отмечено как Решение Дмитрий Загорулькин 05-06-2017, 12:28:39

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Проверяй. Я когда-то тебе говорил, что особенность использования Open/Close и отличие от транзакции в том, что следует побыстрее закрывать неиспользованные объекты.
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Geometry;
  5. using Autodesk.AutoCAD.Runtime;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.IO;
  9. using System.Linq;
  10.  
  11. #pragma warning disable 0618
  12.  
  13. namespace AcadTest
  14. {
  15.   public class DynBlockTest
  16.   {
  17.     public static RXClass AttDefRXCLass = RXClass.GetClass(typeof(AttributeDefinition));
  18.  
  19.     static int counter = 0;
  20.  
  21.     [CommandMethod("TestDynBlockBackgroundPaste")]
  22.     public void InsertAndSettings()
  23.     {
  24.       Document adoc = Application.DocumentManager.MdiActiveDocument;
  25.       Editor ed = adoc.Editor;
  26.       Database db = adoc.Database;
  27.  
  28.       PromptEntityOptions entOpts = new PromptEntityOptions("\nSelect dynamic block: ");
  29.       entOpts.SetRejectMessage("This is not block!");
  30.       entOpts.AddAllowedClass(typeof(BlockReference), true);
  31.  
  32.       PromptEntityResult entRes = ed.GetEntity(entOpts);
  33.       if (entRes.Status != PromptStatus.OK) return;
  34.  
  35.       ObjectId bTabRecId = ObjectId.Null;
  36.       Dictionary<string, object> blkDynProps = new Dictionary<string, object>();
  37.       Dictionary<string, string> attribs = new Dictionary<string, string>();
  38.  
  39.       using (Transaction tr = db.TransactionManager.StartTransaction())
  40.       {
  41.         BlockReference bref = tr.GetObject
  42.             (entRes.ObjectId, OpenMode.ForRead) as BlockReference;
  43.         if (bref.IsDynamicBlock)
  44.         {
  45.           bTabRecId = bref.DynamicBlockTableRecord;
  46.           foreach (DynamicBlockReferenceProperty dynProp
  47.               in bref.DynamicBlockReferencePropertyCollection)
  48.           {
  49.             blkDynProps[dynProp.PropertyName] = dynProp.Value;
  50.           }
  51.  
  52.           foreach (ObjectId attRefId in bref.AttributeCollection)
  53.           {
  54.             AttributeReference attRef = tr.GetObject
  55.                 (attRefId, OpenMode.ForRead) as AttributeReference;
  56.             attribs[attRef.Tag] = attRef.TextString;
  57.           }
  58.         }
  59.  
  60.         tr.Commit();
  61.       }
  62.  
  63.       if (bTabRecId.IsNull || blkDynProps.Count == 0)
  64.       {
  65.         ed.WriteMessage("\nBlock without dynamic props! Exit.");
  66.         return;
  67.       }
  68.  
  69.       if (attribs.Count == 0)
  70.       {
  71.         ed.WriteMessage("\nBlock without attribs! Exit.");
  72.         return;
  73.       }
  74.  
  75.       string dir = Path.GetDirectoryName(adoc.Name);
  76.  
  77.       PromptSaveFileOptions saveFileOpt = new PromptSaveFileOptions("Drawing for save: ");
  78.       saveFileOpt.Filter = "Drawing (*.dwg)|*.dwg";
  79.       saveFileOpt.InitialDirectory = dir;
  80.       saveFileOpt.InitialFileName = $"DynBlkTarget{++counter}.dwg";
  81.       PromptFileNameResult saveFileRes = ed.GetFileNameForSave(saveFileOpt);
  82.  
  83.       //PromptOpenFileOptions openFileOpt = new PromptOpenFileOptions("Drawing for paste block: ");
  84.       //openFileOpt.Filter = "Drawing (*.dwg)|*.dwg";
  85.       //openFileOpt.InitialDirectory = dir;
  86.       //openFileOpt.InitialFileName = "DynBlkTarget.dwg";
  87.       //PromptFileNameResult openFileRes = ed.GetFileNameForOpen(openFileOpt);
  88.  
  89.       //string openFileName = openFileRes.StringResult;
  90.       string newFilePath =
  91.           //Path.Combine
  92.           //    (Path.GetDirectoryName(openFileName),
  93.           //    Path.GetFileNameWithoutExtension(openFileName) + "1.dwg");
  94.           saveFileRes.StringResult;
  95.  
  96.       PromptKeywordOptions keyOpts = new PromptKeywordOptions("\nUse transaction?");
  97.       keyOpts.Keywords.Add("Yes");
  98.       keyOpts.Keywords.Add("No");
  99.       keyOpts.Message += keyOpts.Keywords.GetDisplayString(true);
  100.  
  101.       PromptResult keyRes = ed.GetKeywords(keyOpts);
  102.       if (keyRes.Status != PromptStatus.OK) return;
  103.  
  104.       bool useTrans = keyRes.StringResult == "Yes";
  105.       // Database oldDb = HostApplicationServices.WorkingDatabase;
  106.       using (Database newDb = new Database(true, false))
  107.       {
  108.         // HostApplicationServices.WorkingDatabase = newDb;
  109.         //newDb.ReadDwgFile(openFileName,
  110.         //        FileOpenMode.OpenForReadAndAllShare, true, "");
  111.         ObjectIdCollection ids = new ObjectIdCollection();
  112.         ids.Add(bTabRecId);
  113.         IdMapping mapping = new IdMapping();
  114.         newDb.WblockCloneObjects(ids, newDb.BlockTableId,
  115.             mapping, DuplicateRecordCloning.Replace, false);
  116.  
  117.         ObjectId newBTabRecId = mapping[bTabRecId].Value;
  118.  
  119.         Transaction tr = useTrans ?
  120.             newDb.TransactionManager.StartTransaction()
  121.             : newDb.TransactionManager.StartOpenCloseTransaction();
  122.  
  123.         using (tr)
  124.         {
  125.           BlockReference blkRef = new BlockReference(Point3d.Origin, newBTabRecId);
  126.  
  127.           ObjectId mSpaceId = SymbolUtilityServices.GetBlockModelSpaceId(newDb);
  128.           BlockTableRecord mSpace = tr.GetObject
  129.               (mSpaceId, OpenMode.ForWrite) as BlockTableRecord;
  130.           mSpace.AppendEntity(blkRef);
  131.           tr.AddNewlyCreatedDBObject(blkRef, true);
  132.  
  133.           BlockTableRecord blkRec = tr.GetObject
  134.               (newBTabRecId, OpenMode.ForRead) as BlockTableRecord;
  135.  
  136.           foreach (ObjectId attDefId in blkRec)
  137.           {
  138.             if (!attDefId.ObjectClass.Equals(AttDefRXCLass)) continue;
  139.  
  140.             AttributeDefinition attDef = tr.GetObject
  141.                 (attDefId, OpenMode.ForRead) as AttributeDefinition;
  142.  
  143.             if (!attDef.Constant)
  144.             {
  145.               AttributeReference attRef = new AttributeReference();
  146.               attRef.SetAttributeFromBlock(attDef, blkRef.BlockTransform);
  147.               if (!attDef.HasFields
  148.                   && attribs.ContainsKey(attDef.Tag))
  149.               {
  150.                 attRef.TextString = attribs[attDef.Tag];
  151.               }
  152.               blkRef.AttributeCollection.AppendAttribute(attRef);
  153.               tr.AddNewlyCreatedDBObject(attRef, true);
  154.               // Атрибут должен быть закрыт перед
  155.               // присвоением динамических свойств блоку
  156.               if (!useTrans) attRef.Close();
  157.  
  158.             }
  159.           }
  160.  
  161.           // BlockTableRecord нашего блока должна быть закрыта
  162.           // перед присвоением динамических свойств блоку
  163.           if (!useTrans) blkRec.Close();
  164.  
  165.           DynamicBlockReferencePropertyCollection dynProps =
  166.             blkRef.DynamicBlockReferencePropertyCollection;
  167.  
  168.           foreach (DynamicBlockReferenceProperty dynProp in dynProps)
  169.           {
  170.             KeyValuePair<string, object> propData = blkDynProps
  171.                 .FirstOrDefault(item => item.Key.Equals
  172.                 (dynProp.PropertyName, StringComparison.InvariantCultureIgnoreCase));
  173.             if (propData.Value != null && dynProp.PropertyName != "Origin")
  174.             {
  175.               try
  176.               {
  177.                 dynProp.Value = propData.Value;
  178.               }
  179.               catch (System.Exception ex)
  180.               {
  181.                 Application.DocumentManager.MdiActiveDocument.
  182.                   Editor.WriteMessage("\n{0}", ex);
  183.               }
  184.             }
  185.           }
  186.  
  187.           tr.Commit();
  188.         }
  189.         newDb.SaveAs(newFilePath, DwgVersion.Current);
  190.       }
  191.       // HostApplicationServices.WorkingDatabase = oldDb;
  192.  
  193.       Document newDoc = Application.DocumentManager.Open(newFilePath, false);
  194.       Application.DocumentManager.MdiActiveDocument = newDoc;
  195.     }
  196.   }
  197. }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Проверил - все отлично работает! Спасибо!

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Словил еще две проблемы с атрибутами.
Первая - если в значение по умолчанию атрибута вставлено поле, ссылающееся на значение динпараметра этого блока (оказывается, и так можно делать! :o), то в результате работы кода в атрибуте вместо значения будут решетки. Как это выглядит:

Причем, без разницы как делать - с транзакцией или без нее. Результат от этого не меняется.
Поборол это таким способом: после вставки блока и задания ему динсвойств и атрибутов, повторно, для каждого атрибута с полем выполняю метод AttributeReference.SetAttributeFromBlock(AttributeDefinition, Matrix3d). Возможно, что тут по-другому никак.
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Geometry;
  5. using Autodesk.AutoCAD.Runtime;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.IO;
  9. using System.Linq;
  10.  
  11. #pragma warning disable 0618
  12.  
  13. namespace AcadTest
  14. {
  15.     public class DynBlockTest
  16.     {
  17.         public static RXClass AttDefRXCLass = RXClass.GetClass(typeof(AttributeDefinition));
  18.  
  19.         static int counter = 0;
  20.  
  21.         [CommandMethod("TestDynBlockBackgroundPaste1")]
  22.         public void InsertAndSettings()
  23.         {
  24.             Document adoc = Application.DocumentManager.MdiActiveDocument;
  25.             Editor ed = adoc.Editor;
  26.             Database db = adoc.Database;
  27.  
  28.             PromptEntityOptions entOpts = new PromptEntityOptions("\nSelect dynamic block: ");
  29.             entOpts.SetRejectMessage("This is not block!");
  30.             entOpts.AddAllowedClass(typeof(BlockReference), true);
  31.  
  32.             PromptEntityResult entRes = ed.GetEntity(entOpts);
  33.             if (entRes.Status != PromptStatus.OK) return;
  34.  
  35.             ObjectId bTabRecId = ObjectId.Null;
  36.             Dictionary<string, object> blkDynProps = new Dictionary<string, object>();
  37.             Dictionary<string, string> attribs = new Dictionary<string, string>();
  38.  
  39.             using (Transaction tr = db.TransactionManager.StartTransaction())
  40.             {
  41.                 BlockReference bref = tr.GetObject
  42.                     (entRes.ObjectId, OpenMode.ForRead) as BlockReference;
  43.                 if (bref.IsDynamicBlock)
  44.                 {
  45.                     bTabRecId = bref.DynamicBlockTableRecord;
  46.                     foreach (DynamicBlockReferenceProperty dynProp
  47.                         in bref.DynamicBlockReferencePropertyCollection)
  48.                     {
  49.                         blkDynProps[dynProp.PropertyName] = dynProp.Value;
  50.                     }
  51.  
  52.                     foreach (ObjectId attRefId in bref.AttributeCollection)
  53.                     {
  54.                         AttributeReference attRef = tr.GetObject
  55.                             (attRefId, OpenMode.ForRead) as AttributeReference;
  56.                         attribs[attRef.Tag] = attRef.TextString;
  57.                     }
  58.                 }
  59.  
  60.                 tr.Commit();
  61.             }
  62.  
  63.             if (bTabRecId.IsNull || blkDynProps.Count == 0)
  64.             {
  65.                 ed.WriteMessage("\nBlock without dynamic props! Exit.");
  66.                 return;
  67.             }
  68.  
  69.             if (attribs.Count == 0)
  70.             {
  71.                 ed.WriteMessage("\nBlock without attribs! Exit.");
  72.                 return;
  73.             }
  74.  
  75.             string dir = Path.GetDirectoryName(adoc.Name);
  76.  
  77.             PromptSaveFileOptions saveFileOpt = new PromptSaveFileOptions("Drawing for save: ");
  78.             saveFileOpt.Filter = "Drawing (*.dwg)|*.dwg";
  79.             saveFileOpt.InitialDirectory = dir;
  80.             saveFileOpt.InitialFileName = $"DynBlkTarget{++counter}.dwg";
  81.             PromptFileNameResult saveFileRes = ed.GetFileNameForSave(saveFileOpt);
  82.             string newFilePath = saveFileRes.StringResult;
  83.  
  84.             PromptKeywordOptions keyOpts = new PromptKeywordOptions("\nUse transaction?");
  85.             keyOpts.Keywords.Add("Yes");
  86.             keyOpts.Keywords.Add("No");
  87.             keyOpts.Message += keyOpts.Keywords.GetDisplayString(true);
  88.  
  89.             PromptResult keyRes = ed.GetKeywords(keyOpts);
  90.             if (keyRes.Status != PromptStatus.OK) return;
  91.  
  92.             bool useTrans = keyRes.StringResult == "Yes";
  93.             using (Database newDb = new Database(true, false))
  94.             {
  95.                 ObjectIdCollection ids = new ObjectIdCollection();
  96.                 ids.Add(bTabRecId);
  97.                 IdMapping mapping = new IdMapping();
  98.                 newDb.WblockCloneObjects(ids, newDb.BlockTableId,
  99.                     mapping, DuplicateRecordCloning.Replace, false);
  100.  
  101.                 ObjectId newBTabRecId = mapping[bTabRecId].Value;
  102.  
  103.                 Transaction tr = useTrans ?
  104.                     newDb.TransactionManager.StartTransaction()
  105.                     : newDb.TransactionManager.StartOpenCloseTransaction();
  106.  
  107.                 ObjectId bRefId;
  108.  
  109.                 using (tr)
  110.                 {
  111.                     BlockReference blkRef = new BlockReference(Point3d.Origin, newBTabRecId);
  112.  
  113.                     ObjectId mSpaceId = SymbolUtilityServices.GetBlockModelSpaceId(newDb);
  114.                     BlockTableRecord mSpace = tr.GetObject
  115.                         (mSpaceId, OpenMode.ForWrite) as BlockTableRecord;
  116.                     bRefId = mSpace.AppendEntity(blkRef);
  117.                     tr.AddNewlyCreatedDBObject(blkRef, true);
  118.  
  119.                     BlockTableRecord blkRec = tr.GetObject
  120.                         (newBTabRecId, OpenMode.ForRead) as BlockTableRecord;
  121.  
  122.                     foreach (ObjectId attDefId in blkRec)
  123.                     {
  124.                         if (!attDefId.ObjectClass.Equals(AttDefRXCLass)) continue;
  125.  
  126.                         AttributeDefinition attDef = tr.GetObject
  127.                             (attDefId, OpenMode.ForRead) as AttributeDefinition;
  128.  
  129.                         if (!attDef.Constant)
  130.                         {
  131.                             AttributeReference attRef = new AttributeReference();
  132.                             attRef.SetAttributeFromBlock(attDef, blkRef.BlockTransform);
  133.                             if (!attDef.HasFields
  134.                                 && attribs.ContainsKey(attDef.Tag))
  135.                             {
  136.                                 attRef.TextString = attribs[attDef.Tag];
  137.                             }
  138.                             blkRef.AttributeCollection.AppendAttribute(attRef);
  139.                             tr.AddNewlyCreatedDBObject(attRef, true);
  140.                             // Атрибут должен быть закрыт перед
  141.                             // присвоением динамических свойств блоку
  142.                             if (!useTrans) attRef.Close();
  143.  
  144.                         }
  145.                     }
  146.  
  147.                     // BlockTableRecord нашего блока должна быть закрыта
  148.                     // перед присвоением динамических свойств блоку
  149.                     if (!useTrans) blkRec.Close();
  150.  
  151.                     DynamicBlockReferencePropertyCollection dynProps =
  152.                       blkRef.DynamicBlockReferencePropertyCollection;
  153.  
  154.                     foreach (DynamicBlockReferenceProperty dynProp in dynProps)
  155.                     {
  156.                         KeyValuePair<string, object> propData = blkDynProps
  157.                             .FirstOrDefault(item => item.Key.Equals
  158.                             (dynProp.PropertyName, StringComparison.InvariantCultureIgnoreCase));
  159.                         if (propData.Value != null && dynProp.PropertyName != "Origin")
  160.                         {
  161.                             try
  162.                             {
  163.                                 dynProp.Value = propData.Value;
  164.                             }
  165.                             catch (System.Exception ex)
  166.                             {
  167.                                 Application.DocumentManager.MdiActiveDocument.
  168.                                   Editor.WriteMessage("\n{0}", ex);
  169.                             }
  170.                         }
  171.                     }
  172.  
  173.                     tr.Commit();
  174.                 }
  175.  
  176.                 // Дополнительная обработка атрибутов, ссылающихся
  177.                 // полем на значения динпараметров блока
  178.  
  179.                 ObjectId bTabRecId1;
  180.                 ObjectId[] attRefIds;
  181.                 Matrix3d blkTransform;
  182.  
  183.                 using (BlockReference blkRef = bRefId.Open(OpenMode.ForRead) as BlockReference)
  184.                 {
  185.                     bTabRecId1 = blkRef.BlockTableRecord;
  186.                     attRefIds = blkRef.AttributeCollection.Cast<ObjectId>().ToArray();
  187.                     blkTransform = blkRef.BlockTransform;
  188.                 }
  189.  
  190.                 Dictionary<string, ObjectId> attDefDict = new Dictionary<string, ObjectId>();
  191.  
  192.                 using (BlockTableRecord blkTabRec = bTabRecId1.Open(OpenMode.ForRead) as BlockTableRecord)
  193.                 {
  194.                     ObjectId[] attDefIds = blkTabRec.Cast<ObjectId>().Where(id => id.ObjectClass.Equals(AttDefRXCLass)).ToArray();
  195.                     foreach (ObjectId attDefId in attDefIds)
  196.                     {
  197.                         using (AttributeDefinition attDef = attDefId.Open(OpenMode.ForRead) as AttributeDefinition)
  198.                         {
  199.                             attDefDict[attDef.Tag] = attDefId;
  200.                         }
  201.                     }
  202.                 }
  203.  
  204.                 foreach (ObjectId attRefId in attRefIds)
  205.                 {
  206.                     using (AttributeReference attRef = attRefId.Open(OpenMode.ForRead) as AttributeReference)
  207.                     {
  208.                         if (attRef.HasFields && attDefDict.ContainsKey(attRef.Tag))
  209.                         {
  210.                             using (AttributeDefinition attDef = attDefDict[attRef.Tag].Open(OpenMode.ForRead) as AttributeDefinition)
  211.                             {
  212.                                 attRef.UpgradeOpen();
  213.                                 attRef.SetAttributeFromBlock(attDef, blkTransform);
  214.                                 attRef.DowngradeOpen();
  215.                             }
  216.                         }
  217.                     }
  218.                 }
  219.  
  220.                 newDb.SaveAs(newFilePath, DwgVersion.Current);
  221.             }
  222.  
  223.             Document newDoc = Application.DocumentManager.Open(newFilePath, false);
  224.             Application.DocumentManager.MdiActiveDocument = newDoc;
  225.         }
  226.     }
  227. }
  228.  
А вот вторую проблему никак не победить пока. Один-единственный атрибут реального, не тестового блока (их там с полтора десятка) после экспорта в другой чертеж "уползает" то влево, то вправо. И, что самое обидное, никак не получается воспроизвести это поведение на тестовом блоке.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Получилось создать тестовый блок, на котором воспроизводится проблема №2 из предыдущего сообщения.
Видео:

Никак не получается одолеть эту напасть. Может быть, у вас будут какие-нибудь идеи?

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
В итоге, Google и Kean Walmsley помогли решить этот вопрос. Ответ тут, под заголовком "Update 2": http://through-the-interface.typepad.com/through_the_interface/2007/07/updating-a-sp-1.html?cid=6a00d83452464869e2010536eec215970b:
Цитировать
The above code does not realign attributes after editing their values: if your attributes are anything other than left-justified, you will need to make a call to AdjustAlignment on the attribute reference after editing it.
There's a trick to this: you need to make sure the working database is set to the drawing you're working on, as well as passing it as an argument to the function.
You could set the working database early in the code, or insert this code to do it locally (the choice is yours):
Код - C# [Выбрать]
  1.   ar.TextString = attbValue;
  2.   // Begin alignment code
  3.   Database wdb = HostApplicationServices.WorkingDatabase;
  4.   HostApplicationServices.WorkingDatabase = db;
  5.   ar.AdjustAlignment(db);
  6.   HostApplicationServices.WorkingDatabase = wdb;
  7.   // End alignment code
  8.   ar.DowngradeOpen();
I've left the line before and the line after in the above snippet, so it should be clear where the code needs inserting.
« Последнее редактирование: 11-07-2019, 17:40:26 от Дмитрий Загорулькин »

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
В итоге, Google и Kean Walmsley помогли решить этот вопрос. Ответ тут, под заголовком "Update 2": http://through-the-interface.typepad.com/through_the_interface/2007/07/updating-a-sp-1.html?cid=6a00d83452464869e2010536eec215970b
А ведь мы это когда-то на форуме обсуждали. Это касается не только атрибутов, но и текстов, размеров и т.д.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 611
  • Карма: 155
    • ПГСу Бложик
По совету Димы (https://adn-cis.org/forum/index.php?topic=9225.msg48021#msg48021 ), посмотрел эту тему.
Взял код из 7 сообщения и слегка доработал напильником, убрав атрибуты, в блоках с которыми я работаю их нет.

Собственно вот код:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Geometry;
  5. using Autodesk.AutoCAD.Runtime;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.IO;
  9. using System.Linq;
  10.  
  11. #pragma warning disable 0618
  12.  
  13. namespace ADN_DZ_BlockCopy
  14. {
  15.   public class DynBlockTest
  16.   {
  17.     static int counter = 0;
  18.  
  19.     [CommandMethod("xxx")]
  20.     public void InsertAndSettings()
  21.     {
  22.       Document adoc = Application.DocumentManager.MdiActiveDocument;
  23.       Editor ed = adoc.Editor;
  24.       Database db = adoc.Database;
  25.  
  26.       PromptEntityOptions entOpts = new PromptEntityOptions("\nSelect dynamic block: ");
  27.       entOpts.SetRejectMessage("This is not block!");
  28.       entOpts.AddAllowedClass(typeof(BlockReference), true);
  29.  
  30.       PromptEntityResult entRes = ed.GetEntity(entOpts);
  31.       if (entRes.Status != PromptStatus.OK) return;
  32.  
  33.       ObjectId bTabRecId = ObjectId.Null;
  34.       Dictionary<string, object> blkDynProps = new Dictionary<string, object>();
  35.       Dictionary<string, string> attribs = new Dictionary<string, string>();
  36.  
  37.       using (Transaction tr = db.TransactionManager.StartTransaction())
  38.       {
  39.         BlockReference bref = tr.GetObject
  40.             (entRes.ObjectId, OpenMode.ForRead) as BlockReference;
  41.         if (bref.IsDynamicBlock)
  42.         {
  43.           bTabRecId = bref.DynamicBlockTableRecord;
  44.           foreach (DynamicBlockReferenceProperty dynProp
  45.               in bref.DynamicBlockReferencePropertyCollection)
  46.           {
  47.             blkDynProps[dynProp.PropertyName] = dynProp.Value;
  48.           }
  49.         }
  50.         tr.Commit();
  51.       }
  52.  
  53.       if (bTabRecId.IsNull || blkDynProps.Count == 0)
  54.       {
  55.         ed.WriteMessage("\nBlock without dynamic props! Exit.");
  56.         return;
  57.       }
  58.  
  59.       string dir = Path.GetDirectoryName(adoc.Name);
  60.  
  61.       PromptSaveFileOptions saveFileOpt = new PromptSaveFileOptions("Drawing for save: ");
  62.       saveFileOpt.Filter = "Drawing (*.dwg)|*.dwg";
  63.       saveFileOpt.InitialDirectory = dir;
  64.       saveFileOpt.InitialFileName = $"DynBlkTarget{++counter}.dwg";
  65.       PromptFileNameResult saveFileRes = ed.GetFileNameForSave(saveFileOpt);
  66.       string newFilePath = saveFileRes.StringResult;
  67.  
  68.       PromptKeywordOptions keyOpts = new PromptKeywordOptions("\nUse transaction?");
  69.       keyOpts.Keywords.Add("Yes");
  70.       keyOpts.Keywords.Add("No");
  71.       keyOpts.Message += keyOpts.Keywords.GetDisplayString(true);
  72.  
  73.       PromptResult keyRes = ed.GetKeywords(keyOpts);
  74.       if (keyRes.Status != PromptStatus.OK) return;
  75.  
  76.       bool useTrans = keyRes.StringResult == "Yes";
  77.       using (Database newDb = new Database(true, false))
  78.       {
  79.         ObjectIdCollection ids = new ObjectIdCollection();
  80.         ids.Add(bTabRecId);
  81.         IdMapping mapping = new IdMapping();
  82.         newDb.WblockCloneObjects(ids, newDb.BlockTableId,
  83.             mapping, DuplicateRecordCloning.Replace, false);
  84.  
  85.         ObjectId newBTabRecId = mapping[bTabRecId].Value;
  86.  
  87.         Transaction tr = useTrans ?
  88.             newDb.TransactionManager.StartTransaction()
  89.             : newDb.TransactionManager.StartOpenCloseTransaction();
  90.  
  91.         ObjectId bRefId;
  92.  
  93.         using (tr)
  94.         {
  95.           BlockReference blkRef = new BlockReference(Point3d.Origin, newBTabRecId);
  96.  
  97.           ObjectId mSpaceId = SymbolUtilityServices.GetBlockModelSpaceId(newDb);
  98.           BlockTableRecord mSpace = tr.GetObject
  99.               (mSpaceId, OpenMode.ForWrite) as BlockTableRecord;
  100.           bRefId = mSpace.AppendEntity(blkRef);
  101.           tr.AddNewlyCreatedDBObject(blkRef, true);
  102.  
  103.           BlockTableRecord blkRec = tr.GetObject
  104.               (newBTabRecId, OpenMode.ForRead) as BlockTableRecord;
  105.  
  106.           // BlockTableRecord нашего блока должна быть закрыта
  107.           // перед присвоением динамических свойств блоку
  108.           if (!useTrans) blkRec.Close();
  109.  
  110.           DynamicBlockReferencePropertyCollection dynProps =
  111.             blkRef.DynamicBlockReferencePropertyCollection;
  112.  
  113.           foreach (DynamicBlockReferenceProperty dynProp in dynProps)
  114.           {
  115.             KeyValuePair<string, object> propData = blkDynProps
  116.                 .FirstOrDefault(item => item.Key.Equals
  117.                 (dynProp.PropertyName, StringComparison.InvariantCultureIgnoreCase));
  118.             if (propData.Value != null && dynProp.PropertyName != "Origin")
  119.             {
  120.               try
  121.               {
  122.                 dynProp.Value = propData.Value;
  123.               }
  124.               catch (System.Exception ex)
  125.               {
  126.                 Application.DocumentManager.MdiActiveDocument.
  127.                   Editor.WriteMessage("\n{0}", ex);
  128.               }
  129.             }
  130.           }
  131.           tr.Commit();
  132.         }
  133.         newDb.SaveAs(newFilePath, DwgVersion.Current);
  134.       }
  135.       Document newDoc = Application.DocumentManager.Open(newFilePath, false);
  136.       Application.DocumentManager.MdiActiveDocument = newDoc;
  137.     }
  138.   }
  139. }

Во вложение файл с несколькими блоками. Существенного отличия в блоках я не вижу.
Если попытаться с помощью кода скопировать любой блок под зеленым текстом, то все копируется.
Если попытаться скопировать блок под красным текстом, автокад падает.

Если блок под красным текстом ресетнуть и динамические свойства не трогать, то блок нормально копируется.
Если блок под красным текстом ресетнуть и изменить только дин. св-во "k", то блок нормально копируется.
Если блок под красным текстом ресетнуть и изменить любое дин. св-во, кроме "k", то автокад падает.

Собственно вопрос, что не так с этим блоком и как поменять код, что бы автокад не падал?
Код падает и на ADT 2017 и по отзыву пользователя на чистом 2021 автокаде так же падает.

ЗЫ.
Собственно из-за этого блока и не работал Прогресс бар в указанной выше теме.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
А если вот такой метод попробовать? https://adn-cis.org/forum/index.php?topic=9353.msg39241#msg39241
Это сейчас мой основной по вставке блоков, пока сбоев вроде не давал.

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 611
  • Карма: 155
    • ПГСу Бложик
Это сейчас мой основной по вставке блоков, пока сбоев вроде не давал.
Увы. Вот код с помощью которого вызываю метод CreateBlockReference() (строчки 60, 61), поведение точно такое же, на красном падает.
Код - C# [Выбрать]
  1. static int counter = 0;
  2.     [CommandMethod("zzz")]
  3.     public void InsertAndSettingsZZZ()
  4.     {
  5.       Document adoc = Application.DocumentManager.MdiActiveDocument;
  6.       Editor ed = adoc.Editor;
  7.       Database db = adoc.Database;
  8.  
  9.       PromptEntityOptions entOpts = new PromptEntityOptions("\nSelect dynamic block: ");
  10.       entOpts.SetRejectMessage("This is not block!");
  11.       entOpts.AddAllowedClass(typeof(BlockReference), true);
  12.  
  13.       PromptEntityResult entRes = ed.GetEntity(entOpts);
  14.       if (entRes.Status != PromptStatus.OK) return;
  15.  
  16.       ObjectId bTabRecId = ObjectId.Null;
  17.       Dictionary<string, object> blkDynProps = new Dictionary<string, object>();
  18.       Dictionary<string, string> attribs = new Dictionary<string, string>();
  19.  
  20.       using (Transaction tr = db.TransactionManager.StartTransaction())
  21.       {
  22.         BlockReference bref = tr.GetObject
  23.             (entRes.ObjectId, OpenMode.ForRead) as BlockReference;
  24.         if (bref.IsDynamicBlock)
  25.         {
  26.           bTabRecId = bref.DynamicBlockTableRecord;
  27.           foreach (DynamicBlockReferenceProperty dynProp
  28.               in bref.DynamicBlockReferencePropertyCollection)
  29.           {
  30.             blkDynProps[dynProp.PropertyName] = dynProp.Value;
  31.           }
  32.         }
  33.         tr.Commit();
  34.       }
  35.  
  36.       if (bTabRecId.IsNull || blkDynProps.Count == 0)
  37.       {
  38.         ed.WriteMessage("\nBlock without dynamic props! Exit.");
  39.         return;
  40.       }
  41.  
  42.       string dir = Path.GetDirectoryName(adoc.Name);
  43.       PromptSaveFileOptions saveFileOpt = new PromptSaveFileOptions("Drawing for save: ");
  44.       saveFileOpt.Filter = "Drawing (*.dwg)|*.dwg";
  45.       saveFileOpt.InitialDirectory = dir;
  46.       saveFileOpt.InitialFileName = $"DynBlkTarget{++counter}.dwg";
  47.       PromptFileNameResult saveFileRes = ed.GetFileNameForSave(saveFileOpt);
  48.       string newFilePath = saveFileRes.StringResult;
  49.  
  50.       using (Database newDb = new Database(true, false))
  51.       {
  52.         ObjectIdCollection ids = new ObjectIdCollection();
  53.         ids.Add(bTabRecId);
  54.         IdMapping mapping = new IdMapping();
  55.         newDb.WblockCloneObjects(ids, newDb.BlockTableId,
  56.             mapping, DuplicateRecordCloning.Replace, false);
  57.  
  58.         ObjectId newBTabRecId = mapping[bTabRecId].Value;
  59.  
  60.         var bRefId = Class2.CreateBlockReference(Point3d.Origin,
  61.           newBTabRecId, newDb.CurrentSpaceId, newDb.LayerZero, 1, blkDynProps, attribs);
  62.  
  63.         newDb.SaveAs(newFilePath, DwgVersion.Current);
  64.       }
  65.       Document newDoc = Application.DocumentManager.Open(newFilePath, false);
  66.       Application.DocumentManager.MdiActiveDocument = newDoc;
  67.     }

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Хм... Есть подозрение, что проблема где-то в передаче определения блока в новую базу. Попробую вечером поковырять.