Перестает работать функция (обработчик событий)

Автор Тема: Перестает работать функция (обработчик событий)  (Прочитано 29461 раз)

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

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Всем привет. Заголовок темы не совсем корректный, по причине того, что я даже и не знаю ЧТО перестает работать  :D

В общих чертах работа функции:
1. Обработка события завершения команды - запоминаем нужные объекты (примитивы)
2. Обработка события добавления объекта в БД чертежа - запомненные объекты изменяются как мне нужно
3. Значение "вкл/выкл" функции хранится в XData чертежа
4. При переключении документов читается значение из XData чертежа, чтобы включить/выключить работу функции

В общем проблема в том, что я не знаю в чем проблема :D
Как таковых ошибок не возникает (try{}catch{} ничего не ловит). Функция работает, работает, работает, а потом в какой-то момент бац - и перестает работать. ПРЕДПОЛОЖИТЕЛЬНО дело связано с переключение между документами (еще вариант - переключение между моделью и листом). Чтобы заставить функцию работать снова приходится закрывать документ и открывать заново

Вырезал из кода основные моменты. Где-то тут и происходит стопор:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3.  
  4. namespace ClassLibrary2
  5. {
  6.     public class Class1
  7.     {
  8.         public void Initialize()
  9.         {
  10.             Application.DocumentManager.DocumentCreated += DocumentManager_DocumentCreated;
  11.         }
  12.  
  13.         private void DocumentManager_DocumentCreated(object sender, DocumentCollectionEventArgs e)
  14.         {
  15.             // Чтение данных из расширенных данных чертежа
  16.             // код не привожу, т.к. для вопроса не важен
  17.             if (!MpCadHelpers.HasXDataDictionary("MP_LayerToEnt"))
  18.                 return;
  19.             if (MpCadHelpers.GetStringXData("MP_LayerToEnt").Equals("ON"))
  20.             {
  21.                 MpLayerAutoFunctions.LayerAutoIsEventOn = true;
  22.                 this.On();
  23.             }
  24.             else
  25.             {
  26.                 MpLayerAutoFunctions.LayerAutoIsEventOn = false;
  27.                 this.Off();
  28.             }
  29.         }
  30.  
  31.         // Коллекция ObjectId
  32.         public ObjectIdCollection ObjCol;
  33.         // Переменная служит для определения включена ли работа функции
  34.         public static bool LayerAutoIsEventOn;
  35.  
  36.         public void On()
  37.         {
  38.             // Создаем новую коллекцию ObjectId
  39.             ObjCol = new ObjectIdCollection();
  40.             //
  41.             LayerAutoIsEventOn = true;
  42.             // Включаем обработчики событий
  43.             Application.DocumentManager.MdiActiveDocument.Database.ObjectAppended += CallBack_ObjectAppended;
  44.             Application.DocumentManager.MdiActiveDocument.CommandEnded += CallBack_CommandEnded;
  45.             Application.DocumentManager.MdiActiveDocument.CommandCancelled += CallBack_CommandEnded;
  46.             Application.DocumentManager.MdiActiveDocument.CommandFailed += MdiActiveDocument_CommandFailed;
  47.             Application.DocumentManager.DocumentActivated += DocumentManager_DocumentActivated;
  48.         }
  49.         private void DocumentManager_DocumentActivated(object sender, DocumentCollectionEventArgs e)
  50.         {
  51.             // Очищаем список
  52.             ObjCol?.Clear();
  53.             // В переменную записывается значение из расширенных данных чертежа
  54.             // код не привожу, т.к. он не важен (в случае отсутсвия данных возвращает false)
  55.             LayerAutoIsEventOn = MpCadHelpers.GetStringXData("MP_LayerToEnt").Equals("ON");
  56.         }
  57.         // Отключение работы функции
  58.         public void Off()
  59.         {
  60.             // "Обнуляем" переменные
  61.             ObjCol = null;
  62.             LayerAutoIsEventOn = false;
  63.             // Отключаем обработчики событий
  64.             Application.DocumentManager.MdiActiveDocument.Database.ObjectAppended -= CallBack_ObjectAppended;
  65.             Application.DocumentManager.MdiActiveDocument.CommandEnded -= CallBack_CommandEnded;
  66.             Application.DocumentManager.MdiActiveDocument.CommandCancelled -= CallBack_CommandEnded;
  67.             Application.DocumentManager.MdiActiveDocument.CommandFailed -= MdiActiveDocument_CommandFailed;
  68.             Application.DocumentManager.DocumentActivated -= DocumentManager_DocumentActivated;
  69.         }
  70.         private void CallBack_CommandEnded(object sender, CommandEventArgs e)
  71.         {
  72.             if (!LayerAutoIsEventOn)
  73.                 return;
  74.             // Дальше код программы. Для вопроса не важен
  75.         }
  76.         // Команда завершилась неудачно
  77.         private void MdiActiveDocument_CommandFailed(object sender, CommandEventArgs e)
  78.         {
  79.             // Очищаем список
  80.             ObjCol?.Clear();
  81.         }
  82.         // Обработка события добавления объекта в БД чертежа
  83.         private void CallBack_ObjectAppended(object sender, ObjectEventArgs e)
  84.         {
  85.             if (!LayerAutoIsEventOn)
  86.                 return;
  87.             // Дальше код программы. Для вопроса не важен
  88.         }
  89.     }
  90. }

