Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: simson43 от 03-02-2019, 15:59:55

Название: ObjectOverrule.Close
Отправлено: simson43 от 03-02-2019, 15:59:55
Добрый день!

почитал про этот метод ObjectOverrule.Close()
но не могу понять как с ним работать. как связать изменение условной полилинии с классом унаследовавшим ObjectOverrule?
как должен вызываться ObjectOverrule.Close() при изменении этой полилинии?
Название: Re: ObjectOverrule.Close
Отправлено: Александр Ривилис от 03-02-2019, 16:33:27
simson43,
Зачем?
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 03-02-2019, 16:37:28
нужно при изменении объекта изменить его XData и другой объект связанный с измененным
Название: Re: ObjectOverrule.Close
Отправлено: Александр Пекшев aka Modis от 03-02-2019, 16:41:38
Overrule это такой механизм в автокаде, который похож на подписку на события. Когда вы "подпишитесь" на ObjectOverrule, то будете иметь возможность переопределять поведение метода Close() для объекта. Но ни в коем случае не нужно его вызывать! Он сам вызывается, когда объект закрывается при модификации.
По сути, подпись на событие ObjectModified очень схожа с обработкой метода ObjectOverrule.Close()
Название: Re: ObjectOverrule.Close
Отправлено: Александр Пекшев aka Modis от 03-02-2019, 16:46:33
нужно при изменении объекта изменить его XData и другой объект связанный с измененным
Вот пример:
Код - C# [Выбрать]
  1. // ReSharper disable InconsistentNaming
  2.  
  3. namespace mpESKD.Functions.mpBreakLine.Overrules
  4. {
  5.     using System.Diagnostics;
  6.     using Autodesk.AutoCAD.DatabaseServices;
  7.     using Autodesk.AutoCAD.Runtime;
  8.     using ModPlusAPI.Windows;
  9.     using Base.Helpers;
  10.     using Base;
  11.  
  12.     public class BreakLineObjectOverrule : ObjectOverrule
  13.     {
  14.         protected static BreakLineObjectOverrule _breakLineObjectOverrule;
  15.  
  16.         public static BreakLineObjectOverrule Instance()
  17.         {
  18.             if (_breakLineObjectOverrule != null) return _breakLineObjectOverrule;
  19.             _breakLineObjectOverrule = new BreakLineObjectOverrule();
  20.             // Фильтр "отлова" примитива по расширенным данным. Работает лучше, чем проверка вручную!
  21.             _breakLineObjectOverrule.SetXDataFilter(BreakLineDescriptor.Instance.Name);
  22.             return _breakLineObjectOverrule;
  23.         }
  24.  
  25.         public override void Close(DBObject dbObject)
  26.         {
  27.             Debug.Print(dbObject?.GetRXClass().Name);
  28.             if (IsApplicable(dbObject))
  29.             {
  30.                 try
  31.                 {
  32.                     if (AcadHelpers.Document != null)
  33.                         if (dbObject != null && dbObject.IsNewObject & dbObject.Database == AcadHelpers.Database ||
  34.                             dbObject != null && dbObject.IsUndoing & dbObject.IsModifiedXData)
  35.                         {
  36.                             var breakLine = EntityReaderFactory.Instance.GetFromEntity<BreakLine>((Entity)dbObject);
  37.                             if (breakLine != null)
  38.                             {
  39.                                 breakLine.UpdateEntities();
  40.                                 breakLine.GetBlockTableRecordForUndo((BlockReference)dbObject).UpdateAnonymousBlocks();
  41.                             }
  42.                         }
  43.                 }
  44.                 catch (Exception exception)
  45.                 {
  46.                     ExceptionBox.Show(exception);
  47.                 }
  48.             }
  49.             base.Close(dbObject);
  50.         }
  51.  
  52.         public override bool IsApplicable(RXObject overruledSubject)
  53.         {
  54.             return ExtendedDataHelpers.IsApplicable(overruledSubject, BreakLineDescriptor.Instance.Name, true);
  55.         }
  56.     }
  57. }
