Не отображаются значения полей в атрибутах, которые ссылаются на параметры блока

Автор Тема: Не отображаются значения полей в атрибутах, которые ссылаются на параметры блока  (Прочитано 14956 раз)

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

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

Оффлайн dmitrymaslakovАвтор темы

  • ADN OPEN
  • Сообщений: 40
  • Карма: 1
Есть блок с множеством пользовательских параметров, сведенных в таблицу свойств. И есть атрибуты этого блока, значения которых формируются с использованием полей, ссылающиеся на параметры. Создаю программно BlockReference, вставляю в чертеж и после обновления полей я вижу решетки вместо желаемых значений

Код вставки блока:
Код - C# [Выбрать]
  1.                 using (Transaction tr = db.TransactionManager.StartTransaction()) {
  2.                     BlockTable blockTable = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
  3.                     BlockTableRecord lumDef = tr.GetObject(blockTable[blockName], OpenMode.ForRead) as BlockTableRecord;
  4.                     BlockTableRecord modelSpace = tr.GetObject(modelSpaceId, OpenMode.ForWrite) as BlockTableRecord;
  5.  
  6.                     BlockReference lumRef = new BlockReference(insertPoint, lumDef.Id);
  7.                     modelSpace.AppendEntity(lumRef);
  8.                     tr.AddNewlyCreatedDBObject(lumRef, true);
  9.  
  10.                     foreach (ObjectId id in lumDef) {
  11.                         AttributeDefinition attDef = id.GetObject(OpenMode.ForRead) as AttributeDefinition;
  12.                         if (attDef != null && !attDef.Constant) {
  13.                             AttributeReference attRef = new AttributeReference();
  14.                             attRef.SetAttributeFromBlock(attDef, lumRef.BlockTransform);
  15.                             lumRef.AttributeCollection.AppendAttribute(attRef);
  16.                             tr.AddNewlyCreatedDBObject(attRef, true);
  17.                         }
  18.                     }
  19.                     db.EvaluateFields();
  20.                     tr.Commit();
  21.                 }
  22.  
 

Результат вставки:


Вложил блок

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
И есть атрибуты этого блока, значения которых формируются с использованием полей, ссылающиеся на параметры.
Я не знаю решения, лишь могу подсказать направление, куда копать.
Когда у тебя в атрибутах используются ссылки на динамические свойства, то они привязываются не к BlockTableRecord, а к BlockReference конкретного блока (или к DynamicBlockReferenceProperty).

