Проблема с принудительным обновлением графики. Autocad MEP

Автор Тема: Проблема с принудительным обновлением графики. Autocad MEP  (Прочитано 10404 раз)

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

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

Оффлайн Алексей КузинАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 116
  • Карма: 8
уже давно был разработан (или откуда то взят - история умалчивает) метод для обновлении графики у объекта
Код - C# [Выбрать]
  1.         public static void RefreshMember(Member member)
  2.         {
  3.             if (!member.IsWriteEnabled)
  4.             {
  5.                 member.UpgradeOpen();
  6.             }
  7.  
  8.             member.RecordGraphicsModified(true);
  9.             double test = member.InsulationThickness;
  10.             member.InsulationThickness = test + 10;
  11.             member.InsulationThickness = test;
  12.         }
Работал хорошо и проблем с ним не было. Но в последнее время стал наблюдать сбои в работе, хотя возможно это не причина,а следствия каких то операций. Но пропуская строку 10 проблемы пропадают.
Одна из последних проблем весьма экзотическая - перестают работать обработчики событий в документе!!!   Я не могу точно сказать что именно это является основной причиной, но есть подозрения что то тут не так!

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

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

Оффлайн Алексей КузинАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 116
  • Карма: 8
Объект - DuctFitting

Запускаю
Код - C# [Выбрать]
  1. document.CommandWillStart += new CommandEventHandler(MdiActiveDocument_CommandWillStart);
  2. document.CommandEnded += new CommandEventHandler(MdiActiveDocument_CommandFinish);
  3.  
  4. database.ObjectModified += new ObjectEventHandler(database_ObjectModified);

Собственно после начала команды отлавливаю какие объекты были измены и по окончанию команды запускается постобработка их и регенерация графики.

Проблема с обработчиками возникает при команде ERASE. как измененный приходит объект, который был подсоединен к удаляемому.

Эту ошибку воспроизвести весьма сложно, но результат меня просто поражает. Впервые столкнулся с тем, что обработчики перестают реагировать. Я попробую сделать тестовый пример повторения, но возможно просто это сделать не получится.

Оффлайн Алексей КузинАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 116
  • Карма: 8
Вопрос тут больше в том - смотря кода из вопроса, когда изменяется InsulationThickness и возвращается обратно значение. Это адекватный способ заставить фиттинг обновить геометрию? И могут ли подобные вещи привести к проблемам? Может кто то сталкивался с подобным... Потому что странно, что пропуская это все работает...

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Вопрос тут больше в том - смотря кода из вопроса, когда изменяется InsulationThickness и возвращается обратно значение. Это адекватный способ заставить фиттинг обновить геометрию? И могут ли подобные вещи привести к проблемам? Может кто то сталкивался с подобным... Потому что странно, что пропуская это все работает...
Вероятнее всего при изменении геометрии фитинга меняется что-то и в связанных примитивах (если они конечно есть), что влечет за собой database_ObjectModified и для фитинга и для связанных примитивов. Собственно говоря это самый опасный обработчик события. В нём вообще не следует запускать транзакции и модифицировать какие-либо объекты/примитивы....
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Проблема с обработчиками возникает при команде ERASE. как измененный приходит объект, который был подсоединен к удаляемому.
Воспользуйся ARXDBG/MGDDBG для анализа того, что происходит при ERASE со связанными примитивами. Я совершенно четко могу представить ситуацию, когда при удалении одного примитива модифицируется связанный - на него установлен реактор и он, например, у себя выкидывает ссылку на удалённый примитив или, например, меняет свою форму (укорачивается или удлиняется).
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей КузинАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 116
  • Карма: 8
Цитировать
database_ObjectModified и для фитинга и для связанных примитивов. Собственно говоря это самый опасный обработчик события.
В этом обработчике я только запоминаю id объектов. Работа с ними происходит только в обработчике конца команды

Оффлайн Алексей КузинАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 116
  • Карма: 8
Цитировать
Воспользуйся ARXDBG/MGDDBG
Спасибо, попробую что то накопать

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

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

Оффлайн Алексей КузинАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 116
  • Карма: 8
Цитировать
И после этого снова вызывается database_ObjectModified, причем возможно не только для тех объектов, которые ты редактируешь, но и для связанных.
Или я вас не правильно понял, но если вы про рекурсию, то думаю нет.

Извиняю, выше описал непонятно. Вот примерный код отслеживания изменений в команде.