Подписка:
Код - C# [Выбрать]
  1. /// <inheritdoc />
  2. public void Initialize()
  3. {
  4.     Overrule.AddOverrule(RXObject.GetClass(typeof(BlockReference)), BreakLineObjectOverrule.Instance(), true);
  5. }
  6.  
  7. /// <inheritdoc />
  8. public void Terminate()
  9. {
  10.     Overrule.RemoveOverrule(RXObject.GetClass(typeof(BlockReference)), BreakLineObjectOverrule.Instance());
  11. }

А вот тут (https://drive-cad-with-code.blogspot.com/search?q=overrule) можно найти много примеров с описаниями
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 03-02-2019, 17:07:30
вот "подписку" я как раз и искал.
спасибо! буду пробовать!
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 03-02-2019, 17:48:15
_breakLineObjectOverrule.SetXDataFilter(BreakLineDescriptor.Instance.Name);

это значит что Close() вызовется только для объектов с этим приложением в xdata?
Название: Re: ObjectOverrule.Close
Отправлено: Александр Пекшев aka Modis от 03-02-2019, 17:58:36
это значит что Close() вызовется только для объектов с этим приложением в xdata?
Это значит, что блоки дополнительно фильтруются по наличию XData с AppName равным тому, что у меня записано в переменной BreakLineDescriptor.Instance.Name

Лучше смотрите примеры, на которые я вам ссылку дал
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 03-02-2019, 18:39:53
другие объекты лучше обрабатывать/изменять/создавать не в ObjectOverrule.Close? или можно тут же?
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 03-02-2019, 21:48:28
видимо можно..

после создания объекта еще раз возникает isModified
как его отфильтровать?

у меня вот так
Код - C# [Выбрать]
  1. dbObject.IsModified && !dbObject.IsNewObject && dbObject.IsWriteEnabled
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 04-02-2019, 10:12:24
возникла такая же проблема http://adn-cis.org/forum/index.php?topic=7813.msg26217#msg26217
ошибка при открытии транзакции.

UPD:
решилось заменой транзакции на Open
(причину б узнать почему на транзакции падает)
Название: Re: ObjectOverrule.Close
Отправлено: Дмитрий Загорулькин от 04-02-2019, 14:01:14
причину б узнать почему на транзакции падает
Потому что гладиолус! :)
Если серьёзно - то 100% причину вряд ли кто-то назовёт. Разве что Александр Наумович знает что-то об этом.
Просто надо взять себе за правило - в "продвинутых" случаях использовать транзакцию не стоит: в обработчиках событий с объектами БД чертежа, в методах любых Overrule и т.п.
Название: Re: ObjectOverrule.Close
Отправлено: Александр Пекшев aka Modis от 04-02-2019, 14:03:22
в "продвинутых" случаях использовать транзакцию не стоит
Иногда прокатывает OpenCloseTransaction, что по сути примерно тоже самое. Но в случае с overrule - только методом проб ошибок можно выявить рабочий вариант)
Название: Re: ObjectOverrule.Close
Отправлено: Дмитрий Загорулькин от 04-02-2019, 14:17:55
Иногда прокатывает OpenCloseTransaction, что по сути примерно тоже самое.
Если имеется в виду, что OpenCloseTransaction - это примерно то же самое, что и транзакция, то это не так. Это её эмуляция с помощью спрятанных внутри вызовов Open и Close. Может облегчить жизнь при работе с несколькими одновременно открываемыми объектами. Но иногда из-за того, что объекты долго остаются открытыми (до самого вызова Commit) могут возникнуть ошибки. А по сути - это то же самое, что и использование Open-Close, но с интерфейсом транзакции.
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 04-02-2019, 14:25:23
Так незаметно повысился до статуса продвинутый) приятно
Да после теста с Open, заменил все на OpenCloseTransaction-работает!

