Почему метод ObjectOverrule.Close() вызывается постоянно?

Автор Тема: Почему метод ObjectOverrule.Close() вызывается постоянно?  (Прочитано 10995 раз)

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

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Всем привет. Как-то давно были у меня вопросы (вот, вот) касаемо ObjectOverrule. Те проблемы были решены и все работает. Конечно, возможно не идеально, но вроде без фаталов ошибок и прочего такого. По крайней мере пользователи не сообщали и у меня при тестах хорошо. О результатах я пишу понемногу в этой теме. Скоро, кстати, будет новый комментарий, если это конечно кому-то интересно.
Проект был надолго заброшен, но недавно я прям загорелся им снова. На данный момент занимаюсь рефакторингом и оптимизацией. Переделал практически весь проект, упростив создание новых примитивов до максимума. Настолько, что даже палитра строится сама на основе выбранного примитива ))
Так вот - есть такой код - его не получается обобщить и приходится делать для каждого типа моих примитивов:
Код - C# [Выбрать]
  1. namespace mpESKD.Functions.mpBreakLine.Overrules
  2. {
  3.     using Autodesk.AutoCAD.DatabaseServices;
  4.     using Autodesk.AutoCAD.Runtime;
  5.     using ModPlusAPI.Windows;
  6.     using Base.Helpers;
  7.     using Base;
  8.  
  9.     public class BreakLineObjectOverrule : ObjectOverrule
  10.     {
  11.         protected static BreakLineObjectOverrule _breakLineObjectOverrule;
  12.  
  13.         public static BreakLineObjectOverrule Instance()
  14.         {
  15.             if (_breakLineObjectOverrule != null) return _breakLineObjectOverrule;
  16.             _breakLineObjectOverrule = new BreakLineObjectOverrule();
  17.             // Фильтр "отлова" примитива по расширенным данным. Работает лучше, чем проверка вручную!
  18.             _breakLineObjectOverrule.SetXDataFilter(BreakLineInterface.Name);
  19.             return _breakLineObjectOverrule;
  20.         }
  21.  
  22.         public override void Close(DBObject dbObject)
  23.         {
  24.             // Проверка дополнительных условий
  25.             if (IsApplicable(dbObject))
  26.             {
  27.                 AcadHelpers.WriteMessageInDebug("Close in ObjectOverrule");
  28.                 try
  29.                 {
  30.                     if (AcadHelpers.Document != null)
  31.                         if (dbObject != null && dbObject.IsNewObject & dbObject.Database == AcadHelpers.Database ||
  32.                             dbObject != null && dbObject.IsUndoing & dbObject.IsModifiedXData)
  33.                         {
  34.                             var breakLine = EntityReaderFactory.Instance.GetFromEntity<BreakLine>((Entity)dbObject);
  35.                             if (breakLine != null)
  36.                             {
  37.                                 breakLine.UpdateEntities();
  38.                                 breakLine.GetBlockTableRecordForUndo((BlockReference)dbObject).UpdateAnonymousBlocks();
  39.                             }
  40.                         }
  41.                 }
  42.                 catch (Exception exception)
  43.                 {
  44.                     ExceptionBox.Show(exception);
  45.                 }
  46.             }
  47.             base.Close(dbObject);
  48.         }
  49.  
  50.         public override bool IsApplicable(RXObject overruledSubject)
  51.         {
  52.             return ExtendedDataHelpers.IsApplicable(overruledSubject, BreakLineInterface.Name);
  53.         }
  54.     }
  55. }

Весь код в вопросе не важен. Важны только некоторые строки:
18 - согласно этой статье использование SetXDataFilter позволяет убрать ручную проверку XData, перекладывая эту работу на сам автокад
51-53 - стандартная реализация метода IsApplicable где я проверяю что в примитиве имеется нужная мне XData с кодом 1001
И вот самое интересное - в 27 строке - я просто вывожу сообщение в командную строку. А интересно то, что после создания моего примитива в чертеже, эту строчку в командной строке я вижу ПОСТОЯННО. Независимо от того, делаю я что-то со своим объектом или с любым другим примитивов автокада. А самое главное - эту строчку я вижу при каждом движении мышкой в чертеже!