Поэтому скорее всего SetAttributeFromBlock и AppendAttribute недостаточно.
Нужны дополнительные действия, чтобы перепривязать ссылки в полях атрибутов к вставленному  BlockReference(DynamicBlockReferenceProperty). А вот какие подсказать не могу, дальше пока не копал.

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Год-два назад разбирался с этим вопросом. При вставке блока с полями нюансов много, всех уже сейчас и не вспомню. В результате я сделал универсальный метод, который можно использовать даже не открывая чертёж как документ. Пробуйте:
Код - C# [Выбрать]
  1. /// <summary>
  2. ///
  3. /// </summary>
  4. /// <param name="position">Точка вставки блока</param>
  5. /// <param name="defBlkTabRecId">ObjectId описания блока</param>
  6. /// <param name="ownBlkTabRecId">ObjectId объекта, в который вставляется блок</param>
  7. /// <param name="layerId">ObjectId слоя</param>
  8. /// <param name="scale">Масштаб</param>
  9. /// <param name="dynamicPropsValues">Значения динамических параметров</param>
  10. /// <param name="attributesValues">Значения атрибутов</param>
  11. /// <returns>ObjectId вставки блока или ObjectId.Null при неудаче</returns>
  12. public static ObjectId CreateBlockReference
  13.     (Point3d position, ObjectId defBlkTabRecId,
  14.     ObjectId ownBlkTabRecId, ObjectId layerId,
  15.     double scale = 1.0,
  16.     Dictionary<string, object> dynamicPropsValues = null,
  17.     Dictionary<string, string> attributesValues = null)
  18. {
  19.     ObjectId
  20.         blkRefId = ObjectId.Null,
  21.         blkTabRecId = defBlkTabRecId;
  22.  
  23.     // Создаем блок, настраиваем основные свойства, вставляем в текущее пространство
  24.     using (BlockReference bRef = new BlockReference(position, blkTabRecId))
  25.     {
  26.         bRef.ScaleFactors = bRef.ScaleFactors.MultiplyBy(scale);
  27.         if (layerId.CheckObjectIdFor<LayerTableRecord>())
  28.         {
  29.             bRef.LayerId = layerId;
  30.         }
  31.         using (BlockTableRecord owner
  32.             = ownBlkTabRecId.SafeOpen<BlockTableRecord>(true))
  33.         {
  34.             if (owner != null)
  35.             {
  36.                 blkRefId = owner.AppendEntity(bRef);
  37.             }                    
  38.         }
  39.  
  40.         if (blkRefId.IsValid)
  41.         {
  42.             // Задаем динамические параметры
  43.             if (bRef.IsDynamicBlock
  44.                 && dynamicPropsValues != null
  45.                 && dynamicPropsValues.Count > 0)
  46.             {
  47.                 //Задаем значения динамических свойств
  48.                 foreach (DynamicBlockReferenceProperty dynProp
  49.                     in bRef.DynamicBlockReferencePropertyCollection)
  50.                 {
  51.                     if (!dynProp.ReadOnly
  52.                         && dynamicPropsValues.ContainsKey(dynProp.PropertyName))
  53.                     {
  54.                         IterisExceptions.TryAction(() => dynProp.Value
  55.                         = dynamicPropsValues[dynProp.PropertyName]);                                
  56.                     }
  57.                 }
  58.  
  59.                 blkTabRecId = bRef.BlockTableRecord;
  60.             }
  61.         }
  62.     }
  63.  
  64.     if (!blkRefId.CheckObjectIdFor<BlockReference>())
  65.         return ObjectId.Null;
  66.  
  67.     ObjectId[] attDefIds = null;
  68.  
  69.     using (BlockTableRecord bRec
  70.         = blkTabRecId.SafeOpen<BlockTableRecord>())
  71.     {
  72.         if (bRec != null)
  73.         {
  74.             attDefIds = bRec.GetAttributes().ToArray();
  75.         }
  76.     }
  77.  
  78.     if (attDefIds != null && attDefIds.Count() > 0)
  79.     {
  80.         // Создаем атрибуты
  81.         Dictionary<ObjectId, ObjectId>
  82.             attDefRefDict = new Dictionary<ObjectId, ObjectId>();
  83.         Matrix3d? blkTransform = null;
  84.  
  85.         using (BlockReference bRef
  86.             = blkRefId.SafeOpen<BlockReference>(true))
  87.         {
  88.             if (bRef != null)
  89.             {
  90.                 blkTransform = bRef.BlockTransform;
  91.                 foreach (ObjectId attDefId in attDefIds)
  92.                 {
  93.                     using (AttributeDefinition attDef
  94.                         = attDefId.SafeOpen<AttributeDefinition>())
  95.                     {
  96.                         if (attDef != null)
  97.                         {
  98.                             using (AttributeReference attRef = new AttributeReference())
  99.                             {
  100.                                 attRef.SetAttributeFromBlock(attDef, blkTransform.Value);
  101.                                 ObjectId attRefId = bRef.AttributeCollection.AppendAttribute(attRef);
  102.                                 attDefRefDict[attDefId] = attRefId;
  103.                                 if (!attDef.HasFields
  104.                                     && attributesValues != null
  105.                                     && attributesValues.ContainsKey(attDef.Tag))
  106.                                 {
  107.                                     attRef.TextString = attributesValues[attDef.Tag];
  108.                                 }
  109.                             }
  110.                         }
  111.                     }
  112.                 }
  113.             }
  114.         }
  115.  
  116.         Database db = blkRefId.Database;
  117.  
  118.         if (blkTransform.HasValue)
  119.         {
  120.             using (WorkDbTmpSwitcher switcher = new WorkDbTmpSwitcher(db))
  121.             {
  122.                 // Настраиваем атрибуты после вставки
  123.                 foreach (KeyValuePair<ObjectId, ObjectId> pair in attDefRefDict)
  124.                 {
  125.                     using (AttributeDefinition attDef
  126.                         = pair.Key.SafeOpen<AttributeDefinition>())
  127.                     using (AttributeReference attRef
  128.                         = pair.Value.SafeOpen<AttributeReference>(true))
  129.                     {
  130.                         if (attDef == null || attRef == null) continue;
  131.                         if (attDef.HasFields)
  132.                         {
  133.                             attRef.SetAttributeFromBlock(attDef, blkTransform.Value);
  134.                         }
  135.                         if (attRef.Database.Equals(db))
  136.                         {
  137.                             attRef.AdjustAlignment(db);
  138.                         }
  139.                     }
  140.                 }
  141.             }
  142.         }
  143.     }
  144.  
  145.     return blkRefId;
  146. }
  147.  