Полезное замечение. Спасибо!
Просто надо взять себе за правило - в "продвинутых" случаях использовать транзакцию не стоит: в обработчиках событий с объектами БД чертежа, в методах любых Overrule и т.п.
А можно "и т.п." развернуть?
Название: Re: ObjectOverrule.Close
Отправлено: Александр Пекшев aka Modis от 04-02-2019, 14:25:41
А по сути - это то же самое, что и использование Open-Close
я это и имел ввиду )
Название: Re: ObjectOverrule.Close
Отправлено: Дмитрий Загорулькин от 04-02-2019, 14:38:21
А можно и т.п. развернуть?
Официальных данных по этому вопросу либо совсем нет, либо их мало. Поэтому - всё опытным путём, методом проб и ошибок. Поэтому, я стараюсь вообще не использовать транзакции. Нигде. Но это не всегда получается. Например, в Civil 3D API, с которым я чаще всего имею дело, есть несколько методов, для корректной работы которых требуется явный запуск транзакции.
Неиспользование транзакций требует больше внимания от программиста. Но зато меньше шансов, что в будущем появится какая-то непредвиденная плавающая ошибка. Если не используются транзакции - ошибки вылезают сразу :)
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 04-02-2019, 15:55:38
Например, в Civil 3D API, с которым я чаще всего имею дело, есть несколько методов, для корректной работы которых требуется явный запуск транзакции.
еще немного подробностей) какие?
Название: Re: ObjectOverrule.Close
Отправлено: Дмитрий Загорулькин от 04-02-2019, 15:58:24
еще немного подробностей) какие?
Опять же - выясняется методом проб и ошибок: http://adn-cis.org/forum/index.php?topic=8589.0
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 04-02-2019, 16:05:37
Т е вы не используете даже OpenCloseTransaction? ну стараетесь..
GetObject с OpenCloseTransaction работает?
Название: Re: ObjectOverrule.Close
Отправлено: Александр Ривилис от 04-02-2019, 16:19:55
GetObject с OpenCloseTransaction работает?
Нет. Только с обычной транзакцией.
Т е вы не используете даже OpenCloseTransaction? ну стараетесь..
Open/Close и OpenCloseTransaction - это тоже самое, но иногда важно закрыть объект/примитив принудительно в нужный момент. И в этом случае OpenCloseTransaction неудобна.
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 04-02-2019, 16:22:23
Т е "устаревший" Open/Close самый надежный выходит, если внимательно использовать)

Спасибо за ответы)
Название: Re: ObjectOverrule.Close
Отправлено: Александр Ривилис от 04-02-2019, 16:31:40
Т е "устаревший" Open/Close самый надежный выходит, если внимательно использовать)

Спасибо за ответы)
Я чаще всего использую конструкцию вида:
Код - C# [Выбрать]
  1. using (Entity ent = id.Open(OpenMode.ForRead) as Entity)
  2. {
  3.   // Здесь обработка
  4. }

В конце блока using автоматически вызывается ent.Dispose(), что в свою очередь вызывает ent.Close() для объекта/примитива в базе.
Единственный случай когда предпочтительнее обычная транзакция - это массовое изменение объектов/примитивов. Во всяком случае считается, что в транзакции это происходит быстрее. А вот на единичных чтениях/записях транзакции проигрывают в скорости, т.к. тратится время на запуск/завершение транзакции.
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 05-02-2019, 12:12:55
после создания объекта еще раз возникает isModified
как его отфильтровать?

у меня вот так
Код - C# [Выбрать]
dbObject.IsModified && !dbObject.IsNewObject && dbObject.IsWriteEnabled


