Revit API для начинающих: первый инструмент на C# без опыта программирования
Revit API — это программный интерфейс Autodesk Revit, через который внешний код читает и изменяет модель. Первый инструмент — это надстройка на C# с одной командой. Разберём её по частям: точка входа, манифест, транзакция, поток Revit — и покажем, как собрать и запустить такой плагин без опыта программирования.
Что такое Revit API
Revit API — программный интерфейс Autodesk Revit: набор библиотек .NET, через которые внешний код обращается к модели. Всё, что вы делаете руками в интерфейсе — выделяете элементы категории, меняете параметр, создаёте вид, готовите лист, — можно выразить в коде. Надстройка не заменяет Revit и не работает в стороне: она загружается внутрь запущенного Revit и исполняется в том же процессе, что и сама программа.
Для инженера практический смысл простой: операции, которые повторяются из проекта в проект, перестают быть ручной работой. Проверка параметров, выборка элементов, подготовка отчёта, массовая правка однотипных семейств — всё это надстройка выполняет по нажатию кнопки или по запросу внешнего клиента, а вы проверяете результат.
Отдельный язык учить не нужно: код надстройки пишут на C# (реже на VB.NET), а Revit загружает результат компиляции — DLL-сборку. Это значит, что инструменты для Revit используют те же библиотеки, отладчик и сборщик, что и любое другое приложение на .NET.
- Читать и фильтровать элементы модели по категории, типу и значению параметра.
- Изменять параметры и свойства элементов в рамках транзакции.
- Создавать и размещать элементы, работать с системами и семействами.
- Получать данные для отчётов и выгружать их во внешние форматы.
- Добавлять свои кнопки, панели и окна в интерфейс Revit.
Документ, элементы и параметры
Чтобы код перестал быть для вас набором символов, полезно разложить модель на три уровня, с которыми работает Revit API. Верхний уровень — документ Document: это открытый файл проекта, который содержит всё остальное. Именно из документа берутся элементы и в него записываются изменения.
Средний уровень — элементы Element. Элементом является всё, что существует в модели: стена, колонна, помещение, вид, лист, уровень. У каждого элемента есть категория Category — стены, двери, окна, оборудование, — и именно по категории удобнее всего отбирать элементы.
Нижний уровень — параметры Parameter. Через них элемент несёт свои данные: длину, материал, марку, комментарий, пользовательские атрибуты. Почти любая инженерная проверка сводится к чтению параметров у отобранных элементов и сравнению значений с правилом.
Дополнительно стоит различать экземпляр и тип. Экземпляр — конкретный элемент в модели, тип — общее описание, которое он использует. Часть параметров принадлежит экземпляру, часть — типу; когда код меняет «не тот» параметр, изменение либо не сохраняется, либо затрагивает сразу все элементы типа. Это одна из самых частых причин неожиданного поведения у новичков.
Точка входа: интерфейс IExternalCommand
Внешняя команда Revit реализует интерфейс IExternalCommand. Revit находит ваш класс по манифесту, создаёт экземпляр и вызывает единственный метод Execute. Ниже — полная сигнатура этого интерфейса, ровно так, как её ожидает Revit.
public Result Execute(
ExternalCommandData commandData,
ref string message,
ElementSet elements)Первый параметр, commandData, даёт доступ к приложению Revit, к его интерфейсу и к активному документу. Через него команда получает направления. commandData.Application.ActiveUIDocument — это точка входа к текущему файлу, который пользователь открыл в данный момент.
Второй параметр — строка message, передаваемая по ссылке. Если команда не смогла выполниться, в неё можно записать текст, и Revit покажет его пользователю. Третий параметр, ElementSet elements, — набор элементов, которые Revit подсветит при сообщении об ошибке. Это удобно, когда команда отбраковывает конкретные элементы: пользователь сразу видит, о чём речь.
Возвращаемое значение типа Result сообщает Revit итог работы:
Succeeded— команда отработала, ошибок нет.Failed— команда не выполнена; Revit покажет текст изmessage.Cancelled— тихий отказ без сообщения, когда отмена штатна.
Класс, в котором живёт этот метод, должен быть публичным и иметь конструктор без параметров: Revit создаёт объект сам и не знает, какие аргументы вы хотели бы передать. Поэтому все данные команда получает из окружения, а не из конструктора.
Первый код: команда читает документ
Начнём с самой безопасной операции — чтения. Команда ниже не меняет модель, а только собирает элементы нужной категории и выводит их количество. Такой каркас покажет, что надстройка загружается и видит документ, ещё до того, как вы возьмётесь за изменения.
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
namespace FirstTool
{
[Transaction(TransactionMode.Manual)]
public class CountWallsCommand : IExternalCommand
{
public Result Execute(
ExternalCommandData commandData,
ref string message,
ElementSet elements)
{
UIDocument uidoc = commandData.Application.ActiveUIDocument;
Document doc = uidoc.Document;
FilteredElementCollector collector =
new FilteredElementCollector(doc)
.OfCategory(BuiltInCategory.OST_Walls)
.WhereElementIsNotElementType();
int count = collector.GetElementCount();
TaskDialog.Show("Первый инструмент", $"Стен в модели: {count}");
return Result.Succeeded;
}
}
}Разберём по строкам, потому что здесь помещается почти вся механика надстройки. Директива using подключает пространства имён Revit API: атрибуты, работу с документом и пользовательский интерфейс. Атрибут [Transaction(TransactionMode.Manual)] объявляет, что команда сама управляет транзакциями, — этим мы займёмся дальше.
Класс CountWallsCommand реализует интерфейс команды. Внутри метода мы получаем активный документ через UIDocument, а затем создаём FilteredElementCollector. Это основной инструмент чтения: коллектор проходит по модели и возвращает элементы, подходящие под фильтр. Мы ограничиваем выборку категорией стен и отбрасываем типы стен, оставляя только экземпляры.
Метод GetElementCount возвращает число найденных элементов, а TaskDialog.Show выводит его в окне поверх Revit. В конце команда возвращает Result.Succeeded. Никакой транзакции здесь нет — и не нужно: чтение модель не меняет.
Пять понятий, которых достаточно для первого понимания: пространства имён Autodesk.Revit.*, атрибут транзакции, класс команды, метод Execute и коллектор элементов. Большинство инструментов для Revit — это комбинации этих пяти частей.
Манифест .addin: как Revit узнаёт о команде
Revit не сканирует произвольные папки в поисках кода. Он читает файлы с расширением .addin из каталога %PROGRAMDATA%\Autodesk\Revit\Addins\<версия>, где в конце пути стоит номер версии Revit. Именно этот файл связывает класс в вашей сборке с кнопкой в интерфейсе.
<?xml version="1.0" encoding="utf-8"?>
<RevitAddIns>
<AddIn Type="Command">
<Name>Первый инструмент</Name>
<Assembly>FirstTool.dll</Assembly>
<FullClassName>FirstTool.CountWallsCommand</FullClassName>
<ClientId>00000000-0000-0000-0000-000000000000</ClientId>
<VendorId>MY</VendorId>
<VendorDescription>Первый инструмент для Revit</VendorDescription>
</AddIn>
</RevitAddIns>В манифесте указаны сборка, полное имя класса вместе с пространством имён и текст кнопки. Revit читает его при запуске и подгружает команду. Если сборка лежит рядом с манифестом, путь можно не указывать; если нет — путь задаётся явно.
Версия в пути — это основная версия Revit. Манифест для 2022 года лежит в папке ...\Addins\2022, для 2025 — в соответствующей. Сборка и манифест должны соответствовать версии Revit: плагин, собранный под одну версию, не загрузится в другую без пересборки, потому что у версий различается целевая среда исполнения.
Транзакции: изменение модели
Чтение модели можно делать без транзакции, изменение — нельзя. Любая операция, меняющая документ, должна быть обёрнута в транзакцию, иначе Revit отклонит вызов исключением. Транзакция — это не формальность, а гарантия целостности: либо все изменения внутри блока применяются, либо откатываются целиком.
using (Transaction t = new Transaction(doc, "Правка параметра"))
{
t.Start();
parameter.Set("Новое значение");
t.Commit();
}Здесь всё явно: транзакция открывается методом Start, изменения вносятся между началом и завершением, а Commit фиксирует результат. Если внутри блока возникнет исключение, транзакция не фиксируется, и модель останется прежней. Так неудачная команда не оставляет документ в половинчатом состоянии.
Практический приём, который экономит время: сначала прочитайте модель коллектором и соберите список того, что нужно изменить, и только потом одной транзакцией примените изменения. Долгие вычисления внутри транзакции блокируют Revit, поэтому всё, что можно сделать до неё, делайте до неё.
Однопоточность и поток Revit
Revit API однопоточный. Модель можно трогать только из того потока, в котором работает интерфейс Revit. Попытка обратиться к документу из фонового потока приводит к исключению или к непредсказуемому поведению. Это первое правило, которое отличает надстройку для Revit от обычного приложения .NET.
Отсюда следует практический вывод: если команда приходит не из кнопки в Revit, а извне — из HTTP-сервера, таймера или AI-клиента, — её нельзя выполнить прямо в момент поступления. Запрос нужно передать на поток Revit. Стандартный способ это сделать — внешнее событие ExternalEvent или событие простоя Idling: вы ставите задачу в очередь и регистрируете обработчик, а Revit вызывает его в безопасный момент.
ExternalEvent externalEvent =
ExternalEvent.Create(new MyEventHandler());
externalEvent.Raise();Обработчик события исполняется уже на потоке Revit, поэтому именно там и находится безопасное место для работы с моделью. В проекте RevitAiTools по этому принципу работает вся связка с внешним клиентом: плагин принимает запрос, ставит его в очередь на поток Revit и возвращает результат. Подробнее про эту связку — в материале MCP для Revit.
Версии Revit и целевая среда
Надстройки для Revit 2022–2024 собираются под .NET Framework 4.8, а для Revit 2025 и новее — под .NET 8. Это не рекомендация, а требование платформы: Revit загружает вашу сборку в свой процесс, и её среда исполнения должна совпадать. Сборка под .NET Framework 4.8 не загрузится в Revit 2025, и наоборот.
Если один инструмент должен работать на нескольких версиях, есть два пути: вести отдельные конфигурации сборки под каждую целевую среду или изолировать различия Revit API в тонком слое совместимости и держать общий код независимым от версии. В проекте RevitAiTools используется второй путь: версии 2022–2027 обслуживаются из одного исходного кода через слой совместимости. Разбор диапазона версий — на странице поддерживаемые версии Revit.
Практический вывод для новичка: определите целевую версию Revit до того, как писать код. От неё зависит и целевая среда исполнения, и часть сигнатур API, которые менялись между версиями.
Как собрать и запустить надстройку
Порядок действий короткий, но требует внимательности: один пропущенный шаг — и команда не появится.
- Скомпилировать сборку под целевую версию Revit и её среду исполнения.
- Положить DLL и файл
.addinв каталог надстроек нужной версии. - Убедиться, что в манифесте верно указаны имя сборки и полное имя класса.
- Запустить Revit и вызывать команду с панели надстроек.
- Для отладки прикрепить отладчик к процессу Revit и поставить точку останова в методе Execute.
Отладка мало отличается от обычного .NET: вы прикрепляете отладчик к запущенному Revit и останавливаетесь в своём коде. Основная сложность — модель живёт в том же процессе, что и отладчик, поэтому ошибки нужно читать внимательно: обычное исключение внутри транзакции откатывает изменения, и симптом может выглядеть неочевидно. Сообщение из message и стек вызовов обычно дают ответ быстрее, чем повторный запуск вслепую.
Начните с самой простой команды: подсчитать элементы и показать окно с числом. Если она загрузилась и открыла окно, значит, вся цепочка собрана правильно — сборка найдена, манифест прочитан, класс загружен, метод вызван. Дальше можно усложнять код, не подозревая каждую ошибку на инфраструктуру. Это экономит часы: отлаживать логику модели гораздо проще, когда уверен, что надстройка вообще запускается.
Полезно держать в голове, что Revit загружает надстройки при старте, поэтому после пересборки библиотеки Revit нужно перезапустить. Для итеративной разработки это главный источник раздражения, но обходится он просто: короткие циклы сборки и понятная тестовая модель, на которой проверяется каждая версия команды.
Можно ли начать без опыта программирования
Да, при определённой дисциплине. C# читается как структурированный текст, а первый инструмент — это десятки строк, а не тысячи. Важно не столько писать код с нуля, сколько понимать, что именно делает каждая часть и как проверить результат на модели.
Здесь меняется роль AI-агента. Он пишет черновик по вашему описанию, объясняет строки, предлагает проверки и помогает собрать проект. От человека остаётся то, что агент сделать не может: поставить задачу, разложить её на шаги, понять модель данных Revit и принять результат. Правило простое: агент предлагает — вы проверяете на реальном файле.
- Понимать, что такое категория, тип и экземпляр, — без этого задача ставится приблизительно.
- Читать сообщения об ошибках и сопоставлять их со строкой кода.
- Проверять результат руками: запустить команду и посмотреть на модель.
- Идти от маленькой команды к составной, а не начинать с большого инструмента.
Именно так построено обучение в проекте: от первого метода Execute к составным инструментам, с использованием MCP, чтобы AI-клиент вызывал ваши команды. Состав доступа и материалы описаны на странице RevitAiTools.
Частые ошибки новичка
Большинство первых сбоев объясняется небольшим набором причин. Ниже — те, что встречаются чаще всего.
- Изменение модели без транзакции — Revit выбрасывает исключение.
- Обращение к документу из фонового потока вместо потока Revit.
- Работа с ссылками на удалённые элементы: элемент перестал существовать, а код продолжает к нему обращаться.
- Несовпадение целевой среды сборки и версии Revit, под которую она ставится.
- Отсутствие или неверный манифест
.addin, из-за чего команда не появляется в интерфейсе. - Долгие вычисления внутри транзакции, из-за чего Revit «замирает».
- Подавленные исключения внутри транзакции: ошибка не видна, а изменения молча откатываются.
Эти же пункты — удобный чек-лист перед первым запуском. Если команда не появилась в интерфейсе, сначала проверьте манифест и путь к сборке; если появилась, но завершилась ошибкой, — транзакцию и поток. Такой порядок экономит больше времени, чем перебор кода целиком.
Что дальше
У вас есть весь минимум: точка входа, чтение через коллектор, транзакция, понимание однопоточности и манифест. Следующий шаг — не усложнять, а расширять по одной части за раз: сделать фильтр точнее, добавить изменение параметра, оформить отчёт. Каждый такой шаг проверяется на реальной модели, а не на предположении.
Когда захочется, чтобы команды вызывал AI-клиент, а не пользователь из интерфейса, переходите к связке плагина и MCP-сервера. Про то, как это устроено и где проходит граница проверки перед изменением модели, читайте в материале MCP для Revit и на странице RevitAiTools.
Перейти к практике
Первоначальный платёж открывает приватный GitHub-репозиторий RevitAiTools, обучающий курс и сообщество. Условия, состав доступа и актуальная цена — на главной странице.
Посмотреть условия доступа