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

ADN Club => AutoCAD .NET API => Тема начата: Дмитрий Загорулькин от 11-07-2017, 12:18:31

Название: Как отловить событие включения ленты?
Отправлено: Дмитрий Загорулькин от 11-07-2017, 12:18:31
Здравствуйте!
При инициализации моего приложения выполняется проверка кнопок ленты и, при необходимости, им изменяются состояния (вкл-откл). Для этого, при загрузке приложения выполняется код:
Код - C# [Выбрать]
  1. internal static void AddActivateTabsHandlers()
  2. {
  3.     RibbonControl ribbon = ComponentManager.Ribbon;
  4.  
  5.     if (ribbon == null)
  6.     {
  7.         // Application.ShowAlertDialog("Лента отключена!");
  8.         return;
  9.     }
  10.  
  11.     IEnumerable<RibbonTab> tabs = ribbon.Tabs.Where(item =>
  12.         !m_initsTabs.Contains(item)
  13.         && item.IsVisible
  14.         && !item.IsContextualTab
  15.         && !item.IsActive);
  16.  
  17.     foreach (RibbonTab tab in tabs)
  18.     {                
  19.         tab.Activated += tab_Activated;
  20.         m_initsTabs.Add(tab);
  21.     }
  22. }
  23.  
Проверку включенности ленты (строки 5-9) пришлось добавить только что, т.к. если лента отключена, то в строке 3 переменной ribbon присваивается значение NULL и вылетает исключение:
System.NullReferenceException: Ссылка на объект не указывает на экземпляр объекта.
   в My.Civil.Networks.RibbonSettings.AddActivateTabsHandlers()
   в My.Civil.Networks.AssemblyLoad.InitializeCommand()
   и т.д.
Причем, что самое обидное, исключение вылетает только при автозагрузке приложения, то есть, только в релизной версии. Когда я выполняю отладку, загружая приложение через NETLOAD, исключения не возникает.
Ну да ладно, не беда, добавил проверку - исключение теперь не появляется. Но этот код вызывается только один раз при загрузке приложения. Т.е., если потом включить ленту, то обработка ее кнопок уже не произойдет. Как бы так покорректнее отловить событие включения ленты, чтобы вызывать этот метод?
Пока что на ум приходит только отлов команды включения ленты. Но, т.к. командным реакторам я не сильно доверяю, хочу оставить это на крайний случай, если не найдется более надежного. Может кто уже сталкивался с этим?
Название: Re: Как отловить событие включения ленты?
Отправлено: Александр Пекшев aka Modis от 11-07-2017, 12:24:04
Код - C# [Выбрать]
  1. public void Initialize()
  2.         {
  3.             /* ленту грузим с помощью обработчика событий:
  4.              * Этот вариант нужно использовать, если ваш плагин
  5.              * стоит в автозагрузке, т.к. он (плагин) инициализируется
  6.              * до построения ленты
  7.              */
  8.             Autodesk.Windows.ComponentManager.ItemInitialized += new EventHandler(ComponentManager_ItemInitialized);
  9.         }
  10. void ComponentManager_ItemInitialized(object sender, Autodesk.Windows.RibbonItemEventArgs e)
  11.         {
  12.             // Проверяем, что лента загружена
  13.             if (Autodesk.Windows.ComponentManager.Ribbon != null)
  14.             {
  15.                 // Строим нашу вкладку
  16.                 BuildRibbonTab();
  17.                 //и раз уж лента запустилась, то отключаем обработчик событий
  18.                 Autodesk.Windows.ComponentManager.ItemInitialized -=
  19.                     new EventHandlerRibbonItemEventArgs>(ComponentManager_ItemInitialized);
  20.             }
  21.         }