а с этим есть идеи? если работаю с полилинией то он один лишний раз заходит в этот метод есть с Pipe(немножко не по адресу может), то раз 5
хотелось бы чтоб один раз попадал в эту ветку.
Название: Re: ObjectOverrule.Close
Отправлено: Дмитрий Загорулькин от 05-02-2019, 12:30:12
Что значит "лишний раз"? Объекты открываются-закрываются при необходимости получить из них какие-то данные. Полилиния - довольно простой объект, а вот труба уже гораздо сложнее. Она связана с другими объектами чертежа. Получается так: изменили трубу -> изменилась труба на виде профиля (это отдельный объект) -> изменились присоединённые колодцы -> изменилась метка трубы на плане -> изменилась метка трубы на профиле и т.д. При этом, чтобы получить нужные для связанных объектов данные, каждый раз труба открывается-закрывается.
хотелось бы чтоб один раз попадал в эту ветку
В метод Close? Но это нереально. Труба же закрывается, значит, метод вызывается. Можно лишь проверять условия и если они неподходящие, то не выполнять обработку.
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 05-02-2019, 13:48:13
Да я именно прл фильтррацию в методе close. Я написал какие условия я использовал. Но все равно раз 5 все равно попадаю туда, соотвественно все алгоритмы по 5 раз проходят. Не знаю какие еще условия можно прописать чтоб в идеале 1 раз туда зайти.
Название: Re: ObjectOverrule.Close
Отправлено: Александр Ривилис от 05-02-2019, 13:56:23
Не знаю какие еще условия можно прописать чтоб в идеале 1 раз туда зайти.
Думаю, что никак...
Название: Re: ObjectOverrule.Close
Отправлено: Дмитрий Загорулькин от 05-02-2019, 13:57:10
Без полного понимания того какие обработки выполняются и для чего сложно что-то подсказать. Пример кода нужен.
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 05-02-2019, 14:37:04
просто нужно узнать измененную точку конца и начала трубы, записать ее, выйти
получается что по 5 раз ее перезаписывает - нехорошо
Название: Re: ObjectOverrule.Close
Отправлено: Александр Ривилис от 05-02-2019, 14:48:35
просто нужно узнать измененную точку конца и начала трубы
Изменяется пользователем или твоим кодом?
Название: Re: ObjectOverrule.Close
Отправлено: Дмитрий Загорулькин от 05-02-2019, 15:01:05
получается что по 5 раз ее перезаписывает
Куда перезаписывает?
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 05-02-2019, 15:11:15
пользователь двигает, я записываю в XData
Название: Re: ObjectOverrule.Close
Отправлено: Дмитрий Загорулькин от 05-02-2019, 15:15:12
В методе Open - получение начальной и конечной точки. В методе Close - снова их получаем и сравниваем с теми значениями, которые получены в Open. Если не совпадают - перезаписываем XData.
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 05-02-2019, 15:35:02
Ну т е это будет происходить 5 раз? в любом случае..
Название: Re: ObjectOverrule.Close
Отправлено: Дмитрий Загорулькин от 05-02-2019, 15:40:15
Проверка - да, перезапись XData - только один раз. И только если положение действительно изменилось.
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 05-02-2019, 15:51:04
Понял, спасибо!
Название: Re: ObjectOverrule.Close
Отправлено: Александр Ривилис от 05-02-2019, 16:35:32
пользователь двигает, я записываю в XData
Когда пользователь двигает Close может происходить несколько раз даже без твоего кода.
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 06-02-2019, 17:13:03
получается так, что в попытке открыть соседние объекты, получаю ошибку, что один из них уже открыт для записи
работаю с OpenCloseTransaction
Open/Close не спасет да?
как быть?

и играет ли роль когда вызывать   base.Close(dbObject)  до своих инструкций или после?
Название: Re: ObjectOverrule.Close
Отправлено: Дмитрий Загорулькин от 06-02-2019, 17:54:58
получается так, что в попытке открыть соседние объекты, получаю ошибку, что один из них уже открыт для записи
работаю с OpenCloseTransaction
Open/Close не спасет да?
как быть?
Значит, придётся открывать соседние объекты в каком-то другом месте (в какой-то другой момент). Метод Close для этого не подходит, получается.
и играет ли роль когда вызывать   base.Close(dbObject)  до своих инструкций или после?
Смотря что эти инструкции делают.
Название: Re: ObjectOverrule.Close
Отправлено: Александр Ривилис от 06-02-2019, 18:16:01
и играет ли роль когда вызывать   base.Close(dbObject)  до своих инструкций или после?
Только если ты его же пытаешься открыть.
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 07-02-2019, 13:23:33
В методе Open - получение начальной и конечной точки. В методе Close - снова их получаем и сравниваем с теми значениями, которые получены в Open. Если не совпадают - перезаписываем XData.

