Обновление полей в атрибутах блока

Автор Тема: Обновление полей в атрибутах блока  (Прочитано 19630 раз)

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

Оффлайн ВильдарАвтор темы

  • ADN Club
  • ****
  • Сообщений: 409
  • Карма: 77
  • Skype: vildar82
Re: Обновление полей в атрибутах блока
« Ответ #15 : 17-05-2016, 08:16:38 »
Код такой:
Код - C# [Выбрать]
  1.         [CommandMethod("Test", "Test", CommandFlags.Modal)]
  2.         public void Test()
  3.         {
  4.             // Обновление полей в блоке
  5.             Document doc = Application.DocumentManager.MdiActiveDocument;
  6.             Database db = doc.Database;
  7.             Editor ed = doc.Editor;            
  8.  
  9.             var sel = ed.GetEntity("Выбери блок для обновления полей в атрибутах");
  10.             if (sel.Status != PromptStatus.OK) return;
  11.  
  12.             using (var t = db.TransactionManager.StartTransaction())
  13.             {
  14.                 var blRef = sel.ObjectId.GetObject(OpenMode.ForRead) as BlockReference;                                
  15.                 foreach (ObjectId idAtr in blRef.AttributeCollection)
  16.                 {
  17.                     var atrRef = idAtr.GetObject(OpenMode.ForRead) as AttributeReference;
  18.                     if (atrRef.HasFields)
  19.                     {
  20.                         var fieldId = atrRef.GetField();                        
  21.                         var field = fieldId.GetObject(OpenMode.ForWrite) as Field;                        
  22.                         field.Evaluate();
  23.                         atrRef.UpgradeOpen();
  24.                         atrRef.SetField("TextString", field);
  25.                         atrRef.RecordGraphicsModified(true);                        
  26.                     }
  27.                 }
  28.                 db.TransactionManager.QueueForGraphicsFlush();
  29.                 t.Commit();                
  30.             }
  31.         }

EvaluateFields хорошо, но если получится обновлять только нужные поля - еще лучше.

« Последнее редактирование: 17-05-2016, 11:05:24 от vildar82 »

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Обновление полей в атрибутах блока
« Ответ #16 : 17-05-2016, 11:57:42 »
Я задал вопрос в ADN DevHelp есть ли в AutoCAD .NET API альтернатива для acdbEvaluateFields. Подождём ответа.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
Re: Обновление полей в атрибутах блока
« Ответ #17 : 17-05-2016, 17:00:05 »
EvaluateFields хорошо, но если получится обновлять только нужные поля - еще лучше.
Для пересчета полей и обновления блока ты можешь использовать код:
1.
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
db.EvaluateFields();

2. Работает так же хорошо(на тесте разумеется)
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
ed.Regen();

Когда ты пытаешься обновить точечно.
field.Evaluate(); срабатывает 1й раз, на 2й раз перестает пересчитывать!

можешь сам проверить.
ed.WriteMessage("/r/n" + field.GetStringValue());
field.Evaluate();
ed.WriteMessage("/r/n"+field.GetStringValue());

atrRef.SetField("TextString", field); первый раз прокатывает, второй раз действует нехорошо(удаляет кое-что)
вдаваться в подробности не буду, возможно зависит от работы первого метода field.Evaluate();
Возможно "TextString" не тот параметр, который следует в него передавать. Но в любом случае нужно разбираться вначале почему не срабатывает field.Evaluate();

