☰
Revit 2019.2二次开发:147例官方案例深度拆解与实战指南
2026/10/19 2:16:32 网站建设 项目流程

简介:Revit 2019.2二次开发官方案例集包含147个完整示例项目及源代码,面向具备一定Revit操作基础的BIM工程师、结构工程师或希望转入插件开发的程序员。案例覆盖元素创建与修改、参数读写、视图控制、事件响应、工作集协作、UI扩展与性能优化等主题,可帮助读者从单条命令的写法逐步过渡到完整插件的架构设计。压缩包共2000个文件,以cs源文件为主,另含addin注册文件、csproj工程文件、resx资源文件、rtf说明文档以及rvt/rfa样例模型,整体约256.85MB,目录按Samples组织,便于按编号定位案例。目前已有4470人学习下载,适合作为Revit API系统性入门的配套练习素材。通过逐例运行和修改,读者不仅可掌握外部命令、族创建、选择过滤等常见API用法,还能借鉴官方的项目组织方式与DLL引用配置,快速迁移到实际项目中。

1. 147例Revit 2019.2官方案例:这不是教程,是你要的“API用法答案库”

拿到“Revit 2019.2 二次开发官方案例+源代码,147例”,很多人的第一反应是“又有教程可以看了”,但真把这147例源码翻一遍之后才会意识到:它根本不是教程,而是一套按功能场景组织好的“API用法答案库”。每个案例就是一个完整的、可编译的Visual Studio工程,从选墙、加参数、改族、做楼层统计到UI面板注册,你在实际开发里遇到的大多数“这个API到底怎么调”的问题,都能在对应案例里找到官方写法的底稿。对刚入门Revit二次开发、卡在环境搭建和外部命令注册阶段的人,这套源码能让你跳过“从零搭工程”的拦路虎;对已经写过几个插件但总感觉写法不够正规、事务边界理不清的开发者,这147例就是最好的对照样本。它的价值不在“能看”,而在“能跑、能抄、能改”。

2. 官方案例怎么组织:147例的结构与选型逻辑

2.1 按功能模块拆解的案例目录:先搞清楚每一类解决什么问题

这套官方案例在SDK里是按功能模块分目录组织的,不同模块对应不同的API面,新手最容易犯的错是把147例当成一本从头读到尾的书,结果读了十几个几何案例还没搞明白事务怎么用。正确做法是先看目录,按自己的业务需求定位模块。

常见做法是打开Revit 2019.2安装目录下的SDK文件夹,里面Samples目录下就是官方案例工程。没有安装SDK的,可以在安装Revit时勾选SDK组件,或在官方开发者页面单独下载对应版本的SDK安装包。目录结构大体按如下模块拆分:

模块目录覆盖内容适合解决什么问题
基础API示例元素创建、文档操作、事务、类别与参数读写第一次接触二次开发,想跑通一个最小外部命令
几何相关示例线、实体、布尔运算、几何元素遍历与变换做体量、管道、复杂建模逻辑
族与族类型示例族参数、族类型、共享参数、载入族做族库管理、参数驱动、族自动创建
文档与存储示例文件导入导出、视图管理、打印做批量处理、出图、模型检查工具
结构专业示例结构构件、荷载、钢筋相关API用法做结构插件或建筑结构协同工具
UI交互示例外部应用、Ribbon面板、任务对话框、外部事件做带面板的完整插件、交互窗口

这六个模块就是这套案例的主干。实际用的时候,我一般会先把自己的需求拆成若干个“API小问题”,再回到对应模块里找案例。比如要做一个“批量修改墙类型”的功能,那你要找的是基础API示例里的元素过滤案例和族参数修改案例,而不是去几何模块里翻。

2.2 为什么跟着官方案例学而不是跟着博客学

网上关于Revit二次开发的博客和视频很多,但跟着它们学习有一个绕不开的问题:版本错位。写博客的人很可能用的是Revit 2017或2020的API,代码里调用的方法在你的2019.2环境下要么已标记弃用,要么行为完全不同。而官方案例是与Revit 2019.2版本同步发布的,所有API调用都针对当前版本,编译和运行时不会出现“这个类不存在”之类的版本问题。

另一个选型理由是官方代码的命名空间和引用路径是标准的。很多博客作者喜欢把API再封装一层,看起来省事,但你不知道他的封装在底层绕过了哪些边界检查;官方案例展示的是最贴近API原貌的写法,你在它基础上做项目改造,出问题时排查路径最短。