Происходит так, что открываются для записи все трубы, что есть в чертеже (хотя в данный момент я их не трогаю), якобы для модфикации. пересохраняют последовательно точки начальные и конечные!
а потом так же последовательно закрываются и получается что сравниваются точки последнего открытого объекта, соответственно все изменяются т к точки разные
Отфильтровать их у меня не получилось..
что тогда словарь создавать и соотносить точки с конкретным объектом, их и сравнивать? постоянно хранить в памяти словарь со всеми точками? или есть другой выход
Название: Re: ObjectOverrule.Close
Отправлено: Александр Ривилис от 07-02-2019, 13:27:20
что тогда словарь создавать и соотносить точки с конкретным объектом, их и сравнивать?
Конечно. А как иначе?
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 07-02-2019, 13:28:34
я честно говоря рассчитывал что они последовательно откроются закроются и как раз сравню соответствующие точки.. наивно рассчитывал..
понял, спасибо!
Название: Re: ObjectOverrule.Close
Отправлено: Александр Ривилис от 07-02-2019, 13:31:39
наивно рассчитывал..
Конечно наивно рассчитывал. Если используют транзакцию, то условно говоря идут последовательные Open для всех объектов, открываемых в транзакции, а затем последовательные Close при вызове Transaction.Commit().
Да и для обычных Open/Close тоже возможны различные варианты. Например для проверки пересечения IntersectWith требуется, чтобы они оба были открыты. Т.е. два Open, а затем два Close.
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 07-02-2019, 13:33:04
Логично, понял!
еще одно уточнение словарь такого вида Dictionary<ObjectId,Point3d[]> ?
Название: Re: ObjectOverrule.Close
Отправлено: Александр Ривилис от 07-02-2019, 13:34:50
Логично, понял!
еще одно уточнение словарь такого вида Dictionary<ObjectId,Point3d[]> ?
Думаю, что подойдёт.
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 07-02-2019, 13:35:24
или можно прям вот так  Dictionary<Pipe,Point3d[]>  ?
Название: Re: ObjectOverrule.Close
Отправлено: Александр Ривилис от 07-02-2019, 13:36:19
или можно прям вот так  Dictionary<Pipe,Point3d[]>  ?

Нет. Нарвёшься, на ошибки.
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 18-02-2019, 15:03:12
GetObject с OpenCloseTransaction работает?
Нет. Только с обычной транзакцией.

а TopTransaction с открытой OpenCloseTransaction тоже не прокатит я так понимаю...
т е OpenCloseTransaction только передавать?
Название: Re: ObjectOverrule.Close
Отправлено: Дмитрий Загорулькин от 18-02-2019, 15:11:12
Это такой ребус? О чём вообще речь?
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 18-02-2019, 15:52:51
наверное опять немного оффтоп( просто тут была затронута эта тема.
GetObject работает только с обычной Transaction. Вопрос туда же: TransactionManager.TopTransaction вернет тоже обычную Transaction, следовательно, OpenCloseTransaction можно только из метода в метод передавать?
Название: Re: ObjectOverrule.Close
Отправлено: Дмитрий Загорулькин от 18-02-2019, 15:59:09
Можно и передавать. Но универсальнее и надёжнее передавать ObjectId, а в методе уже открывать или новую OpenCloseTransaction, или просто с помощью  Open. Или передавать объекты уже открытыми.
Название: Re: ObjectOverrule.Close
Отправлено: simson43 от 18-02-2019, 16:03:38
Спасибо!
остановился на 1 варианте)
Название: Re: ObjectOverrule.Close
Отправлено: Александр Ривилис от 18-02-2019, 16:49:03
Но универсальнее и надёжнее передавать ObjectId
При условии, что этот объект еще не открыт.