Название: Re: Как отловить событие включения ленты?
Отправлено: Дмитрий Загорулькин от 11-07-2017, 12:50:55
Цитировать
Отвечаю в надежде получить плюсики в карму =))
Плюсик я, так уж и быть, поставлю :)
Но это не то. Объясню почему. Как я понимаю, это событие возникает при инициализации какого-то отдельного элемента ленты. Что происходит: инициализируется первый элемент ленты, отрабатывает код. Но лента вся целиком еще не инициализирована. Соответственно, моих кнопок на ней еще нет и код отрабатывает вхолостую. Надо какое-то такое событие, которое гарантирует, что лента уже вся прогружена.
Название: Re: Как отловить событие включения ленты?
Отправлено: Дмитрий Загорулькин от 11-07-2017, 14:08:38
Пробовал в событии ComponentManager_ItemInitialized дополнительно подписаться на RibbonControl.Initialized, RibbonControl.Loaded, RibbonControl.LayoutUpdated. Первые два не срабатывают. Видимо, они происходят ранее. Третье срабатывает тоже слишком рано, когда на ленте еще не прогрузилась нужная мне вкладка. Столкнулся еще со странной особенностью: в событие RibbonControl.LayoutUpdated в качестве объекта sender передается NULL почему-то. Первый раз с таким сталкиваюсь.
Название: Re: Как отловить событие включения ленты?
Отправлено: Александр Ривилис от 11-07-2017, 16:40:04
Столкнулся еще со странной особенностью: в событие RibbonControl.LayoutUpdated в качестве объекта sender передается NULL почему-то. Первый раз с таким сталкиваюсь.
Возможно просто баг. Я бы на твоём месте особо не заморачивался, а в командном событии (а еще лучше в DocumentCollection.DocumentLockModeChanged) выполнял бы инициализацию своей ленты (имя команды анализировать совершенно необязательно).
Название: Re: Как отловить событие включения ленты?
Отправлено: Дмитрий Загорулькин от 11-07-2017, 18:06:06
Я бы на твоём месте особо не заморачивался
Решил так и сделать. Пока оставил код в таком виде, как в #1 шапке темы. Время появится - буду разбираться.
Название: Re: Как отловить событие включения ленты?
Отправлено: miss от 21-10-2020, 15:37:21
Время появится - буду разбираться.
Разобрались? :)
Название: Re: Как отловить событие включения ленты?
Отправлено: Александр Пекшев aka Modis от 21-10-2020, 15:41:21
Autodesk.Windows.ComponentManager.Ribbon.BackgroundRenderFinished
Название: Re: Как отловить событие включения ленты?
Отправлено: Александр Ривилис от 21-10-2020, 16:25:00
Autodesk.Windows.ComponentManager.Ribbon.BackgroundRenderFinished
Вообще-то это не совсем то, о чем шла речь в этой теме. Пока не инициализирован Ribbon - он равен null. И подписаться на его событие ты не сможешь.
Название: Re: Как отловить событие включения ленты?
Отправлено: Александр Пекшев aka Modis от 21-10-2020, 17:06:42
Autodesk.Windows.ComponentManager.Ribbon.BackgroundRenderFinished
Вообще-то это не совсем то, о чем шла речь в этой теме. Пока не инициализирован Ribbon - он равен null. И подписаться на его событие ты не сможешь.

Так как раз надо совместить мой первый ответ и этот, и будет то, что Дмитрий хочет )
Название: Re: Как отловить событие включения ленты?
Отправлено: Дмитрий Загорулькин от 21-10-2020, 18:40:35
Освежил память.
В общем, сейчас у меня так это всё работает:
1. При загрузке приложения идёт подписка на Application.Idle.
2. Когда оно наступает - пробую получить ленту, и если она не null, то проверяю-задаю состояния для моих кнопок. После этого отписываюсь от этого события.
3. При загрузке приложения идёт подписка на Application.SystemVariableChanged. При изменении переменных, проверяю их имена. Если это "WSCURRENT" или "RIBBONSTATE" - значит, есть шанс, что были изменения в ленте. Но в момент изменения значения переменной ещё рано трогать ленту. Поэтому, снова подписываюсь на Application.Idle и далее - см.п 2.
Название: Re: Как отловить событие включения ленты?
Отправлено: Дмитрий Загорулькин от 21-10-2020, 19:08:06
Вот как это выглядит:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.EditorInput;
  3. using Autodesk.Windows;
  4. using System;
  5. using AppCore = Autodesk.AutoCAD.ApplicationServices.Core.Application;
  6. using AppSystemVariableChangedEventArgs
  7.     = Autodesk.AutoCAD.ApplicationServices.SystemVariableChangedEventArgs;
  8.  
  9. namespace Networks
  10. {
  11.     internal static class ApplicationSettings
  12.     {
  13.         private static bool
  14.             _initialized,          
  15.             _needUpdRibbonDetected;
  16.  
  17.         /// <summary>
  18.         /// Инициализация
  19.         /// </summary>
  20.         public static void Initialize()
  21.         {
  22.             if (!_initialized)
  23.             {
  24.                 _initialized = true;
  25.              
  26.                 AppCore.Idle += Application_Idle_RibbonUpdate;
  27.                 AppCore.SystemVariableChanged += App_SysVarChanged_RibbonUpdate;                
  28.             }
  29.         }
  30.                
  31.         private static void App_SysVarChanged_RibbonUpdate
  32.             (object sender, AppSystemVariableChangedEventArgs e)
  33.         {
  34.             if (!_needUpdRibbonDetected
  35.                 && e.Name.Equals("WSCURRENT",
  36.                 StringComparison.OrdinalIgnoreCase)
  37.                 || e.Name.Equals("RIBBONSTATE",
  38.                 StringComparison.OrdinalIgnoreCase))
  39.             {
  40.                 _needUpdRibbonDetected = true;
  41.                 AppCore.Idle += Application_Idle_RibbonUpdate;
  42.             }
  43.         }
  44.  
  45.         private static void Application_Idle_RibbonUpdate(object sender, EventArgs e)
  46.         {
  47.             RibbonControl ribbon = ComponentManager.Ribbon;
  48.             if (ribbon != null)
  49.             {
  50.                 AppCore.Idle -= Application_Idle_RibbonUpdate;
  51.                 _needUpdRibbonDetected = false;
  52.                 RibbonSettings.UpdateTabs();
  53.             }
  54.         }      
  55.     }
  56. }

ApplicationSettings.Initialize() вызывается при загрузке dll.
RibbonSettings.UpdateTabs() - метод, который обновляет состояния кнопок на ленте.