Ошибка при работе с блоком содержащий OverRule графику

Автор Тема: Ошибка при работе с блоком содержащий OverRule графику  (Прочитано 2486 раз)

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

Оффлайн Дима_Автор темы

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
У меня есть большая ACAD библиотека которая взаимодействует с ИС предприятия. В ней, в том числе, содержится переопределение отображения графики (привязок и пр.). Пользователи обнаружили странное исчезновение при включенном доп. отображении. Таинственные исчезновения происходят при работе с блоками, в которых содержаться видоизмененные примитивы. Исчезнет часть (или вся графика) зависит от содержания блока (и как выяснилось, похоже даже от порядка примитивов в блоке - см пример ниже). Методом "обрезки всего лишнего" удалось локализовать причину возникновения и создать минимальный код демонстрирующий проблему:
Код - C# [Выбрать]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using Autodesk.AutoCAD.ApplicationServices;
  7. using Autodesk.AutoCAD.DatabaseServices;
  8. using Autodesk.AutoCAD.EditorInput;
  9. using Autodesk.AutoCAD.Runtime;
  10. using gr=Autodesk.AutoCAD.GraphicsInterface;
  11.  
  12. namespace OverruleBugExample
  13. {
  14.     public class OverRule : gr.DrawableOverrule
  15.     {
  16.         public override bool WorldDraw(gr.Drawable drawable, gr.WorldDraw wd)
  17.         {
  18.             if (drawable is Polyline pl)
  19.             //if (drawable is Polyline pl && pl.ObjectId.IsValid && !pl.ObjectId.IsErased) // можно и так - по примеру бага ничего не изменится
  20.             {
  21.                 // без этого блока баг не проявляется
  22.                 using (var tr = Application.DocumentManager.MdiActiveDocument.TransactionManager.StartTransaction())
  23.                 {
  24.                     tr.Commit();
  25.                 }
  26.                 // просто для примера работы отображения - без этого блока баг так-же проявляется
  27.                 using (var circ = new Circle { Center = pl.StartPoint, Radius = 50 })
  28.                 {
  29.                     circ.WorldDraw(wd);
  30.                 }
  31.             }
  32.             return base.WorldDraw(drawable, wd);
  33.         }
  34.     }
  35.    
  36.     public class BugExample
  37.     {
  38.         private bool isOn = false;
  39.         private readonly OverRule over=new OverRule();
  40.        
  41.         [CommandMethod("OverBug")]
  42.         public void OverBug()
  43.         {
  44.             var ed = Application.DocumentManager.MdiActiveDocument.Editor;
  45.             if (isOn)
  46.             {
  47.                 Overrule.RemoveOverrule(RXClass.GetClass(typeof(Polyline)), over);
  48.                 isOn = false;
  49.                 ed.Regen();
  50.                 ed.WriteMessage("\nOverrule off");
  51.             }
  52.             else
  53.             {
  54.                 Overrule.AddOverrule(RXClass.GetClass(typeof(Polyline)), over, true);
  55.                 isOn = true;
  56.                 ed.Regen();
  57.                 ed.WriteMessage("\nOverrule on");
  58.             }
  59.         }
  60.     }
  61. }
  62.  

Суть проблемы при взрыве либо, при контекстном редактировании блока "по месту" может исчезать все, либо часть примитивов (причем обычно остается та часть которая имеет переопределение). В примере 2 одинаковых блока, но у левого (на экране) вначале был создан прямоугольник, а затем линия - и он взрыв переживает нормально, у правого наоборот - он полностью исчезает после взрыва (до команды regen.). Повторю, на более сложных блоках картина может отличаться - исчезнуть часть, и исчезнуть до "перегрузки" документа. Баг проявляется только при открытии транзакции внутри обработчика (в данном примере она не нужна, т.к. ничего не делает, но в реальном нужна - т.к. надо считывать расширенные данные и иногда другие примитивы.) Баг появится вне зависимости от наличия непосредственно транзитной графики (то есть можем ничего не выводить, достаточно открыть и закоментить транзакцию).

Вне блоков поведение абсолютно нормальное никаких ошибок не выявляется.

Отмечено как Решение Дима_ 24-01-2021, 10:03:31

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Баг проявляется только при открытии транзакции внутри обработчика (в данном примере она не нужна, т.к. ничего не делает, но в реальном нужна - т.к. надо считывать расширенные данные и иногда другие примитивы.)
1. Подтверждаю для AutoCAD 2021. После регенерации всё восстанавливается.
2. Не проявляется если использовать эмуляцию транзакции:
Код - C# [Выбрать]
  1. using (var tr = Application.DocumentManager.MdiActiveDocument.TransactionManager.StartOpenCloseTransaction())
  2.         {
  3.           tr.Commit();
  4.         }
Вообще рекомендую в событиях и в оверулинге использовать эмуляцию транзакции, а не обычную транзакцию.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дима_Автор темы

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Спасибо, попробую применить на более сложных манипуляциях и отпишусь. Напомните пж. (или дайте ссылку), в чем разница между транзакцией и эмуляцией (я помню, что  использовал, но не могу даже найти где).
P. S. У автокада, есть "исторически сложившиеся" API, подход в которых никак не запоминается в моей голове, и я уже не первый раз их заново для себя открываю (а ну точно, тут же так),  такие казусы есть не только у автокада, но он у меня явный рекордсмен.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
В качестве ссылки: https://adn-cis.org/sozdanie-polyline3d-bez-ispolzovaniya-tranzakczii.html
Главное отличие эмуляции транзакции от обычной транзакции для программиста связано с ограничением, запрещающим повторное открытие одного и того же объекта в ряде случаев:

Обычная транзакция в этом плане менее строгая.
В остальном же для тебя должно быть достаточно замены StartTransaction на StartOpenCloseTransaction.
 
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дима_Автор темы

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
В остальном же для тебя должно быть достаточно замены StartTransaction на StartOpenCloseTransaction.
К сожалению, на "боевом" примере так не получилось (дальше по коду куча null'ов - т.к. вызывается GetObject по TopTransaction) - если появится решение как можно применять обычную транзакцию - напишите пж. - мне это очень поможет, пока пост выше отмечаю как решение - видимо придется править кучу методов, на "безтранзакционное" открытие.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
т.к. вызывается GetObject по TopTransaction
Ну тут или переписывать код или придумывать переопределение для TopTransaction, чтобы он возвращал OpenCloseTransaction (если это возможно). Кстати, это не значит, что везде нужно отказываться от обычной транзакции.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение