Как отловить событие включения ленты?

Автор Тема: Как отловить событие включения ленты?  (Прочитано 5836 раз)

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

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Здравствуйте!
При инициализации моего приложения выполняется проверка кнопок ленты и, при необходимости, им изменяются состояния (вкл-откл). Для этого, при загрузке приложения выполняется код:
Код - 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, исключения не возникает.
Ну да ладно, не беда, добавил проверку - исключение теперь не появляется. Но этот код вызывается только один раз при загрузке приложения. Т.е., если потом включить ленту, то обработка ее кнопок уже не произойдет. Как бы так покорректнее отловить событие включения ленты, чтобы вызывать этот метод?
Пока что на ум приходит только отлов команды включения ленты. Но, т.к. командным реакторам я не сильно доверяю, хочу оставить это на крайний случай, если не найдется более надежного. Может кто уже сталкивался с этим?

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Код - 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.         }

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Цитировать
Отвечаю в надежде получить плюсики в карму =))
Плюсик я, так уж и быть, поставлю :)
Но это не то. Объясню почему. Как я понимаю, это событие возникает при инициализации какого-то отдельного элемента ленты. Что происходит: инициализируется первый элемент ленты, отрабатывает код. Но лента вся целиком еще не инициализирована. Соответственно, моих кнопок на ней еще нет и код отрабатывает вхолостую. Надо какое-то такое событие, которое гарантирует, что лента уже вся прогружена.

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Пробовал в событии ComponentManager_ItemInitialized дополнительно подписаться на RibbonControl.Initialized, RibbonControl.Loaded, RibbonControl.LayoutUpdated. Первые два не срабатывают. Видимо, они происходят ранее. Третье срабатывает тоже слишком рано, когда на ленте еще не прогрузилась нужная мне вкладка. Столкнулся еще со странной особенностью: в событие RibbonControl.LayoutUpdated в качестве объекта sender передается NULL почему-то. Первый раз с таким сталкиваюсь.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Столкнулся еще со странной особенностью: в событие RibbonControl.LayoutUpdated в качестве объекта sender передается NULL почему-то. Первый раз с таким сталкиваюсь.
Возможно просто баг. Я бы на твоём месте особо не заморачивался, а в командном событии (а еще лучше в DocumentCollection.DocumentLockModeChanged) выполнял бы инициализацию своей ленты (имя команды анализировать совершенно необязательно).
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Я бы на твоём месте особо не заморачивался
Решил так и сделать. Пока оставил код в таком виде, как в #1 шапке темы. Время появится - буду разбираться.
« Последнее редактирование: 12-07-2017, 11:17:54 от Дмитрий Загорулькин »

Оффлайн miss

  • ADN OPEN
  • Сообщений: 8
  • Карма: 3
Время появится - буду разбираться.
Разобрались? :)

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Autodesk.Windows.ComponentManager.Ribbon.BackgroundRenderFinished

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Autodesk.Windows.ComponentManager.Ribbon.BackgroundRenderFinished
Вообще-то это не совсем то, о чем шла речь в этой теме. Пока не инициализирован Ribbon - он равен null. И подписаться на его событие ты не сможешь.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Autodesk.Windows.ComponentManager.Ribbon.BackgroundRenderFinished
Вообще-то это не совсем то, о чем шла речь в этой теме. Пока не инициализирован Ribbon - он равен null. И подписаться на его событие ты не сможешь.

Так как раз надо совместить мой первый ответ и этот, и будет то, что Дмитрий хочет )

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Освежил память.
В общем, сейчас у меня так это всё работает:
1. При загрузке приложения идёт подписка на Application.Idle.
2. Когда оно наступает - пробую получить ленту, и если она не null, то проверяю-задаю состояния для моих кнопок. После этого отписываюсь от этого события.
3. При загрузке приложения идёт подписка на Application.SystemVariableChanged. При изменении переменных, проверяю их имена. Если это "WSCURRENT" или "RIBBONSTATE" - значит, есть шанс, что были изменения в ленте. Но в момент изменения значения переменной ещё рано трогать ленту. Поэтому, снова подписываюсь на Application.Idle и далее - см.п 2.

Отмечено как Решение Александр Ривилис 21-10-2020, 20:00:46

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Вот как это выглядит:
Код - 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() - метод, который обновляет состояния кнопок на ленте.