Получается как-то совсем не оптимизировано. Хотелось бы понять почему так происходит и как лучше поступить в этой ситуации

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

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
 ;D ;D ;D
Для того, чтобы AutoCAD мог определить есть или нет у примитива XData с соответствующим именем приложения, примитив нужно открыть, ну а потом закрыть, т.е. вызвать его метод Close. Так что тут всё очевидно. Способа оптимизации я не вижу, так как понимаю, что во всех случаях у тебя примитив - BlockReference, так что отфильтровать не открывая его не получится.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Для того, чтобы AutoCAD мог определить есть или нет у примитива XData с соответствующим именем приложения, примитив нужно открыть, ну а потом закрыть, т.е. вызвать его метод Close
Блин, и точно)) Очевидно же

Но вот что мне не совсем очевидно - что происходит, когда я просто мышкой двигаю в пустом пространстве? Что при этом постоянно открывается?

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

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Что при этом постоянно открывается?
Запусти под отладчиком и посмотри. Возможно какой-то другой Overrule или PointMonitor/PointFilter шалит.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Что при этом постоянно открывается?
Запусти под отладчиком и посмотри. Возможно какой-то другой Overrule или PointMonitor/PointFilter шалит.
Понятия не имею как это сделать) Я знаю, что срабатывает мой конкретный метод Close(), знаю, что прилетает в него всегда BlockReference, а вот как узнать кто является причиной - я так не умею )

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

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Александр Пекшев aka Modis,
1. Что будет если твой метод IsApplicable будет всегда возвращать false?
2. Что делает ExtendedDataHelpers.IsApplicable(overruledSubject, BreakLineInterface.Name)? Нужен код.
3. Я бы в этой ситуации использовал бы не фильтр SetXDataFilter, а SetIdFilter, предварительно отобрав бы ObjectId своих примитивов и создав из них коллекцию для каждого открытого документа.
Не забывай, что Close вызывается не только для примитивов, но и для любых объектов (блоки/слои/типы линий/виды и т.д. и т.п.), и соответственно при фильтре SetXDataFilter каждый из них открывается/закрывается и это рекурсивно приводит к вызову Close.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Я бы в этой ситуации использовал бы не фильтр SetXDataFilter, а SetIdFilter, предварительно отобрав бы ObjectId своих примитивов и создав из них коллекцию для каждого документа.
Идея очень даже хорошая, но вот реализация объёмная как мне кажется. Я ведь за этой коллекцией должен следить и многое могу не усмотреть сразу. Это я так рассуждаю, потому-что еще ни разу не использовал словари автокадовские (даже не помню как их там зовут). Надо будет поизучать и посмотреть примеры.

Сейчас уже проводить тесты поздно, так что пока лишь приведу метод:
Код - C# [Выбрать]
  1. /// <summary>
  2. /// Проверка поддерживаемости примитива для Overrule
  3. /// </summary>
  4. /// <param name="rxObject"></param>
  5. /// <param name="appName"></param>
  6. public static bool IsApplicable(RXObject rxObject, string appName)
  7. {
  8.     DBObject dbObject = rxObject as DBObject;
  9.     if (dbObject == null)
  10.         return false;
  11.     // Всегда нужно проверять по наличию расширенных данных
  12.     // иначе может привести к фаталам при работе с динамическими блоками
  13.     return IsIntellectualEntity(dbObject, appName);
  14. }
  15. public static bool IsIntellectualEntity(DBObject dbObject, string appName)
  16. {
  17.     ResultBuffer rb = dbObject.GetXDataForApplication(appName);
  18.     return rb != null;
  19. }
