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

ADN Club => AutoCAD .NET API => Тема начата: Алексей Терно от 19-04-2019, 11:20:22

Название: Removing something that wasn't added?
Отправлено: Алексей Терно от 19-04-2019, 11:20:22
Прислали мне несколько чертежей для тестирования. При открытия одного из них я получаю вот такое сообщение:
(https://i.postimg.cc/8zPQwL1P/2019-04-19-10-33-43.png)
Прервать - закрытие автокада/сивила.
Повтор - отладка в VS.
Пропустить - все загружается и работает, но после закрытия этого чертежа или переключении на другой появляется вот такое сообщение:
(https://i.postimg.cc/wjS23db8/2019-04-19-10-37-26.png)

В первом сообщении я нашел упоминание события EnteringQuiescentState. При отладке он показывает в методе Initialize эту строчку:
Код - C# [Выбрать]
  1. ed.EnteringQuiescentState -= new EventHandler(ed_EnteringQuiescentState);

При открытии других чертежей таких сообщений нет. Что это такое?
Название: Re: Removing something that wasn't added?
Отправлено: Дмитрий Загорулькин от 19-04-2019, 13:30:41
С событиями редактора надо быть аккуратным. Он не прощает отписки от события, на который не было ранее подписки и вот таким образом ругается.
Название: Re: Removing something that wasn't added?
Отправлено: Алексей Терно от 19-04-2019, 13:35:41
Тогда эта ошибка должна вылезать везде, а она появляется в некоторых чертежах.
Название: Re: Removing something that wasn't added?
Отправлено: Александр Ривилис от 19-04-2019, 13:40:47
Тогда эта ошибка должна вылезать везде, а она появляется в некоторых чертежах.
Нужно смотреть логику, которая у тебя прописана в Initialize. Возможно этот код не всегда вызывается. Но в любом случае Дмитрий Загорулькин абсолютно прав. Как минимум этот код следует обернуть в try/catch.
Название: Re: Removing something that wasn't added?
Отправлено: Алексей Терно от 19-04-2019, 13:47:40
Нужно смотреть логику, которая у тебя прописана в Initialize. Возможно этот код не всегда вызывается.
Логика проста - я подписываюсь на события, которые мне необходимы, а потом добавление переопределений. Эта строчка должна вызываться всегда.
И да, Дима прав - я убрал из Initialize отписку от этого события и эта проблема ушла.
Я оставил пару отписка-подписка в событиях DocumentCreated и DocumentActivated. По идее в них такой проблемы не должно быть.
Название: Re: Removing something that wasn't added?
Отправлено: Дмитрий Загорулькин от 19-04-2019, 15:07:26
Я оставил пару отписка-подписка в событиях DocumentCreated и DocumentActivated. По идее в них такой проблемы не должно быть.
Плохая идея.
Название: Re: Removing something that wasn't added?
Отправлено: Алексей Терно от 19-04-2019, 15:10:03
Плохая идея.
Ты предлагаешь и там убрать отписку?
Название: Re: Removing something that wasn't added?
Отправлено: Вильдар от 19-04-2019, 15:15:11
Плохая идея.
А почему?
Через трай-катч, тоже так делаю.
Название: Re: Removing something that wasn't added?
Отправлено: Дмитрий Загорулькин от 19-04-2019, 15:21:57
Плохая идея использовать пару отписка-подписка с событиями редактора. Думаю, в данном случае надёжнее будет если сохранять состояние подписки в переменной. Подписались - значение в true. Отписались - значение в false. Собираемся подписываться или отписываться - проверяем переменную состояния.
Название: Re: Removing something that wasn't added?
Отправлено: Дмитрий Загорулькин от 19-04-2019, 15:27:21
Через трай-катч, тоже так делаю.
Лучше бы вообще не доводить до состояния, когда возникает исключение. Иногда такие исключения вроде как отлавливаются, но после этого что-то внутри автокада нарушается...
Название: Re: Removing something that wasn't added?
Отправлено: Александр Ривилис от 19-04-2019, 17:56:21
Плохая идея.
Ты предлагаешь и там убрать отписку?
Отписываться можно только если подписался. Иначе в лучшем случае исключение, в худшем Fatal Error (зависит от типа события).
Название: Re: Removing something that wasn't added?
Отправлено: Алексей Терно от 20-04-2019, 12:43:18
Не отлавливается отписка от события EnteringQuiescentState трайкэтчем - все равно выскакивает это исключение. Теперь уже предложение Димы сохранять состояние подписки не кажется мне излишним )) Я думаю создать глобальный список пар [Document.Database.BlockTableId]-[состояние подписки] и пополнять его при создании или открытии чертежа.
Название: Re: Removing something that wasn't added?
Отправлено: Алексей Терно от 20-04-2019, 13:43:35
Вот так вот я сделал:
Код - C# [Выбрать]
  1. public class ImplementClass0 : IExtensionApplication
  2. {
  3.     //тут я храню id всех открытых в текущий момент чертежей
  4.     //это коллекция отслеживания
  5.     private List<ObjectId> btids = new List<ObjectId>();
  6.  
  7.     public void Initialize()
  8.     {
  9.         if (Application.DocumentManager.MdiActiveDocument == null)
  10.             return;
  11.  
  12.         Document doc = Application.DocumentManager.MdiActiveDocument;
  13.         Database db = doc.Database;
  14.         Editor ed = doc.Editor;
  15.  
  16.         Application.DocumentManager.DocumentCreated += new DocumentCollectionEventHandler(doc_DocumentCreated);
  17.         Application.DocumentManager.DocumentActivated += new DocumentCollectionEventHandler(doc_DocumentActivated);
  18.         Application.DocumentManager.DocumentToBeDestroyed += new DocumentCollectionEventHandler(doc_DocumentDestroyed);
  19.  
  20.         //сразу подписываюсь на события активного чертежа и добавляю его в коллекцию отслеживания
  21.         btids.Add(db.BlockTableId);
  22.         addreactors(doc, db, ed);
  23.     }
  24.  
  25.     public void Terminate()
  26.     {
  27.         throw new NotImplementedException();
  28.     }
  29.  
  30.     public void addreactors(Document _doc, Database _db, Editor _ed)
  31.     {
  32.         _doc.Database.SystemVariableChanged += new Autodesk.AutoCAD.DatabaseServices.SystemVariableChangedEventHandler(db_SystemVariableChanged);
  33.         _doc.ImpliedSelectionChanged += new EventHandler(doc_SelectionChanged);
  34.         _doc.CommandWillStart += new CommandEventHandler(doc_MonitorCommandWillStarted);
  35.         _doc.CommandEnded += new CommandEventHandler(doc_MonitorCommandEnded);
  36.         _db.ObjectAppended += new ObjectEventHandler(db_MonitorObjectAppended);
  37.         _ed.EnteringQuiescentState += new EventHandler(ed_EnteringQuiescentState);
  38.     }
  39.  
  40.     public void doc_DocumentCreated(object sender, DocumentCollectionEventArgs e)
  41.     {
  42.         if (e.Document == null || e.Document.Database == null)
  43.             return;
  44.  
  45.         Document doc = Application.DocumentManager.MdiActiveDocument;
  46.         Database db = doc.Database;
  47.         Editor ed = doc.Editor;
  48.  
  49.         //если докемнт только что создан, значит подписки на события еще не было - подписываюсь
  50.         btids.Add(db.BlockTableId);
  51.         addreactors(doc, db, ed);
  52.     }
  53.  
  54.     public void doc_DocumentActivated(object sender, DocumentCollectionEventArgs e)
  55.     {
  56.         if (e.Document == null || e.Document.Database == null)
  57.             return;
  58.  
  59.         Document doc = Application.DocumentManager.MdiActiveDocument;
  60.         Database db = doc.Database;
  61.         Editor ed = doc.Editor;
  62.  
  63.         //если id чертежа есть в коллекции отслеживания, то подписка уже была, в противном случае - подписываюсь
  64.         if (!btids.Contains(db.BlockTableId))
  65.         {
  66.             btids.Add(db.BlockTableId);
  67.             addreactors(doc, db, ed);
  68.         }
  69.     }
  70.  
  71.     public void doc_DocumentDestroyed(object sender, DocumentCollectionEventArgs e)
  72.     {
  73.         //при закрытии чертежа удаляю его id из коллекции отслеживания
  74.         if (btids.Contains(e.Document.Database.BlockTableId))
  75.             btids.Remove(e.Document.Database.BlockTableId);
  76.     }
  77. }