P.S. Работаю на 2016 автокаде. В более ранних проверить не могу

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
3. Значение "вкл/выкл" функции хранится в XData чертежа
???
1. Обработка события завершения команды - запоминаем нужные объекты (примитивы)
2. Обработка события добавления объекта в БД чертежа - запомненные объекты изменяются как мне нужно
Обычно всё наоборот - в событии добавления в базу запоминают объекты, а в событии завершения команды их обрабатывают.
По коду ничего сказать не могу. Тут надо сидеть с отладчиком.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
по поводу XData - проблем никогда вроде не возникало. Сейчас через декомпилятор посмотрел код - примерно такой:
Код - C# [Выбрать]
  1. public static string GetStringXData(string dictionaryName)
  2.         {
  3.             Document mdiActiveDocument = Application.DocumentManager.MdiActiveDocument;
  4.             if (mdiActiveDocument == null) return string.Empty;
  5.  
  6.             Database database = mdiActiveDocument.Database;
  7.             try
  8.             {
  9.                 using (mdiActiveDocument.LockDocument())
  10.                 {
  11.                     using (Transaction transaction = database.TransactionManager.StartTransaction())
  12.                     {
  13.                         ObjectId at = ((DBDictionary)transaction.GetObject(database.NamedObjectsDictionaryId, (OpenMode)1, true)).GetAt(dictionaryName);
  14.                         Xrecord xrecord = transaction.GetObject(at, (OpenMode)1, true) as Xrecord;
  15.                         string str = string.Empty;
  16.                         if (xrecord != null)
  17.                         {
  18.                             foreach (TypedValue typedValue in xrecord.Data.AsArray())
  19.                             {
  20.                                 str = @typedValue.Value.ToString();
  21.                             }
  22.                         }
  23.                         transaction.Commit();
  24.                         return str;
  25.                     }
  26.                 }
  27.             }
  28.             catch
  29.             {
  30.                 return string.Empty;
  31.             }
  32.         }
Честно - я уже и не помню где это брал. Там еще пару методов. Но проблем никогда не было.
Обычно всё наоборот - в событии добавления в базу запоминают объекты, а в событии завершения команды их обрабатывают
Верно. Это я просто напутал немного ))
По коду ничего сказать не могу. Тут надо сидеть с отладчиком
Вот тут и самая "засада" - сидел с отладчиком не один раз. Если бы проблему можно было вызвать или хотя-бы причину возникновения...
По факту - я могу работать в автокаде не один час - и все нормально. Много раз пытался поймать момент когда функция перестает работать - тщетно. Только вот подозрение и осталось на переключение между документами (или моделью/листом) - когда работаю с несколькими документами, то "поломка" происходит быстрее

Тему создал уже от безысходности. Надеюсь, что просто чей-нибудь опыт, чья-нибудь догадка/предположение помогут

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
3. Значение "вкл/выкл" функции хранится в XData чертежа
Xrecord xrecord = transaction.GetObject(at, (OpenMode)1, true) as Xrecord;
Да уж. И где у тебя XData???
1) Если ты только читаешь из чертежа, то LockDocument() не нужен. Более того в момент переключения чертежа может не сработать.
2) Попробуй убрать из кода транзакцию - можно легко без неё обойтись.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
я даже и не знаю ЧТО перестает работать
Лучше всего добавить логгирование в файл. Или запустить автокад в режиме отладки и проверить переменные.