WorkDbTmpSwitcher:
Код - C# [Выбрать]
  1. /// <summary>
  2. /// Класс для временного переключения рабочей БД
  3. /// </summary>
  4. public class WorkDbTmpSwitcher : IDisposable
  5. {
  6.     /// <summary>
  7.     /// Переменная для хранения исходной БД
  8.     /// </summary>
  9.     Database _oldWorkDb;
  10.  
  11.     /// <summary>
  12.     /// Метка того, нужно переключать БД или нет
  13.     /// </summary>
  14.     bool _needSwitch;
  15.  
  16.     /// <summary>
  17.     /// Создание вспомогательного объекта для временного переключения БД
  18.     /// </summary>
  19.     /// <param name="tmpWorkDb">Ссылка на БД на которую временно переключаемся</param>
  20.     public WorkDbTmpSwitcher(Database tmpWorkDb)
  21.     {
  22.         _oldWorkDb = HostApplicationServices.WorkingDatabase;
  23.         _needSwitch = !tmpWorkDb.Equals(_oldWorkDb);
  24.         if (_needSwitch)
  25.         {
  26.             HostApplicationServices.WorkingDatabase = tmpWorkDb;
  27.         }
  28.     }
  29.  
  30.     /// <summary>
  31.     /// Реализация IDisposable
  32.     /// </summary>
  33.     public void Dispose()
  34.     {
  35.         if (_needSwitch)
  36.         {
  37.             HostApplicationServices.WorkingDatabase = _oldWorkDb;
  38.             _oldWorkDb = null;
  39.         }
  40.     }
  41. }
  42.  

TryAction:
Код - C# [Выбрать]
  1. /// <summary>
  2. /// Защищённое выполнение действия
  3. /// </summary>
  4. /// <param name="action"></param>
  5. /// <returns></returns>
  6. public static Exception TryAction(Action action)
  7. {
  8.     try
  9.     {
  10.         action();
  11.         return null;
  12.     }
  13.     catch (System.Exception ex)
  14.     {
  15.         Debug.WriteLine(ex.Message);
  16.         Debug.WriteLine(ex.StackTrace);
  17.         return ex;
  18.     }
  19. }
  20.  

Оффлайн dmitrymaslakovАвтор темы

  • ADN OPEN
  • Сообщений: 40
  • Карма: 1
Спасибо, Дмитрий Загорулькин, буду пробовать.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Дмитрий Загорулькин,
Для полного счастья кажется не хватает исходника метода SafeOpen.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Да, я знаю :) Суть в том, что там один метод за другой цепляется и придётся выложить с десяток вспомогательных методов. Мне лень :)
SafeOpen - это просто обёртка для метода ObjectId.Open. Если вызывается:
- SafeOpen(), то это открытие объекта на чтение.
- SafeOpen(true), то это открытие объекта на запись.
Ещё нет CheckObjectIdFor, но если поискать по форуму, то его можно найти в одной из недавних тем.

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Хотя, ладно.
CheckObjectIdFor:
Код - C# [Выбрать]
  1. /// <summary>
  2. /// Проверка типа Id объекта
  3. /// </summary>
  4. /// <typeparam name="T">Тип, на который проверяем</typeparam>
  5. /// <param name="id">Id объекта</param>
  6. /// <param name="allowErased">Допускается объект, который был удален</param>
  7. /// <returns></returns>
  8. public static bool CheckObjectIdFor<T>
  9.     (this ObjectId id,
  10.     bool allowErased = false) where T : DBObject
  11. {
  12.     if (id.CheckId(allowErased))
  13.     {
  14.         RXClass
  15.             forCheck = RXObject.GetClass(typeof(T)),
  16.             objClass = id.ObjectClass;
  17.  
  18.         return objClass.Equals(forCheck)
  19.             || objClass.IsDerivedFrom(forCheck);
  20.     }
  21.     return false;
  22. }
  23.  