отсюда скорее всего следует вывод, что field.Evaluate() недостаточен. После него нужно как-то обновлять блок.
Можно пытаться добавлять RecordGraphicsModified(true); и вызывать к примеру "_regen3"
Но на данном тесте смысла делать этого нет, т.к. цель была, если я правильно понял сэкономить на вызове "_regen".
нужен большой рабочий файл и смотреть что сработает быстрее.
Либо искать метод обновления вида одного примитива типа Entity.Regen() если такой вообще существует.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Обновление полей в атрибутах блока
« Ответ #18 : 17-05-2016, 17:11:22 »
Самый правильный и быстрый способ P/Invoke для acdbEvaluateFields, когда локально обновляется только атрибут, переданный через ObjectId. Но сигнатура метода достаточно нетривиальная:
Код - C++ [Выбрать]
  1. Acad::ErrorStatus acdbEvaluateFields(
  2.     const AcDbObjectId& objId,
  3.     int nContext,
  4.     const ACHAR* pszPropName = NULL,
  5.     AcDbDatabase* pDb = NULL,
  6.     AcFd::EvalFields nEvalFlag = AcFd::kEvalRecursive,
  7.     int* pNumFound = NULL,
  8.     int* pNumEvaluated = NULL
  9. );

И потребуется несколько сигнатур (в зависимости от версии AutoCAD и его разрядности).
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Обновление полей в атрибутах блока
« Ответ #19 : 17-05-2016, 17:14:33 »
Либо искать метод обновления вида одного примитива типа Entity.Regen() если такой вообще существует.
Если бы ты запустил пример с приложенным dwg-файлом, то убедился бы, что _REGEN в данном случае не помогает. Точнее обновление происходит не моментально. Помогает сразу только _UPDATEFIELDS.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
Re: Обновление полей в атрибутах блока
« Ответ #20 : 17-05-2016, 18:45:42 »
Если бы ты запустил пример с приложенным dwg-файлом...
только на нем и пробовал

Точнее обновление происходит не моментально.
скорее всего, я только хотел указать что тоже может помочь.

Помогает сразу только _UPDATEFIELDS.
предполагаю что регенерация вызывает вначале группу методов, таких как db.EvaluateFields(); а затем обновляет кэш изображений.
и не настаиваю, что вызов регенерации - правильное и оптимальное решение. )))

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Обновление полей в атрибутах блока
« Ответ #21 : 17-05-2016, 22:46:23 »
Пока через P/Invoke acdbEvaluateFields вот так. Кстати, не нужно указывать конкретный атрибут. Достаточно указать ObjectId вставки блока.