Возможно порядок событий не так срабатывает, как ты ожидаешь. Например ты отлавливаешь
DocumentCreated
а потом сразу привязываешься к
MdiActiveDocument
DocumentActivated
а не факт что документ создался, и успел стать активным, т.е. привязка произошла к активному в данный момент документу предыдущего чертежа.
Что также может сказаться на проверке. MpCadHelpers.GetStringXData("MP_LayerToEnt").Equals("ON")

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
а не факт что документ создался, и успел стать активным, т.е. привязка произошла к активному в данный момент документу предыдущего чертежа
Интересная идея. Звучит вполне разумно - буду тестить
Но сразу возникает вопрос - если и так, то что тогда делать? О_о

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
если и так, то что тогда делать?
Скорее всего подписаться на DocumentActivated
...но это я все так, в теории.
Лучше всего Алексанра Ривилиса повыспрашивать про очередность событий документов ;-)

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Лучше всего Алексанра Ривилиса повыспрашивать про очередность событий документов ;-)
Есть четкое правило - никогда не рассчитывать на очередность событий редактора/документов.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
Возможно в public void On()
при череде удачных MpCadHelpers.GetStringXData("MP_LayerToEnt").Equals("ON")
Ты можешь несколько раз подписать функции, и они будут срабатывать по несколько раз.
Ну тут нужно про события обновить знания)

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
Есть четкое правило - никогда не рассчитывать на очередность событий редактора/документов.
Т.е. сначала может для чертежа сработать DocumentActivated, а потом DocumentCreated?

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Наш диалог натолкнул меня на мысль - переделать немного логику функции:
в события DocumentCreated и DocumentActivated запихнуть подписывание на события завершения команд и добавления объектов. А вот в них уже проверять - включена функция или нет.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
В любом случае и в DocumentCreated и в DocumentActivated ты дожен брать данные из e.Document, а не из MDIActiveDocument.
Т.е. функцию чтения нужно переписать так, чтобы она принимала в качестве еще одного аргумента Document (или Database - это уже на твоё усмотрение).
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Я сталкивался с тем, что события перестают обрабатываться, если в методе обработки возникает исключение. Это исключение может перехватить какой-нибудь try-catch, но это делу не помогает. Действительно, спасает только открытие чертежа заново или перезапуск автокада. Скорее всего, здесь то же самое - какое-то трудно отлавливаемое исключение.
Совет - сделайте вывод какого-нибудь предупреждения при попадании в блок catch. Хоть в консоль, хоть в виде MessageBox-AlertMessage. Тогда будет хотя бы ясно, в какой момент происходит сбой.
И еще, я в свое время пришел к выводу, что лучше обрабатывать событие DocumentActivated вместо DocumentCreated. Вроде бы, у меня с ним тоже были какие-то проблемы...

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Вот, кстати, как вариант того, что могло случиться:
http://adn-cis.org/forum/index.php?topic=743.msg3986#msg3986

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
В общем - я человек ленивый)) И разбираться с проблемами документов мне не захотелось
В итоге я переделал немного принцип работы. Для тестов нужно много времени, но вроде все работает нормально
Код - C# [Выбрать]
  1. public static ObjectIdCollection ObjCol;
  2. public static List<string> AcadCommands;
  3. public void Initialize()
  4. {
  5.     AcApp.DocumentManager.MdiActiveDocument.Database.ObjectAppended += CallBack_ObjectAppended;
  6.     AcApp.DocumentManager.MdiActiveDocument.CommandEnded += CallBack_CommandEnded;
  7.     AcApp.DocumentManager.MdiActiveDocument.CommandCancelled += CallBack_CommandEnded;
  8.     AcApp.DocumentManager.MdiActiveDocument.CommandFailed += MdiActiveDocument_CommandFailed;
  9.     //
  10.     AcApp.DocumentManager.DocumentActivated += DocumentManager_DocumentActivated;
  11.     AcApp.DocumentManager.DocumentCreated += DocumentManager_DocumentCreated;
  12. }
  13. public void Terminate()
  14. {
  15.     // Ничего не нужно
  16. }
  17. private static void DocumentManager_DocumentActivated(object sender, DocumentCollectionEventArgs e)
  18. {
  19.     // Очищаем список
  20.     ObjCol?.Clear();
  21.     if (e.Document != null)
  22.     {
  23.         e.Document.Database.ObjectAppended += CallBack_ObjectAppended;
  24.         e.Document.CommandEnded += CallBack_CommandEnded;
  25.         e.Document.CommandCancelled += CallBack_CommandEnded;
  26.         e.Document.CommandFailed += MdiActiveDocument_CommandFailed;
  27.     }
  28. }
  29.  
  30. static void DocumentManager_DocumentCreated(object sender, DocumentCollectionEventArgs e)
  31. {
  32.     // Очищаем список
  33.     ObjCol?.Clear();
  34.     if (e.Document != null)
  35.     {
  36.         e.Document.Database.ObjectAppended += CallBack_ObjectAppended;
  37.         e.Document.CommandEnded += CallBack_CommandEnded;
  38.         e.Document.CommandCancelled += CallBack_CommandEnded;
  39.         e.Document.CommandFailed += MdiActiveDocument_CommandFailed;
  40.     }
  41. }
  42. public static void On()
  43. {
  44.     MpCadHelpers.SetStringXData("MP_LayerToEnt", "ON");
  45. }
  46. public static void Off()
  47. {
  48.     ObjCol = null;
  49.     MpCadHelpers.SetStringXData("MP_LayerToEnt", "OFF");
  50. }
  51. private static void MdiActiveDocument_CommandFailed(object sender, CommandEventArgs e)
  52. {
  53.     // Очищаем список
  54.     ObjCol?.Clear();
  55. }
  56. // Обработка события добавления объекта в базу чертежа
  57. private static void CallBack_ObjectAppended(object sender, ObjectEventArgs e)
  58. {
  59.     // Код для примера не важный
  60. }
  61. // Обработка события завершения команды автокада
  62. private static void CallBack_CommandEnded(object sender, CommandEventArgs e)
  63. {
  64.     if (MpCadHelpers.GetStringXData("MP_LayerToEnt").Equals("ON"))
  65.     {
  66.        // Далее код для примера не важный
  67.     }
  68. }