CheckId:
Код - C# [Выбрать]
  1. /// <summary>
  2. /// Check the id for not null, valid and not erased (optional)
  3. /// </summary>
  4. /// <param name="id"></param>
  5. /// <param name="allowErased"></param>
  6. /// <returns></returns>
  7. public static bool CheckId(this ObjectId id, bool allowErased = false)
  8. {
  9.     return !id.IsNull
  10.         && id.IsValid
  11.         && (allowErased || (!id.IsErased && !id.IsEffectivelyErased));
  12. }
SafeOpen с параметром OpenMode:
Код - C# [Выбрать]
  1.         /// <summary>
  2.         ///
  3.         /// </summary>
  4.         /// <typeparam name="T"></typeparam>
  5.         /// <param name="id"></param>
  6.         /// <param name="mode"></param>
  7.         /// <param name="openErased"></param>
  8.         /// <param name="forceOpenOnLockedLayer"></param>
  9.         /// <returns></returns>
  10.         public static T SafeOpen<T>(this ObjectId id, OpenMode mode,
  11.             bool openErased = false,
  12.             bool forceOpenOnLockedLayer = true) where T : DBObject
  13.         {
  14.             T obj = null;
  15.  
  16.             if (id.CheckObjectIdFor<T>(openErased))
  17.             {
  18.                 try
  19.                 {
  20. #pragma warning disable 618
  21.                     obj = id.Open(mode, openErased, forceOpenOnLockedLayer) as T;
  22. #pragma warning restore 618                    
  23.                 }
  24.                 catch (System.Exception ex)
  25.                 {
  26.                     Debug.WriteLine(ex.Message);
  27.                     Debug.WriteLine(ex.StackTrace);
  28.                 }
  29.             }
  30.  
  31.             return obj;
  32.         }
SafeOpen с параметром bool:
Код - C# [Выбрать]
  1. /// <summary>
  2. ///
  3. /// </summary>
  4. /// <typeparam name="T"></typeparam>
  5. /// <param name="id"></param>
  6. /// <param name="forWrite"></param>
  7. /// <param name="openErased"></param>
  8. /// <param name="forceOpenOnLockedLayer"></param>
  9. /// <returns></returns>
  10. public static T SafeOpen<T>(this ObjectId id,
  11.     bool forWrite = false,
  12.     bool openErased = false,
  13.     bool forceOpenOnLockedLayer = true) where T : DBObject
  14.     => SafeOpen<T>
  15.         (id,
  16.         forWrite ? OpenMode.ForWrite : OpenMode.ForRead,
  17.         openErased,
  18.         forceOpenOnLockedLayer);
  19.  
Вроде всё? Если нет - напишите каких методов не хватает.

Оффлайн dmitrymaslakovАвтор темы

  • ADN OPEN
  • Сообщений: 40
  • Карма: 1