Код - C# [Выбрать]
  1. #region PInvoke acdbEvaluateFields
  2. // Acad::ErrorStatus acdbEvaluateFields (
  3. //   const AcDbObjectId& objId,
  4. //   int nContext,
  5. //   const ACHAR* pszPropName = NULL,
  6. //   AcDbDatabase* pDb        = NULL,
  7. //   AcFd::EvalFields nEvalFlag = AcFd::kEvalRecursive,
  8. //   int* pNumFound           = NULL,
  9. //   int* pNumEvaluated       = NULL
  10. // );
  11. // AutoCAD 2013 и 2014 x64
  12. [DllImport("acdb19.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, ExactSpelling = true,
  13.   EntryPoint = "?acdbEvaluateFields@@YA?AW4ErrorStatus@Acad@@AEBVAcDbObjectId@@HPEB_WPEAVAcDbDatabase@@W4EvalFields@AcFd@@PEAH4@Z")]
  14. private static extern Int32 acdbEvaluateFields19x64(ref ObjectId id, Int32 context, IntPtr pszPropName, IntPtr db, Int32 eval, IntPtr i1, IntPtr i2);
  15. // AutoCAD 2013 и 2014 x86
  16. [DllImport("acdb19.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, ExactSpelling = true,
  17. EntryPoint = "?acdbEvaluateFields@@YA?AW4ErrorStatus@Acad@@ABVAcDbObjectId@@HPB_WPAVAcDbDatabase@@W4EvalFields@AcFd@@PAH4@Z")]
  18. private static extern Int32 acdbEvaluateFields19x32(ref ObjectId id, Int32 context, IntPtr pszPropName, IntPtr db, Int32 eval, IntPtr i1, IntPtr i2);
  19. // AutoCAD 2015 и 2016 x64
  20. [DllImport("acdb20.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, ExactSpelling = true,
  21.   EntryPoint = "?acdbEvaluateFields@@YA?AW4ErrorStatus@Acad@@AEBVAcDbObjectId@@HPEB_WPEAVAcDbDatabase@@W4EvalFields@AcFd@@PEAH4@Z")]
  22. private static extern Int32 acdbEvaluateFields20x64(ref ObjectId id, Int32 context, IntPtr pszPropName, IntPtr db, Int32 eval, IntPtr i1, IntPtr i2);
  23. // AutoCAD 2015 и 2016 x86
  24. [DllImport("acdb20.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, ExactSpelling = true,
  25. EntryPoint = "?acdbEvaluateFields@@YA?AW4ErrorStatus@Acad@@ABVAcDbObjectId@@HPB_WPAVAcDbDatabase@@W4EvalFields@AcFd@@PAH4@Z")]
  26. private static extern Int32 acdbEvaluateFields20x32(ref ObjectId id, Int32 context, IntPtr pszPropName, IntPtr db, Int32 eval, IntPtr i1, IntPtr i2);
  27. // AutoCAD 2017 x64
  28. [DllImport("acdb21.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, ExactSpelling = true,
  29.   EntryPoint = "?acdbEvaluateFields@@YA?AW4ErrorStatus@Acad@@AEBVAcDbObjectId@@HPEB_WPEAVAcDbDatabase@@W4EvalFields@AcFd@@PEAH4@Z")]
  30. private static extern Int32 acdbEvaluateFields21x64(ref ObjectId id, Int32 context, IntPtr pszPropName, IntPtr db, Int32 eval, IntPtr i1, IntPtr i2);
  31. // AutoCAD 2017x86
  32. [DllImport("acdb21.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, ExactSpelling = true,
  33. EntryPoint = "?acdbEvaluateFields@@YA?AW4ErrorStatus@Acad@@ABVAcDbObjectId@@HPB_WPAVAcDbDatabase@@W4EvalFields@AcFd@@PAH4@Z")]
  34. private static extern Int32 acdbEvaluateFields21x32(ref ObjectId id, Int32 context, IntPtr pszPropName, IntPtr db, Int32 eval, IntPtr i1, IntPtr i2);
  35. #endregion
  36. private Int32 acdbEvaluateFields(ref ObjectId id, Int32 context)
  37. {
  38.   switch (Application.Version.Major)
  39.   {
  40.     case 21:
  41.       if (IntPtr.Size == 8)  
  42.         return acdbEvaluateFields21x64(ref id, 16, IntPtr.Zero, IntPtr.Zero, 1, IntPtr.Zero, IntPtr.Zero);
  43.       else
  44.         return acdbEvaluateFields21x32(ref id, 16, IntPtr.Zero, IntPtr.Zero, 1, IntPtr.Zero, IntPtr.Zero);
  45.     case 20:
  46.       if (IntPtr.Size == 8)
  47.         return acdbEvaluateFields20x64(ref id, 16, IntPtr.Zero, IntPtr.Zero, 1, IntPtr.Zero, IntPtr.Zero);
  48.       else
  49.         return acdbEvaluateFields20x32(ref id, 16, IntPtr.Zero, IntPtr.Zero, 1, IntPtr.Zero, IntPtr.Zero);
  50.     case 19:
  51.       if (IntPtr.Size == 8)
  52.         return acdbEvaluateFields19x64(ref id, 16, IntPtr.Zero, IntPtr.Zero, 1, IntPtr.Zero, IntPtr.Zero);
  53.       else
  54.         return acdbEvaluateFields19x32(ref id, 16, IntPtr.Zero, IntPtr.Zero, 1, IntPtr.Zero, IntPtr.Zero);
  55.     default:
  56.       break;
  57.   }
  58.   return 0;
  59. }
  60.  
  61. [CommandMethod("Test", "Test", CommandFlags.Modal)]
  62. public void Test()
  63. {
  64.   // Обновление полей в блоке
  65.   Document doc = Application.DocumentManager.MdiActiveDocument;
  66.   Database db = doc.Database;
  67.   Editor ed = doc.Editor;
  68.  
  69.   var sel = ed.GetEntity("Выбери блок для обновления полей в атрибутах: ");
  70.   if (sel.Status == PromptStatus.OK)
  71.   {
  72.     ObjectId id = sel.ObjectId;
  73.     acdbEvaluateFields(ref id, 16);
  74.   }
  75. }

Так это выглядит:



Я проверял только в AutoCAD 2015 и 2016 x64.
« Последнее редактирование: 17-05-2016, 23:35:15 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн ВильдарАвтор темы

  • ADN Club
  • ****
  • Сообщений: 409
  • Карма: 77
  • Skype: vildar82
Re: Обновление полей в атрибутах блока
« Ответ #22 : 18-05-2016, 08:18:09 »
Спасибо большое!

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Обновление полей в атрибутах блока
« Ответ #23 : 19-05-2016, 14:14:23 »
В ADN DevHelp мне подтвердили, что предложенное мной решение - единственное, и направили в Dev Team запрос на добавление функционала в .NET API. Пока вот так.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Geniy_dzydo

  • ADN OPEN
  • Сообщений: 3
  • Карма: 0
Re: Обновление полей в атрибутах блока
« Ответ #24 : 16-09-2016, 11:41:47 »
Здравствуйте гуру автокада. Подскажите пожалуйста может ли ваш код помочь в моем случае. Делаю блок с тремя атрибутами, в два атрибута вношу значения, в третьем атрибуте вычисляю разницу этих значений. Делаю полями в формуле; в пространстве редактора блоков обновление вычисления происходит. А когда потом уже после закрытия блока делаю изменения атрибутов уже ничего не вычисляется. Так понимаю эта проблема известна и простыми способами не решается. Можете что то подсказать, очень прошу!

И еще вопрос: как этот кода использовать в автокад, сохранять как лисп?

Оффлайн ВильдарАвтор темы

  • ADN Club
  • ****
  • Сообщений: 409
  • Карма: 77
  • Skype: vildar82
Re: Обновление полей в атрибутах блока
« Ответ #25 : 16-09-2016, 12:35:41 »
Привет.
Прикрепи файл с блоком, посмотреть.
Код приведен для примера. Использовать на твое усмотрение в своем проекте. Это тестовый черновик.

Оффлайн Geniy_dzydo

  • ADN OPEN
  • Сообщений: 3
  • Карма: 0
Re: Обновление полей в атрибутах блока
« Ответ #26 : 16-09-2016, 12:47:34 »
Прикладываю файл.
ту же задачу решил полями в обычном тексте и в таблице, но блок был бы лучшим вариантом. странно думал что в блоке будет так же отрабатывать, ан нет((((

Оффлайн ВильдарАвтор темы

  • ADN Club
  • ****
  • Сообщений: 409
  • Карма: 77
  • Skype: vildar82
Re: Обновление полей в атрибутах блока
« Ответ #27 : 16-09-2016, 12:52:54 »
Какая то особенность вычисления полей в формулах.
Немного поменял вычисляемый атрибут. Так работает.

Оффлайн Geniy_dzydo

  • ADN OPEN
  • Сообщений: 3
  • Карма: 0
Re: Обновление полей в атрибутах блока
« Ответ #28 : 16-09-2016, 14:13:43 »
ммм....ничего не понимаю, почему не работало. А еще такой вопрос, в вычисляемом поле можно поставить в качестве разделителя и точку и запятую, в тех атрибутах куда мы вносим значения можно ставить только точку. Можно ли что то изменить чтобы формула понимала и запятую тоже???

Оффлайн ВильдарАвтор темы

  • ADN Club
  • ****
  • Сообщений: 409
  • Карма: 77
  • Skype: vildar82
Re: Обновление полей в атрибутах блока
« Ответ #29 : 16-09-2016, 15:16:00 »
Думаю нет. Или делать свое программное решение.