Код - C# [Выбрать]
  1. Application.DocumentManager.DocumentCreated += new DocumentCollectionEventHandler(DocumentManager_DocumentCreated);
  2.     Application.DocumentManager.DocumentToBeDestroyed += new DocumentCollectionEventHandler(DocumentManager_DocumentToBeDestroyed);
  3.  
  4.  
  5.  
  6.  
  7.  
  8.     List<ObjectId> modify = new List<ObjectId>();
  9.  
  10.     private void DocumentManager_DocumentCreated(object sender, Autodesk.AutoCAD.ApplicationServices.DocumentCollectionEventArgs e)
  11.     {
  12.         document.CommandWillStart += new CommandEventHandler(MdiActiveDocument_CommandWillStart);
  13.         document.CommandEnded += new CommandEventHandler(MdiActiveDocument_CommandFinish);
  14.         document.CommandFailed += new CommandEventHandler(MdiActiveDocument_CommandFinish);
  15.         document.CommandCancelled += new CommandEventHandler(MdiActiveDocument_CommandFinish);
  16.     }
  17.  
  18.     private void DocumentManager_DocumentToBeDestroyed(object sender, Autodesk.AutoCAD.ApplicationServices.DocumentCollectionEventArgs e)
  19.     {
  20.         document.CommandWillStart -= new CommandEventHandler(MdiActiveDocument_CommandWillStart);
  21.         document.CommandEnded -= new CommandEventHandler(MdiActiveDocument_CommandFinish);
  22.         document.CommandFailed -= new CommandEventHandler(MdiActiveDocument_CommandFinish);
  23.         document.CommandCancelled -= new CommandEventHandler(MdiActiveDocument_CommandFinish);
  24.     }
  25.  
  26.     private void MdiActiveDocument_CommandWillStart(object sender, CommandEventArgs e)
  27.     {
  28.         Database database = document.Database;
  29.         database.ObjectModified += new ObjectEventHandler(database_ObjectModified);
  30.     }
  31.  
  32.     private void MdiActiveDocument_CommandFinish(object sender, CommandEventArgs e)
  33.     {
  34.         Database database = document.Database;
  35.         database.ObjectModified -= new ObjectEventHandler(database_ObjectModified);
  36.  
  37.         ApplyChanges(commandName, document);
  38.     }
  39.  
  40.     private void database_ObjectModified(object sender, ObjectEventArgs e)
  41.     {
  42.         modify.Add(e.DBObject.Id);
  43.     }
  44.  
  45.     private void ApplyChanges(string commandName, Document document)
  46.     {
  47.         try
  48.         {
  49.             foreach(var id in modify)
  50.             {
  51.                 if (id.IsErased || id.IsNull)
  52.                     continue;
  53.  
  54.                 Transaction tr = null;
  55.                 try
  56.                 {
  57.                     tr = document.Database.TransactionManager.StartTransaction();
  58.  
  59.                     using (var obj = tr.GetObject(id, OpenMode.ForWrite))
  60.                         if (obj is Member member)
  61.                         {
  62.                             //постобработка
  63.                             RefreshMember(member);
  64.                         }
  65.  
  66.                     tr.Commit();
  67.                 }
  68.                 catch
  69.                 {
  70.                     if (tr != null)
  71.                         tr.Abort();
  72.                 }
  73.                 finally
  74.                 {
  75.                     if (tr != null)
  76.                         tr.Dispose();
  77.                 }
  78.             }
  79.         }
  80.         finally
  81.         {
  82.             modify.Clear();
  83.         }
  84.     }
  85.  
  86.     public static void RefreshMember(Member member)
  87.     {
  88.         if (!member.IsWriteEnabled)
  89.         {
  90.             member.UpgradeOpen();
  91.         }
  92.  
  93.         member.RecordGraphicsModified(true);
  94.         double test = member.InsulationThickness;
  95.         member.InsulationThickness = test + 10;
  96.         member.InsulationThickness = test;
  97.     }

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
По коду:
1. UpgradeOpen следует выполнять для объектов открытых через Open (или в эмуляции транзакции), а не в простой транзакции.
2. Почему ты в database_ObjectModified не фильтруешь объекты по типу? Тебя интересуют только объекты типа Member? Тогда только их id добавляй в modify
3. В ApplyChanges ты открываешь объект для записи и только после этого проверяешь его тип. Ну не смешно ли это? Фактически сразу же срабатывает событие database_ObjectModified и если есть связанные объекты, то и им передаётся эта информация. И вероятно в modify добавляются элементы. А достаточно было проверить id.ObjectClass. Кроме того при database_ObjectModified перед добавлением id в modify неплохо было бы проверить, а нет ли его еще там...
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей КузинАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 116
  • Карма: 8
Цитировать
1. UpgradeOpen следует выполнять для объектов открытых через Open (или в эмуляции транзакции), а не в простой транзакции.
2. Почему ты в database_ObjectModified не фильтруешь объекты по типу? Тебя интересуют только объекты типа Member? Тогда только их id добавляй в modify
3. В ApplyChanges ты открываешь объект для записи и только после этого проверяешь его тип. Ну не смешно ли это? Фактически сразу же срабатывает событие database_ObjectModified и если есть связанные объекты, то и им передаётся эта информация. И вероятно в modify добавляются элементы. А достаточно было проверить id.ObjectClass. Кроме того при database_ObjectModified перед добавлением id в modify неплохо было бы проверить, а нет ли его еще там...
Это был только примерный кусок для того, чтобы развеять вопросы о рекурсии в моем коде. Все проверки, о которых вы пишите учтены, я просто выделил принцип работы который я делаю, чтобы показать.
Цитировать
Фактически сразу же срабатывает событие database_ObjectModified
на этот момент мы уже отписались от события.

Оффлайн Алексей КузинАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 116
  • Карма: 8
Цитировать
UpgradeOpen следует выполнять для объектов открытых через Open (или в эмуляции транзакции), а не в простой транзакции.
Не знал что это не допустимо в простых транзакциях. А есть другой способ в простой транзакции переоткрыть объект для записи?

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

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

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Не знал что это не допустимо в простых транзакциях. А есть другой способ в простой транзакции переоткрыть объект для записи?
Да. Просто открыть его повторно для записи. Мы это уже обсуждали на форуме здесь: http://adn-cis.org/forum/index.php?topic=7944 и здесь: http://adn-cis.org/forum/index.php?topic=8791.msg34359#msg34359
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение