При разработке плагинов для Revit неминуемо встает вопрос: как быстро и удобно создавать кнопки, вкладки и панели на ленте. Каждый раз писать одну и ту же громоздкую логику — неудобно и нечитабельно. В этой статье я покажу, как можно значительно упростить работу с интерфейсом Revit, вынеся часто повторяющийся код в переиспользуемые расширения.
Мы рассмотрим два вспомогательных класса:
- RevitPanelTools — для создания панелей на ленте;
- RevitButtonTools — для добавления кнопок, иконок и сплит-кнопок.
Эти инструменты сделают ваш код чище, удобнее для поддержки и расширения. Также я покажу, как легко подключать ресурсы с иконками и масштабировать их на лету.
🔧 Работа с панелями: RevitPanelTools
При разработке интерфейса для Revit часто возникает необходимость добавлять пользовательские панели (RibbonPanel) во вкладки на ленте. Однако каждый раз приходится писать похожую логику: получить вкладку, проверить, существует ли уже нужная панель, а если нет — создать её.
Чтобы упростить эту рутину, мы создали расширение GetOrCreateRibbonPanel, которое автоматически возвращает нужную панель, создавая её при необходимости. Это делает код в методе OnStartup намного чище и декларативнее.
📄 Метод GetOrCreateRibbonPanel
🔍 Как это работает:
- Метод расширения
Метод объявлен с ключевым словом this перед параметром UIControlledApplication application, что делает его расширением и позволяет вызывать его прямо на объекте application. - Поиск существующей панели
Вначале получаем все панели на вкладке tabName с помощью application.GetRibbonPanels(tabName). Затем находим первую панель с нужным именем (panelName) через FirstOrDefault(...). - Создание панели, если не найдена
Если нужная панель не найдена (результат FirstOrDefault равен null), вызывается application.CreateRibbonPanel(...), создающая новую панель с заданным именем. - Параметр по умолчанию
Значение вкладки (tabName) по умолчанию — "IT4BIM", но вы можете передать любое другое имя вкладки.
🔧 Работа с кнопками: RevitButtonTools
1. CreateButton<TCommand>
Описание:
Создаёт кнопку (PushButton) и добавляет её на панель RibbonPanel.
Параметры:
- TCommand — класс команды, реализующий IExternalCommand.
- ribbonPanel — панель, на которую будет добавлена кнопка.
- label — текст кнопки.
- tooltip — всплывающая подсказка.
- iconImageName — имя иконки из ресурсов.
- tooltipImageName (опционально) — картинка, отображаемая в подсказке.
- helpURL (опционально) — ссылка на справочную страницу.
- longDescription (опционально) — расширенное описание кнопки.
- availabilityClass (опционально) — класс, определяющий доступность кнопки.
- smallIconImageName (опционально) — отдельная маленькая иконка 16×16. (по умолчанию сжимает изображение из переменной iconImageName)
Изображения берутся из папки Resources, в свойствах изображения нужно указать Build Action - Resource
Как работает:
Метод формирует PushButtonData с помощью CreatePushButtonData<TCommand>, затем добавляет кнопку в RibbonPanel через AddItem.
2. CreatePushButtonData<TCommand>
Описание:
Создаёт и настраивает объект PushButtonData, который описывает кнопку.
Параметры:
(Те же, что в CreateButton.)
Как работает:
- Указывает путь к сборке и полное имя команды.
- Загружает иконки.
- Устанавливает подсказки, длинное описание и ссылку на помощь.
- Устанавливает класс доступности, если он задан.
- Масштабирует картинку для маленькой иконки, если отдельная маленькая не указана.
Особенность:
Можно использовать отдельно, чтобы потом собрать несколько кнопок в SplitButton или Stack.
3. CreateSplitButtons
Описание:
Создаёт и добавляет SplitButton — это кнопка с выпадающим списком других кнопок.
Параметры:
- ribbonPanel — панель, на которую добавляется SplitButton.
- internalName — внутреннее имя SplitButton.
- buttonText — текст кнопки.
- buttonsData — массив кнопок (PushButtonData), которые будут внутри SplitButton (от 2 до 5 кнопок).
Как работает:
- Создаёт SplitButtonData и добавляет его на панель.
- Вставляет все переданные кнопки.
- Назначает первую кнопку как кнопку по умолчанию (CurrentButton).
Важно:
Если передано меньше 2 или больше 5 кнопок — выбрасывается ArgumentException.
4. CreateStackedButtons
Описание:
Добавляет на панель 2-3 кнопки, расположенные в одну строку.
Параметры:
- ribbonPanel — панель для размещения.
- button1, button2 , button3— данные для двух кнопок.
Как работает:
Вызывает AddStackedItems панели RibbonPanel, передавая обе кнопки.
💡 Пример использования:
Преимущества подхода:
- Минимум кода: Вся логика получения или создания панели — в одной строке.
- Без дублирования: Не нужно каждый раз проверять, существует ли панель.
- Гибкость: Можно использовать любое имя вкладки.
- Мы можем получить уже существующую панель и добавить кнопку именно на нее из другого проекта/решения
🛠 Рекомендация: выносите создание панели в отдельный метод
При разработке рекомендуется выносить создание каждой панели в отдельный публичный метод.
Это особенно полезно в тех случаях, когда в будущем планируется объединить несколько плагинов из разных проектов в одном общем решении.
Например, вместо того чтобы сразу в OnStartup добавлять команды и элементы управления, лучше вызвать отдельный метод, ответственный за конкретную панель.
Данная логика позволит разрабатывать плагины связанные с разными доменами в разных решениях и разных гит репозиториях. А соединять в одно корпоративное решение в другом проекте с минимумом логики – только вызовы по созданию панелей плагинов.
Здесь вы уже видите структуру проектов, которую лучше разбить по разным решениям и гит репозиториям, но для удобства статьи организую в рамках одного решения
Вывод
В этом примере мы разработали класс RevitButtonTools, который упрощает создание различных типов кнопок для интерфейса Revit.
Он позволяет быстро добавлять одиночные кнопки, группы из двух или трёх кнопок, а также кнопки с выпадающим списком.
Особое внимание было уделено удобной настройке внешнего вида кнопок — всплывающим подсказкам, иконкам и ссылкам на справочные материалы.
Чтобы продемонстрировать работу RevitButtonTools и других утилит, мы создали отдельный проект Bim.Examples.Library.
Этот проект мы специально вынесли в отдельную библиотеку с расчётом на последующую публикацию в виде NuGet-пакета.
Это позволит упростить повторное использование кода в реальных проектах без необходимости копировать вспомогательные классы вручную.
Также хочу отметить важный момент:
при использовании метода CreatePushButtonData рекомендуется задавать картинку по умолчанию.
Это удобно для тестовых и временных команд — кнопки будут иметь аккуратный вид даже в процессе разработки и отладки.
Что дальше?
В следующих шагах мы рассмотрим, как подготовить проект для публикации, оформить NuGet-пакет и подключить его в реальном проекте Revit.
Таким образом, мы ещё больше упростим подключение общих инструментов в разных решениях и командах.