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

ADN Club => AutoCAD .NET API => Тема начата: Дима_ от 23-01-2021, 10:00:02

Название: Ошибка при работе с блоком содержащий OverRule графику
Отправлено: Дима_ от 23-01-2021, 10:00:02
У меня есть большая 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.). Повторю, на более сложных блоках картина может отличаться - исчезнуть часть, и исчезнуть до "перегрузки" документа. Баг проявляется только при открытии транзакции внутри обработчика (в данном примере она не нужна, т.к. ничего не делает, но в реальном нужна - т.к. надо считывать расширенные данные и иногда другие примитивы.) Баг появится вне зависимости от наличия непосредственно транзитной графики (то есть можем ничего не выводить, достаточно открыть и закоментить транзакцию).

Вне блоков поведение абсолютно нормальное никаких ошибок не выявляется.
Название: Re: Ошибка при работе с блоком содержащий OverRule графику
Отправлено: Александр Ривилис от 23-01-2021, 21:53:32
Баг проявляется только при открытии транзакции внутри обработчика (в данном примере она не нужна, т.к. ничего не делает, но в реальном нужна - т.к. надо считывать расширенные данные и иногда другие примитивы.)
1. Подтверждаю для AutoCAD 2021. После регенерации всё восстанавливается.
2. Не проявляется если использовать эмуляцию транзакции:
Код - C# [Выбрать]
  1. using (var tr = Application.DocumentManager.MdiActiveDocument.TransactionManager.StartOpenCloseTransaction())
  2.         {
  3.           tr.Commit();
  4.         }
Вообще рекомендую в событиях и в оверулинге использовать эмуляцию транзакции, а не обычную транзакцию.
Название: Re: Ошибка при работе с блоком содержащий OverRule графику
Отправлено: Дима_ от 23-01-2021, 23:06:02
Спасибо, попробую применить на более сложных манипуляциях и отпишусь. Напомните пж. (или дайте ссылку), в чем разница между транзакцией и эмуляцией (я помню, что  использовал, но не могу даже найти где).
P. S. У автокада, есть "исторически сложившиеся" API, подход в которых никак не запоминается в моей голове, и я уже не первый раз их заново для себя открываю (а ну точно, тут же так),  такие казусы есть не только у автокада, но он у меня явный рекордсмен.
Название: Re: Ошибка при работе с блоком содержащий OverRule графику
Отправлено: Александр Ривилис от 23-01-2021, 23:42:09
В качестве ссылки: https://adn-cis.org/sozdanie-polyline3d-bez-ispolzovaniya-tranzakczii.html
Главное отличие эмуляции транзакции от обычной транзакции для программиста связано с ограничением, запрещающим повторное открытие одного и того же объекта в ряде случаев:
(https://live.staticflickr.com/65535/50867853907_55c2843db0_o.png)
Обычная транзакция в этом плане менее строгая.
В остальном же для тебя должно быть достаточно замены StartTransaction на StartOpenCloseTransaction.
 
Название: Re: Ошибка при работе с блоком содержащий OverRule графику
Отправлено: Дима_ от 24-01-2021, 10:03:24
В остальном же для тебя должно быть достаточно замены StartTransaction на StartOpenCloseTransaction.
К сожалению, на "боевом" примере так не получилось (дальше по коду куча null'ов - т.к. вызывается GetObject по TopTransaction) - если появится решение как можно применять обычную транзакцию - напишите пж. - мне это очень поможет, пока пост выше отмечаю как решение - видимо придется править кучу методов, на "безтранзакционное" открытие.
Название: Re: Ошибка при работе с блоком содержащий OverRule графику
Отправлено: Александр Ривилис от 24-01-2021, 15:15:46
т.к. вызывается GetObject по TopTransaction
Ну тут или переписывать код или придумывать переопределение для TopTransaction, чтобы он возвращал OpenCloseTransaction (если это возможно). Кстати, это не значит, что везде нужно отказываться от обычной транзакции.