Тут все просто

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

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Это я так рассуждаю, потому-что еще ни разу не использовал словари автокадовские (даже не помню как их там зовут).
Причем здесь "AutoCAD'овские словари"? Я не про AutoCAD'овские, а про .NET-овские.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Это я так рассуждаю, потому-что еще ни разу не использовал словари автокадовские (даже не помню как их там зовут).
Причем здесь "AutoCAD'овские словари"? Я не про AutoCAD'овские, а про .NET-овские.
Ну мне же эти данные нужно будет сохранять в документе, чтобы при следующем открытии документа все заработало. А значит либо XData, либо DBDictionary. При этом первый вариант, по идее, подвержен переполнению

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

  • Administrator
  • *****
  • Сообщений: 13877
  • Карма: 1785
  • Рыцарь ObjectARX
  • Skype: rivilis
Ну мне же эти данные нужно будет сохранять в документе, чтобы при следующем открытии документа все заработало.
Можно и так. Тогда XRecord в Named Object Dictionary (NOD) или в ExtensionDictionary для BlockTable. А можно и налету при открытии файла. Но в любом случае Close будет срабатывать и для них. Вот что самое печальное.
Кстати, если у тебя это только BlockReference, то почему ты сразу не проверяешь в IsApplicable на BlockReference? Кроме того я проверил бы еще и ObjectId на null и в этом случае возвращал сразу false.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 624
  • Карма: 158
    • ПГСу Бложик
Скоро, кстати, будет новый комментарий, если это конечно кому-то интересно.
Лично мне эта тема интересна и последние несколько месяцев ей и занимаюсь по мере сил, результаты экспериментов есть на youtube (если интересно), код пока не выкладываю, так как там именно эксперименты и показать пока нечего. Про оптимизацию пока не думал, но с интересом читаю твои посты.

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Но в любом случае Close будет срабатывать и для них
Тогда, пожалуй, пока отложу такую фичу. На данный момент не вижу в ней острой необходимости. Возможно, когда моих "кастомных" примитивов перевалит штук за 10, тогда можно будет задуматься об этом еще раз
Кстати, если у тебя это только BlockReference, то почему ты сразу не проверяешь в IsApplicable на BlockReference? Кроме того я проверил бы еще и ObjectId на null и в этом случае возвращал сразу false
Хорошие замечания. Добавлю в проверку. Все-таки свежий взгляд полезен. Особенно, когда проект уже перевалил за 5К строк исполняемого кода (согласно метрикам VS)
результаты экспериментов есть на youtube (если интересно)
Только вот нет ссылки на ютуб =))
Про оптимизацию пока не думал, но с интересом читаю твои посты
Кстати, рассматриваю вариант делать проект OpenSource. Правда не совсем в этом уверен, так как он будет не "отвязанным" - т.е. все-равно завязан на ModPlus и работать только в нём. Вот и думаю - нужно ли?

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

  • ADN Club
  • *****
  • Сообщений: 624
  • Карма: 158
    • ПГСу Бложик
Off-Topic: показать
Только вот нет ссылки на ютуб =))
Отвлекся, думал что добавил... =(
Извините, вам запрещён просмотр содержимого спойлеров.

Open Source... если код завязан на закрытую библиотеку кода, то какой смысл? Меня посещала мылсЯ, что-то типа "движка" сделать... т.е. разделить код в соответствии с МVC и упростить создание модели до предела, что бы можно было очень просто и легко клепать свои "кустомные" объекты. Но чувствую опыта и знаний пока маловато для этого...

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Отвлекся, думал что добавил
Какая-то специфическая штуковина во всех видосах =)) Что это за объект такой? От какой специальности?

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

  • ADN Club
  • *****
  • Сообщений: 624
  • Карма: 158
    • ПГСу Бложик
Какая-то специфическая штуковина во всех видосах =)) Что это за объект такой? От какой специальности?
Сейчас придет Александр Ривилис и даст нам по голове, за такой оффтоп...
Это из КЖ, зона раскладки арматуры. Проблема в том, что классические дин. блоки плохо зеркалятся (там с атрибутами заморочка, как пример, попробуй это сделать с этим блоком https://dwg.ru/dnl/14692)
А такой кустомный объект такого недостатка лишён, плюс часто требуется не совсем прямые арматурины, а с некоторой формой или отгибами или условными обозначениями на концах, плюс растягивать можно в соответствии с шагами по ширине и кратностью 11700 по длине, в общем плюшек очень много ... вот и экспериментирую...