Как получить данные кнопки, которая запускает команду
Пользователь Legantmar на форуме задал интересный вопрос, можно ли получить название кнопки, по нажатию которой была вызвана команда.
Общий смысл был таков. В процессе запуска приложения динамически создаются несколько кнопок (по описанию из текстового файла), назначенные на одну и ту же команду. В коде самой команды нужно было понять, какая же конкретно кнопка была нажата и, в зависимости от этого, проделать определенные действия.
Поискав в документации по Revit API, ничего подобного не нашлось. Но, вспомнив о том, что помимо официальных сборок Revit API, есть еще недокументированные сборки, которые содержат много интересных фишек, и которые используется самим Revit. В частности есть сборка AdWindows.dll, в которой и прописана вся логика работы с интерфейсом, в частности с лентой.
Собственно, идея состояла в том, чтобы найти свойства, методы, и события, которые помогут как-то определить, какая кнопка на ленте была нажата. И такое событие было найдено.
В этой сборке есть статический класс – ComponentManager. Раз статический, можно использовать его где угодно и когда угодно. Вернее, доступ к нему есть отовсюду, но можно ли им воспользоваться или нет, зависит от контекста.
Первое событие, что мне попалось на глаза – ComponentManager.ItemExecuted. В аргументах обработки события мы видим класс RibbonItemExecutedEventArgs, где есть свойство Item. Логично предположить, что после того, как будет нажата кнопка на ленте, будет вызвано это событие. В обработчике события мы получим доступ к тому, что же именно было нажато. Попробуем реализовать такой алгоритм:
1) Подпишемся на это событие при старте приложения
2) В обработке события запишем в статическую переменную тот элемент управления на ленте, которые был использован для выполнения
3) В команде обратимся к этому статическому свойству и извлечем оттуда название.
- class App : IExternalApplication
- {
- private static RibbonItem _executedItem;
- public static RibbonItem ExecutedItem
- {
- get { return _executedItem; }
- }
- public Result OnStartup(UIControlledApplication a)
- {
- // Подписываемся на событие при старте приложения
- ComponentManager.ItemExecuted += ComponentManager_ItemExecuted
- return Result.Succeeded;
- }
- }
И команда:
- var item = App.ExecutedItem;
- if (item == null)
- {
- return Result.Failed;
- }
- TaskDialog.Show(“ADN-CIS”, item.Id);
Выводим Id кнопки в сообщении.
Запускаем. И… почти все работает, если бы ни одно но... Событие ItemExecuted вызывается уже после окончания выполнения кода команды. Таким образом мы получаем кнопку, которая была нажата ранее.
Дальнейший поиск привел к еще одному событию - ComponentManager.UIElementActivated. Согласно названию, данное событие должно возникать, в тот момент, когда элемент управления станет активным. Нажатие мышкой на него приводит к активации. Смущает только то, что событие будет вызываться не только по нажатию кнопки, а вообще по любому действию на ленте – переключение по вкладкам, панелям и т.п. В целом не критично, но все же.
Данные подход сработал. Событие вызывается еще до момента запуска команды. А значит успеваем записать в статическую переменную, что же за кнопка была нажата.
В итоге получился такой код:
- class App : IExternalApplication
- {
- private static RibbonItem _executedItem;
- public static RibbonItem ExecutedItem
- {
- get { return _executedItem; }
- }
- public Result OnStartup(UIControlledApplication a)
- {
- // Подписываемся на событие активации элеента на ленте
- ComponentManager.UIElementActivated += ComponentManager_UIElementActivated;
- var panel = a.CreateRibbonPanel("ADN-CIS");
- var assemblyName = Assembly.GetExecutingAssembly().Location;
- // Создаем 10 кнопок с разным идентификатором и текстом
- for (int i = 0; i < 10; i++)
- {
- var buttonName = string.Format("ADN-CIS_Button{0}", i);
- // каждая кнопка запускает одну и ту же команду
- PushButtonData pushButtonData =
- new PushButtonData(buttonName, string.Format("Кнопка {0}", i), assemblyName, "ADNCIS.Command");
- panel.AddItem(pushButtonData);
- }
- return Result.Succeeded;
- }
- void ComponentManager_UIElementActivated(object sender, UIElementActivatedEventArgs e)
- {
- _executedItem = e.Item;
- }
- public Result OnShutdown(UIControlledApplication a)
- {
- return Result.Succeeded;
- }
- }
И такая команда:
- [Transaction(TransactionMode.Manual)]
- public class Command : IExternalCommand
- {
- public Result Execute(
- ExternalCommandData commandData,
- ref string message,
- ElementSet elements)
- {
- var item = App.ExecutedItem;
- if (item == null)
- {
- return Result.Failed;
- }
- var taskDialog = new TaskDialog("ADN-CIS");
- // Свойство Text содержит текст, который видит пользователь.
- taskDialog.MainInstruction = item.Text;
- // В свойстве Id хранится идентификатор объекта
- // Формируется он как то так, где последняя часть - это идентификатор кнопки, который мы задали при создании
- // "CustomCtrl_%CustomCtrl_%Add-Ins%ADN-CIS%ADN-CIS_Button2"
- var buttonName = item.Id.Substring(item.Id.LastIndexOf('%')+1, item.Id.Length - (item.Id.LastIndexOf('%') + 1));
- taskDialog.MainContent = buttonName;
- taskDialog.Show();
- return Result.Succeeded;
- }
- }
В заключении – видео с демонстрацией работы.
Обсуждение: http://adn-cis.org/forum/index.php?topic=7644
Опубликовано 17.02.2017Отредактировано 17.02.2017 в 17:28:55