Название: Re: Removing something that wasn't added?
Отправлено: Дмитрий Загорулькин от 20-04-2019, 14:33:07
Интересно, сработает или нет? Попробуй открыть новый чертёж командой Open, но когда откроется диалог выбора чертежа - нажми "Отмена". Должен случиться эксепшн. Отбой, увидел проверку :)
И ещё посмотри в 27 строку своего кода.
Название: Re: Removing something that wasn't added?
Отправлено: Алексей Терно от 20-04-2019, 14:40:39
посмотри в 27 строку своего кода
А, да - это стандартная строчка осталась от примера ))
Название: Re: Removing something that wasn't added?
Отправлено: Александр Ривилис от 20-04-2019, 14:49:22
Алексей Терно,
У несколько вопросов к коду.
1. Почему коллекция ObjectId вместо коллекции Document?
2. Зачем в addreactors передавать три параметра вместо одного?
Название: Re: Removing something that wasn't added?
Отправлено: Алексей Терно от 20-04-2019, 15:03:57
Алексей Терно,
У несколько вопросов к коду.
1. Почему коллекция ObjectId вместо коллекции Document?
2. Зачем в addreactors передавать три параметра вместо одного?

1. У меня были опасения, что Document будет меняться при изменении Database. ObjectId меняться не будет.
2. У меня нет адекватного ответа на этот вопрос ))
Название: Re: Removing something that wasn't added?
Отправлено: Александр Ривилис от 20-04-2019, 15:25:37
1. У меня были опасения, что Document будет меняться при изменении Database.
Эту фразу не понял.