第三个理由涉及事务边界的处理。Revit API要求任何文档修改必须在事务内完成,博客里给的简写代码经常把事务省略或嵌套错误,但在复杂场景下会导致数据回滚或文档状态异常。官方案例里每个方案都明确标注了事务范围,哪些操作属于“读”,哪些属于“写”,写操作的事务包裹在哪一层,都有清晰的示范。对于刚涉足Revit二次开发的新手来说,照着官方案例的骨架去套自己的逻辑,比从零摸索要稳妥得多。

2.3 所有案例共用的骨架:外部命令就是那个统一的“入口”

把147例全部看一遍会发现,它们的工程结构高度一致:每个案例里都有一个继承自IExternalCommand的类,类里重写Execute方法,这个方法就是整条业务逻辑的入口。你可以把它理解为Revit给每个插件开的一扇门——用户在Revit里点击按钮,Revit把当前文档、窗口句柄和运行数据塞进来,你的代码从Execute开始干活,干完返回一个结果。

最小骨架大致是这样:

using System; using Autodesk.Revit.UI; using Autodesk.Revit.DB; using Autodesk.Revit.ApplicationServices; namespace SampleCommand { [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] public class HelloWall : IExternalCommand { public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements) { // 拿到当前打开的文档对象,所有数据操作都从它开始 Document doc = commandData.Application.ActiveUIDocument.Document; // 这里写业务逻辑:读模型、创建元素、修改参数…… // 凡是修改文档的操作,必须包在 Transaction 里 return Result.Succeeded; } } }

Execute的三个参数是理解官方案例的关键。commandData里装着当前Revit会话的上下文,最常用的是Application和ActiveUIDocument,前者给你全局应用级别的入口,后者给你当前打开的文档和视图;ref message是当命令失败时回传给Revit错误对话框的文本;elements是失败时高亮的图元集合,一般调试错误时用,正常业务里很少填。

TransactionMode.Manual声明这个命令用事务手动控制文档修改,这也是绝大多数写操作案例的标准配置。读操作案例会声明为ReadOnly,那些案例的代码里就不出现事务。理解了这套骨架,后面看任何一个案例都能快速定位逻辑主体:找到Execute,从头往下读,就是这条命令的完整执行流程。

3. 把第一条例跑起来:编译环境与最小运行流程

3.1 环境清单:三个版本要一次对齐

跑官方案例最忌讳的是“环境差一点点”。Revit 2019.2的二次开发环境需要几个版本完全对齐:Revit本体版本、.NET Framework目标框架、Visual Studio的C#编译器版本和位数。任何一处错位,后面编译报错都够折腾一阵子。

我一般建议新手按这张表把环境先配齐:

组件版本建议说明
Revit2019.2案例API与2019.2绑定,版本不匹配会出现调用异常
SDK与Revit 2019.2配套的SDK存放官方案例工程和API文档
.NET Framework4.7.2Revit 2019.2的API DLL目标框架是4.7.2
Visual Studio2017或2019,支持C#即可2019版社区版足够用
平台目标x64Revit是64位进程,插件DLL必须是x64,AnyCPU会加载失败

这里重点说两个经常翻车的点。第一,SDK不会自动和Revit一起装,默认安装只装主程序,需要在安装界面勾选SDK组件,或者事后单独跑SDK安装包。第二,Visual Studio新建项目时,“框架”下拉框要选.NET Framework 4.7.2,选成.NET Core或.NET 5+都会出现引用加载失败。2019.2的API本质是.NET Framework时代的产物,跨到.NET Core环境会遇到一堆兼容问题,不值得去折腾。

3.2 从SDK到可运行DLL的完整操作路径

找到SDK里的Samples目录后,你会看到里面按模块分了多个子文件夹,每个子文件夹下有若干个带.sln后缀的Visual Studio解决方案文件。接下来的步骤是把其中一个案例编译成Revit能加载的DLL。

用命令行编译是排查问题最少的方式。打开“开发者命令提示符”或普通命令行,进入案例目录后执行msbuild:

# 切换到案例解决方案所在目录 cd "C:\你的SDK路径\Samples\基础示例\HelloWall" # 用 Release 配置编译,平台选 x64,输出到指定目录 msbuild HelloWall.csproj /p:Configuration=Release /p:Platform=x64 /p:OutputPath=C:\RevitAddins

编译成功的标志是C:\RevitAddins目录下出现一个HelloWall.dll文件。然后用记事本或Visual Studio打开项目里的.csproj文件,能看到程序集名、目标框架和引用列表;里面必然引用了RevitAPI.dll和RevitAPIUI.dll,这两个就是开发时面对的主要API程序集。

补充一个常见操作细节:如果你不想用命令行,直接在Visual Studio里打开解决方案、选择Release加x64配置、右键生成,效果相同。但要注意生成成功后DLL的位置——它默认输出到bin\x64\Release目录,Revit加载addin时引用的是这个路径,不要找错目录。

3.3 写对addin文件,外部工具才能识别

DLL编译出来只完成了一半,Revit不会自动发现它。需要在Revit的插件注册目录里放一个.addin清单文件,把DLL路径和入口类名告诉Revit。2019.2的addin文件是XML格式,内容大致如下:

<?xml version="1.0" encoding="utf-8"?> <RevitAddIns> <AddIn Type="Command"> <Name>Hello Wall Sample</Name> <Assembly>C:\RevitAddins\HelloWall.dll</Assembly> <FullClassName>SampleCommand.HelloWall</FullClassName> <AddInId>a1b2c3d4-0000-4000-8000-123456789abc</AddInId> <VendorId>MyCompany</VendorId> </AddIn> </RevitAddIns>

把这段XML另存为HelloWall.addin,放到这个路径下:C:\ProgramData\Autodesk\Revit\Addins\2019.2\。重新打开Revit后,在“附加模块”选项卡的“外部工具”下拉菜单里就能看到这个命令。点击它,执行的就是我们刚才写的Execute方法。

Assembly节点必须写DLL的绝对路径,相对路径在Revit 2019.2里不可靠。FullClassName是“命名空间.类名”的完整形式,漏写或写错会直接导致按钮不显示。AddInId是一个GUID,每条命令要唯一,可以随意生成但不要跟其他插件重复。VendorId是厂商标识,多个插件可以用同一个,但不要留空。

另一个经常被忽略的细节是Type属性。我们这里用的是Type="Command",对应IExternalCommand实现类;如果你写的是实现IExternalApplication的插件,比如要添加Ribbon面板,这一项要改成Type="Application"。不同入口类型对应不同的加载时机:Command是点击时运行,Application是Revit启动时加载。147例里两类案例都有,注册方式不要搞混。

4. 顺着案例源码拆解三类核心写法

4.1 事务怎么写:从只读查询到修改模型

读了十几个案例后你会发现,所有涉及写操作的案例,事务结构几乎是一个模子刻出来的:Transaction开启、执行修改、Commit提交,异常时RollBack。看案例代码时如果跳过事务部分只看业务逻辑,后面自己写插件遇到“数据没变”或“整个Revit崩溃”时会一头雾水。

标准的事务写法是这样:

using (Transaction trans = new Transaction(doc, "创建墙并设置参数")) { trans.Start(); Wall wall = Wall.Create(doc, line, levelId, false); Parameter heightParam = wall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM); heightParam.Set(3000); trans.Commit(); }

事务的生命周期就是Start到Commit之间的区域。Start之后对文档的一切改动都处于“暂存”状态,Commit时才真正写入文档;如果没有Commit直接结束命令,Revit会提示“事务未提交”,并把所有改动回滚。Transaction对象的第一个参数是当前文档,第二个参数是事务名称,事务名称会出现在Undo列表里,方便用户撤销操作,所以起名要直观,比如“创建墙并设置参数”。

TransactionMode.Manual下还有一个进阶结构:TransactionGroup。当一次操作需要拆成多个事务且要求“要么全部成功要么全部回滚”时,把多个Transaction包在一个TransactionGroup里。案例里凡是批量修改元素的场景,基本都有这个结构。你只需要记住:单个修改用Transaction,一批有原子性要求的修改用TransactionGroup包住多个Transaction。

4.2 元素过滤的套路:一句话筛出你要的那批墙

二次开发里高频操作是“遍历模型里满足某条件的元素”。官方案例里过滤元素的写法非常统一,核心类是FilteredElementCollector。它的设计思路很像数据库查询——指定范围、指定类别、追加过滤条件。

最常用的组合是“遍历当前文档里所有墙”:

// 创建收集器,指定从哪找:文档所有元素 FilteredElementCollector collector = new FilteredElementCollector(doc); // 先按类别过滤,只要墙;再排除墙类型,只留墙实例 ICollection<Element> walls = collector .OfClass(typeof(Wall)) .WhereElementIsNotElementType() .ToElements(); foreach (Wall wall in walls) { double volume = wall.get_Parameter(BuiltInParameter.HOST_VOLUME_COMPUTED).AsDouble(); }

这里三个方法各管一段:OfClass(typeof(Wall))把范围缩到Wall类及其子类,WhereElementIsNotElementType()排除掉族类型记录,只保留模型里的实例元素。为什么必须排除类型?因为Revit里的族类型本身也是元素,如果不过滤,收集器返回的对象里会混入墙的类型记录,后续按实例属性取值时会得到一堆空值。

参数过滤用ElementParameterFilter,适合“只要高度大于3米的墙”这类带业务条件的筛选。先构造一个FilterRule,再把它传给过滤器的构造函数。官方案例里凡是涉及批量条件判断的业务,基本都是这个套路:收集器负责缩小范围,规则对象负责精准匹配,两步组合起来再ToElements()取出结果。自己写的时候不要急着用foreach去遍历全模型,先把范围缩下来,性能差异在大型项目里非常明显。

4.3 UI入口的两种写法:外部命令与外部应用

147例里有一类案例专门演示UI扩展,读了它们会把Revit插件从“命令行式工具”升级成“带面板的专业插件”。这里核心区别是:外部命令只在点击时执行一次,外部应用则在Revit启动时加载并常驻。

外部应用的标准写法是实现IExternalApplication接口的两个方法:

public class App : IExternalApplication { public Result OnStartup(UIControlledApplication application) { // 创建一个名为"我的工具"的选项卡面板 RibbonPanel panel = application.CreateRibbonPanel("我的工具"); // 把外部命令绑定为一个按钮 PushButtonData buttonData = new PushButtonData( "HelloButton", "Hello 示例", @"C:\RevitAddins\HelloWall.dll", "SampleCommand.HelloWall"); panel.AddItem(buttonData); return Result.Succeeded; } public Result OnShutdown(UIControlledApplication application) { return Result.Succeeded; } }

OnStartup在Revit启动时被调用,application对象代表Revit的UI应用环境,用它创建Ribbon面板和按钮。PushButtonData构造函数的四个参数分别是按钮内部标识、按钮显示文字、程序集路径和入口类名。这里有个容易踩的坑:入口类名必须和你addin文件里的FullClassName一致,否则按钮生成了但点击无效。

案例里还经常展示ExternalEvent的用法。核心思想是:Ribbon按钮的点击事件运行在Revit的UI线程里,如果你的插件要做耗时操作或需要后台线程交互,不能直接在后台线程里改文档。ExternalEvent提供了一种“把后台线程的请求排队递交给UI线程处理”的机制,实现方式是ExternalEvent.Create()创建事件,然后用Raise()触发。凡是案例里写到“Async”或“ExternalEvent”字样的,都是这个用途。

5. 跑官方案例最容易翻车的5个坑:现象、原因、解决

5.1 编译报错:找不到Autodesk.Revit.DB类型

现象:用Visual Studio打开案例工程,所有涉及Autodesk.Revit命名空间的代码全部标红,生成时报“未能找到类型或命名空间”。

原因:.csproj里的引用路径不适用你本机环境。官方案例的工程文件写的是写代码的人机器上的SDK路径,你本机SDK装的位置不同,引用失效。

解决:手动重新添加引用。在解决方案资源管理器里右键“引用”,选择“添加引用”,点“浏览”,去Revit安装目录下找到RevitAPI.dll和RevitAPIUI.dll,选中加入。路径一般在安装目录的根目录下,不确定就用文件搜索找这两个文件名。加完之后检查每个代码文件顶部的using语句没标红,再重新生成。另外确认项目的“平台目标”是x64,不是AnyCPU或x86。

5.2 加载后面板一片空白

现象:addin文件放好了,重新打开Revit,附加模块里空空如也,连按钮的影子都看不到。

原因:三个地方最容易写错。Assembly节点的DLL路径写错或没写绝对路径;FullClassName漏掉了命名空间前缀;XML编码被保存成带BOM的格式,Revit解析失败。

解决:先用记事本打开addin文件检查路径和类名,再对照案例工程里的实际命名空间和类名复制粘贴到XML里,不要手敲。然后把文件另存为UTF-8编码。如果还不行,把Revit日志打开看加载信息,日志文件位于%LOCALAPPDATA%\Autodesk\Revit\2019.2目录下,里面有每个addin的加载结果。看到“Cannot load file”之类的关键字,基本就是DLL路径问题;看到“Cannot find class”,就是FullClassName问题。

5.3 一运行就崩溃,提示“事务”问题

现象:点击外部命令后Revit弹窗报错,提示“在事务外部修改文档”,或命令执行完但模型里没有任何变化。

原因:这是新手最容易犯的错。案例代码里Transaction包裹的是修改操作,但你自己改造代码时,在trans.Start()之前就调用了修改元素的API,比如直接用Element的set_Parameter改了值;另一种情况是trans.Start()之后没调Commit(),Revit直接把改动回滚了。

解决:把所有写操作严格放在Start和Commit之间。我一般给自己定两条规矩:写完事务后用读代码方式检查“Start到Commit之间有没有非写操作的耗时逻辑”,有就移到外面;每次Commit后立刻看返回值,Commit失败就打印错误信息,不要静默吞掉。还要注意TransactionMode.ReadOnly的命令里如果出现写操作,编译能过但运行必崩,声明和操作要一致。

5.4 案例在别的版本上运行不了

现象:把2019.2的案例源码复制到Revit 2023环境里编译,报一堆API过时错误,或者编译通过但点击按钮后行为怪异,比如某些对话框显示不出来。

原因:Revit API在版本间有弃用和变更。2019.2和后续版本之间,部分方法签名改了,部分枚举值废弃了,官方在发布新版本时会一并更新案例源码,但你拿到的还是2019.2那一版。

解决:认准“案例SDK版本等于本机Revit版本”这条原则。要么用2019.2的Revit和配套SDK跑这套案例,要么去下载对应你本机Revit版本的SDK案例。如果非要在新版本里用老代码,逐个处理编译警告,优先把标记为[Obsolete]的方法替换成新版推荐写法,从Revit API文档里查替代接口。不要抱着“能用就行”的心态,版本升级时这些隐患会集中爆发。

5.5 看源码找不到“Main函数”

现象:打开一个案例工程,几十个cs文件堆在那里,不知道从哪开始看起,项目管理器里一片密密麻麻的类。

原因:官方案例不是单一入口程序,也没有名为Main的函数。它的运行入口就是那个实现IExternalCommand接口的类,但案例工程里还包含大量辅助类、对话框类、几何计算类,新手容易被这些辅助代码带偏。

解决:用“两步定位法”快速找到入口。第一步,随便打开一个cs文件,看类声明里有没有IExternalCommand或IExternalApplication,有就是入口类。第二步,在类里找Execute方法或OnStartup/OnShutdown方法,从这里向下读。读的时候把辅助类当作黑匣子,先不深究内部实现,只看入口代码里调用了哪些辅助方法、传了什么参数,等主线逻辑通透了再回头读辅助类。这种方式读任何案例都能在一个小时左右理清它的完整工作路径。

6. 把147例变成自己的开发起点:三种进阶用法

6.1 建立“功能→案例”索引表

147例不可能全记住,也不需要全记住。我习惯把自己业务里可能用到的功能列成一张索引表,每条对应到具体案例模块和核心代码位置。比如“批量改墙高”,对应基础API模块里的元素过滤和参数修改案例;搜索的时候先在索引表里找关键词,再跳到对应案例看具体实现,比漫无目的地翻目录快得多。索引表不用做得多精美,一个表格几行字,重点是“功能关键词”和“案例位置”两列,后续每次做完一个功能就补一行,慢慢就成了自己的常用手册。

6.2 拿官方案例当脚手架改造

做自己的插件时,不要从“新建空项目”开始,那意味着引用配置、addin注册、入口类结构全部重来一遍。正确做法是找一个功能最接近的官方案例,直接复制整个文件夹,改掉工程名和命名空间,再往Execute方法里填自己的业务逻辑。这样做的好处是引用路径、平台配置、编译选项都是已经调好的,你只需要关注业务代码本身。改命名空间时注意别漏改addin文件里的FullClassName,不然前面第5章的空白面板坑会再踩一次。

6.3 调试技巧:附加到Revit进程

很多人在二次开发调试时习惯用MessageBox.Show弹窗看变量,这在简单场景够用,但遇到循环和批量处理时就力不从心了。正确姿势是直接附加到Revit进程做断点调试。在Visual Studio里按调试快捷键,选择“附加到进程”,进程列表里选中Revit.exe,确认代码里的断点是在Execute方法内部,然后回到Revit界面点击外部命令,代码就会停在断点处。这样能逐行看变量值,性能开销也比弹窗小得多。

我有一个从血泪教训里总结出来的收尾习惯:每次改完案例代码生成新DLL后,先把Revit完全关掉再重新打开测试加载,不要用“附加到进程”的方式在运行中覆盖DLL——文件占用会导致加载旧程序集,测了半天改了个寂寞。这套源码用顺了以后,大部分二次开发的起步问题都能在你自己的案例索引和调试流程里快速闭环,希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询