Прикрутил Дмитрия метод. Добавил регенерацию. Заработало частично: в одном атрибуте значения видны, а вот во втором отразились названия параметров. Посижу покручу, если ничего не получится, то выложу код.

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Да, почему-то один из трёх атрибутов не высчитывается. Но если зайти в редактор атрибутов, выбрать этот атрибут - то покажется правильное значение. Если выйти из редактора блоков через "ОК", то значение атрибута исправляется. Видимо, что-то ещё надо добавлять в мой метод...
Проверял вот таким кодом (Civil 3D 2020 as AutoCAD ):
Код - C# [Выбрать]
  1. public class InsertBlockTest
  2. {
  3.     [CommandMethod("TestInsertBlock")]
  4.     public void RunCommand()
  5.     {
  6.         Document adoc = Application.DocumentManager.MdiActiveDocument;
  7.         Editor ed = adoc.Editor;
  8.         Database db = adoc.Database;
  9.  
  10.         PromptEntityResult res = ed.GetEntity("\nSelect block reference: ");
  11.         if (res.Status != PromptStatus.OK) return;
  12.         ObjectId blkId = res.ObjectId;
  13.  
  14.         ObjectId recId;
  15.  
  16.         using (BlockReference blkRef = blkId.SafeOpen<BlockReference>())
  17.         {
  18.             if (blkRef is null) return;
  19.  
  20.             recId = blkRef.IsDynamicBlock
  21.                 ? blkRef.DynamicBlockTableRecord
  22.                 : blkRef.BlockTableRecord;
  23.         }
  24.  
  25.         PromptPointResult ptRes = ed.GetPoint("\nSelect point: ");
  26.         if (ptRes.Status != PromptStatus.OK) return;
  27.  
  28.         Point3d insPt = ptRes.Value.TransformBy(ed.CurrentUserCoordinateSystem);
  29.  
  30.         CreateBlockReference(insPt, recId, db.CurrentSpaceId, db.LayerZero);    
  31.     }
  32. }
  33.  

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Дмитрий Загорулькин,
В полях определений атрибутов этого блока есть вот такое: %<\AcObjProp.16.2 Object(?BlockRefId).Parameter(601).UserVariable>%
Так вот ?BlockRefId следует заменить на %<\_ObjId NNNNNNNNN>%, где NNNNNNNNN - числовое значение ObjectId вставки блока.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Я попробовал сделать по этому примеру: https://forums.autodesk.com/t5/net/insert-block-works-but-problem-with-update-field/m-p/3084964#M24250
Пока что-то не получается.
Вроде всё работает. Или я что-то пропустил?
Код - C# [Выбрать]
  1. using System;
  2. using Autodesk.AutoCAD.Runtime;
  3. using Autodesk.AutoCAD.ApplicationServices;
  4. using Autodesk.AutoCAD.DatabaseServices;
  5. using Autodesk.AutoCAD.Geometry;
  6. using Autodesk.AutoCAD.EditorInput;
  7.  
  8. // This line is not mandatory, but improves loading performances
  9. [assembly: CommandClass(typeof(InsertBlockWithAttFields.MyCommands))]
  10.  
  11. namespace InsertBlockWithAttFields
  12. {
  13.  
  14.   public class MyCommands
  15.   {
  16.     [CommandMethod("InsertBlockWithFieldAtts")]
  17.     public void InsertBlockWithFieldAtts()
  18.     {
  19.       Document doc = Application.DocumentManager.MdiActiveDocument;
  20.       Database db = doc.Database;
  21.       Editor ed = doc.Editor;
  22.  
  23.       using (Transaction trx = db.TransactionManager.StartTransaction())
  24.       {
  25.         BlockTable bt = trx.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
  26.         BlockTableRecord modelBtr = trx.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
  27.         BlockTableRecord blockBtr = trx.GetObject(bt["Светильник потолочный светодиодный"], OpenMode.ForRead) as BlockTableRecord;
  28.         Point3d insertPoint = ed.GetPoint("Select Insertion Point").Value;
  29.         BlockReference bref = new BlockReference(insertPoint, blockBtr.ObjectId);
  30.         modelBtr.AppendEntity(bref);
  31.         trx.AddNewlyCreatedDBObject(bref, true);
  32.  
  33.         foreach (ObjectId id in blockBtr)
  34.         {
  35.           if (id.ObjectClass.Name == "AcDbAttributeDefinition")
  36.           {
  37.             AttributeDefinition attDef = trx.GetObject(id, OpenMode.ForRead) as AttributeDefinition;
  38.             AttributeReference attref = new AttributeReference();
  39.             attref.SetAttributeFromBlock(attDef, bref.BlockTransform);
  40.  
  41.             bref.AttributeCollection.AppendAttribute(attref);
  42.             trx.AddNewlyCreatedDBObject(attref, true);
  43.  
  44.             if (attDef.Constant)
  45.             {
  46.               continue;
  47.             }
  48.  
  49.             if (!attref.ExtensionDictionary.IsNull)
  50.             {
  51.               DBDictionary extDic = trx.GetObject(attref.ExtensionDictionary, OpenMode.ForRead) as DBDictionary;
  52.               if (!extDic.GetAt("ACAD_FIELD").IsNull)
  53.               {
  54.                 DBDictionary fieldDic = trx.GetObject(extDic.GetAt("ACAD_FIELD"), OpenMode.ForRead) as DBDictionary;
  55.                 Field fld = trx.GetObject(fieldDic.GetAt("TEXT"), OpenMode.ForWrite) as Field;
  56.  
  57.                 string strId = bref.ObjectId.OldIdPtr.ToString();
  58.                 string updteStr = "%<\\_ObjId " + strId + ">%";
  59.                 string fieldCode = fld.GetFieldCode(FieldCodeFlags.AddMarkers);
  60.                 string newFieldCode = fieldCode.Replace("?BlockRefId", updteStr);
  61.                 fld.SetFieldCode(newFieldCode);
  62.               }
  63.             }
  64.           }
  65.         }
  66.         trx.Commit();
  67.       }
  68.       ed.Regen();
  69.     }
  70.   }
  71. }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение dmitrymaslakov 12-07-2019, 05:07:07

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Или я что-то пропустил?
Думаю, что да. У вставки есть особенности. Часть из них мы с Вами как раз тут на форуме обсуждали года два назад - Вы мне подсказали пару неочевидных моментов, касаемо порядка вызова методов и того, что в какой момент может быть быть открыто. Потому и появился у меня такой непростой метод. Правда, возможно, что конкретно в данном случае у dmitrymaslakov ситуация такая, что он не встретится никогда с этими особенностями.
Поэкспериментировал я основательно и пришёл к выводу, что надо разделять создание атрибутов и их настройку. Создаём атрибут, добавляем его в блок, закрываем блок - и потом можно снова открывать атрибут и настраивать его. Если следовать этому принципу, то метод SetAttributeFromBlock сам все нужные действия выполняет по внесению Id в код поля и не нужно "вручную" это делать. В общем, ещё одна особенность...
Итоговый код метода:
Код - C# [Выбрать]
  1. /// <summary>
  2. ///
  3. /// </summary>
  4. /// <param name="position">Точка вставки блока</param>
  5. /// <param name="defBlkTabRecId">ObjectId описания блока</param>
  6. /// <param name="ownBlkTabRecId">ObjectId объекта, в который вставляется блок</param>
  7. /// <param name="layerId">ObjectId слоя</param>
  8. /// <param name="scale">Масштаб</param>
  9. /// <param name="dynamicPropsValues">Значения динамических параметров</param>
  10. /// <param name="attributesValues">Значения атрибутов</param>
  11. /// <returns>ObjectId вставки блока или ObjectId.Null при неудаче</returns>
  12. public static ObjectId CreateBlockReference
  13.     (Point3d position, ObjectId defBlkTabRecId,
  14.     ObjectId ownBlkTabRecId, ObjectId layerId,
  15.     double scale = 1.0,
  16.     Dictionary<string, object> dynamicPropsValues = null,
  17.     Dictionary<string, string> attributesValues = null)
  18. {
  19.     ObjectId
  20.         blkRefId = ObjectId.Null,
  21.         blkTabRecId = defBlkTabRecId;
  22.  
  23.     // Создаем блок, настраиваем основные свойства, вставляем в текущее пространство
  24.     using (BlockReference bRef = new BlockReference(position, blkTabRecId))
  25.     {
  26.         bRef.ScaleFactors = bRef.ScaleFactors.MultiplyBy(scale);
  27.         if (layerId.CheckObjectIdFor<LayerTableRecord>())
  28.         {
  29.             bRef.LayerId = layerId;
  30.         }
  31.         using (BlockTableRecord owner
  32.             = ownBlkTabRecId.SafeOpen<BlockTableRecord>(true))
  33.         {
  34.             if (owner != null)
  35.             {
  36.                 blkRefId = owner.AppendEntity(bRef);
  37.             }
  38.         }
  39.  
  40.         if (blkRefId.IsValid)
  41.         {
  42.             // Задаем динамические параметры
  43.             if (bRef.IsDynamicBlock)
  44.             {
  45.                 //Задаем значения динамических свойств
  46.                 foreach (DynamicBlockReferenceProperty dynProp
  47.                     in bRef.DynamicBlockReferencePropertyCollection)
  48.                 {
  49.                     if (!dynProp.ReadOnly
  50.                         && (dynamicPropsValues?.ContainsKey(dynProp.PropertyName) ?? false))
  51.                     {
  52.                         IterisExceptions.TryAction(() => dynProp.Value
  53.                         = dynamicPropsValues[dynProp.PropertyName]);
  54.                     }
  55.                 }
  56.  
  57.                 blkTabRecId = bRef.BlockTableRecord;
  58.             }
  59.         }
  60.     }
  61.  
  62.     if (!blkRefId.CheckObjectIdFor<BlockReference>())
  63.         return ObjectId.Null;
  64.  
  65.     ObjectId[] attDefIds;
  66.  
  67.     using (BlockTableRecord bRec
  68.         = blkTabRecId.SafeOpen<BlockTableRecord>())
  69.     {
  70.         attDefIds = bRec?.GetAttributes().ToArray();
  71.     }
  72.  
  73.     if (attDefIds != null && attDefIds.Any())
  74.     {
  75.         // Создаем атрибуты
  76.         Dictionary<ObjectId, ObjectId>
  77.             attDefRefDict = new Dictionary<ObjectId, ObjectId>();
  78.         Matrix3d? blkTransform = null;
  79.  
  80.         using (BlockReference bRef
  81.             = blkRefId.SafeOpen<BlockReference>(true))
  82.         {
  83.             if (bRef != null)
  84.             {
  85.                 blkTransform = bRef.BlockTransform;
  86.                 foreach (ObjectId attDefId in attDefIds)
  87.                 {
  88.                     using (AttributeDefinition attDef
  89.                         = attDefId.SafeOpen<AttributeDefinition>())
  90.                     {
  91.                         if (attDef != null)
  92.                         {
  93.                             using (AttributeReference attRef = new AttributeReference())
  94.                             {
  95.                                 ObjectId attRefId = bRef.AttributeCollection.AppendAttribute(attRef);
  96.                                 attDefRefDict[attDefId] = attRefId;
  97.                             }
  98.                         }
  99.                     }
  100.                 }
  101.             }
  102.         }
  103.  
  104.         Database db = blkRefId.Database;
  105.  
  106.         if (blkTransform.HasValue)
  107.         {
  108.             using (WorkDbTmpSwitcher switcher = new WorkDbTmpSwitcher(db))
  109.             {
  110.                 // Настраиваем атрибуты
  111.                 foreach (KeyValuePair<ObjectId, ObjectId> pair in attDefRefDict)
  112.                 {
  113.                     using (AttributeDefinition attDef
  114.                         = pair.Key.SafeOpen<AttributeDefinition>())
  115.                     using (AttributeReference attRef
  116.                         = pair.Value.SafeOpen<AttributeReference>(true))
  117.                     {
  118.                         if (attDef is null || attRef is null) continue;
  119.                         attRef.SetAttributeFromBlock(attDef, blkTransform.Value);
  120.                         if (!attDef.HasFields
  121.                             && !attDef.Constant
  122.                             && attributesValues != null
  123.                             && attributesValues.ContainsKey(attDef.Tag))
  124.                         {
  125.                             attRef.TextString = attributesValues[attDef.Tag];
  126.                         }
  127.  
  128.                         if (attRef.Database.Equals(db))
  129.                         {
  130.                             attRef.AdjustAlignment(db);
  131.                         }
  132.                     }
  133.                 }
  134.             }
  135.         }
  136.     }
  137.     return blkRefId;
  138. }
  139.  
Пока проверял, обнаружил что ещё один метод не выложил - BlockTableRecord.GetAttributes():
Код - C# [Выбрать]
  1. /// <summary>
  2. /// Получение коллекции атрибутов из определения блока
  3. /// </summary>
  4. /// <param name="blockTableRecord">Определение блока</param>
  5. /// <returns>Коллекция атрибутов блока</returns>
  6. public static IEnumerable<ObjectId> GetAttributes(this BlockTableRecord blockTableRecord)
  7. {
  8.     return blockTableRecord
  9.         .Cast<ObjectId>()
  10.         .Where(objId => objId.CheckObjectIdFor<AttributeDefinition>());
  11. }
  12.  

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Если следовать этому принципу, то метод SetAttributeFromBlock сам все нужные действия выполняет по внесению Id в код поля и не нужно "вручную" это делать.
Не уверен, что это работает во всех версиях AutoCAD...
Мой код отработал нормально на примере чертежа.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Не уверен, что это работает во всех версиях AutoCAD...
Хм... Резонное замечание. Я проверял только в 2020 версии. Потестирую в других, но уже не сегодня.