02插件集成
插件集成
开发人员通过创建和实现 External Commands 和 External Applications 来添加功能。Revit 使用 .addin 清单文件标识新命令和应用程序。外部命令显示在 Add-Ins 选项卡上的 External Tools 菜单按钮下。外部应用程序在 Revit 启动时调用,在 Revit 关闭时卸载。
本章重点介绍以下内容:
- 了解如何使用 External Commands 和 External Applications 添加功能。
- 如何访问 Revit 事件。
- 如何自定义 Revit UI。
概述
Revit 平台 API 基于 Revit 应用程序功能。Revit 平台 API 由两个类库组成,这两个类库仅在 Revit 运行时工作。
RevitAPI.dll包含用于在数据库级别访问 Revit 的应用程序、文档、图元和参数的方法。它还包含 IExternalDBApplication 和相关接口。
RevitAPIUI.dll包含与 Revit 用户界面的操作和自定义相关的所有 API 接口,包括:
- IExternalCommand 和 External Command 相关接口
- IExternalApplication 和相关接口
- Selection 选择
- RibbonPanel、RibbonItem 和子类
- TaskDialogs 任务对话框
如下图所示,Revit Architecture、Revit Structure 和 Revit MEP 分别特定于 Architecture、Structure 和 MEP。
要创建基于 RevitAPI 的插件,必须在插件 DLL 中提供特定的入口点类型。这些入口点类实现接口IExternalCommand、IExternalApplication 或 IExternalDBApplication。通过这种方式,加载项在某些事件上自动运行,或者在 IExternalCommand 和 IExternalApplication 的情况下,从“外部工具”菜单按钮手动运行。
本章介绍了 IExternalCommand、IExternalApplication、IExternalDBApplication 和其他可用于附加模块集成的 Revit 事件。
外部命令
开发人员可以通过实现 External Tools 菜单按钮中显示的 External Commands 来添加功能。
加载和运行外部命令
当 Revit 中没有其他命令或编辑模式处于活动状态时,将启用已注册的外部命令。选择命令后,将创建一个命令对象并调用其 Execute() 方法。此方法返回到 Revit 后,命令对象将被销毁。因此,在命令执行之间,数据无法保留在对象中。但是,还有其他方法可以在命令执行之间保存数据;例如,可以使用 Revit 共享参数机制将数据存储在 Revit 项目中。
您可以将外部命令添加到“外部工具”菜单按钮下的“外部工具面板”中,或者作为“插件”选项卡、“分析”选项卡或新的自定义功能区选项卡上的自定义功能区面板。有关这两种方法的示例,请参阅演练:Hello World 和演练:添加 Hello World 功能区面板。
外部工具、功能区选项卡和功能区面板在启动时进行初始化。初始化步骤如下:
- Revit 读取清单文件并识别:
- 可调用的外部应用程序。
- 可添加到 Revit 外部工具菜单按钮的外部工具。
- 外部应用程序会话将面板和内容添加到“加载项”选项卡中。
IExternalCommand
通过创建实现 IExternalCommand 接口的对象,可以创建外部命令。IExternalCommand 接口有一个抽象方法 Execute,它是外部命令的主要方法。
Execute() 方法有三个参数:
- commandData (ExternalCommandData)
- message (String)
- elements (ElementSet)
ExternalCommandData 对象包含外部命令所需的对 Application 和 View 的引用。所有 Revit 数据都是从外部命令中的此参数直接或间接检索的。
例如,以下语句说明了如何从 commandData 参数检索 Autodesk.Revit.Document:
1 | Document doc = commandData.Application.ActiveUIDocument.Document; |
下表说明了 ExternalCommandData
公共属性表 1:ExternalCommandData 公共属性
Property 成员 | Description 描述 |
---|---|
Application (Autodesk.Revit.UI.UIApplication) | 检索表示当前 UIApplication for external 命令的对象。 |
JournalData (IDictionary<String, String>) | 可用于将数据读取和写入 Revit 日志文件的数据映射。 |
View (Autodesk.Revit.DB.View) | 检索表示 View 外部命令处理的对象。 |
message (String):错误消息由外部命令使用输出参数 message 返回。string-type 参数在外部命令进程中设置。返回 Autodesk.Revit.UI.Result.Failed 或 Autodesk.Revit.UI.Result.Cancelled 并设置消息参数时,会显示一个错误对话框。
以下代码示例说明了如何使用 message 参数。
1 | class IExternalCommand_message : IExternalCommand |
实施前面的 external 命令会导致出现以下对话框:
elements(ElementSet):每当返回 Autodesk.Revit.UI.Result.Failed 或 Autodesk.Revit.UI.Result.Canceled 且参数消息不为空时,都会显示错误或警告对话框。此外,如果向 elements 参数添加了任何元素,则这些元素将在屏幕上突出显示。每当命令失败时,无论是否还返回元素,最好设置 message 参数。 以下代码高亮显示预先选择的墙:
1 | class IExternalcommand_elements : IExternalCommand |
Return 返回:Return 结果表示执行失败、成功或被用户取消。如果不成功,Revit 将撤消外部命令所做的更改。
表 2:IExternalCommand.Result
Member Name 成员名称 | Description 描述 |
---|---|
Autodesk.Revit.UI.Result.Succeeded | 外部命令已成功完成。Revit 保留由外部命令所做的所有更改。 |
Autodesk.Revit.UI.Result.Failed | 外部命令未能完成任务。Revit 将撤消由外部命令执行的操作。如果设置了 Execute 的消息参数,Revit 将显示一个对话框,其中包含文本“错误 - 无法忽略”。 |
Autodesk.Revit.UI.Result.Cancelled | Revit 将撤消由外部命令所做的更改。如果设置了 Execute 的消息参数,Revit 将显示一个对话框,其中包含文本“警告 - 可以忽略”。 |
以下示例显示问候消息,并允许用户选择返回值。使用 Execute() 方法作为 Revit 应用程序的入口。
代码区域 3-4:提示用户
1 | public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData, |
IExternalCommandAvailability
此界面允许您控制是否可以按下外部命令按钮。IsCommandAvailable 接口方法将应用程序和一组与 Revit 中选定项目的类别匹配的类别传递给您的实现。典型用途是检查所选类别,以查看它们是否满足要运行命令的条件。
在此示例中,辅助功能检查允许在没有活动选择或至少选择了一面墙时单击按钮:
代码区域 3-5:设置命令可用性
1 | public class SampleAccessibilityCheck : IExternalCommandAvailability |
外部应用程序
开发人员可以通过外部应用程序和外部命令添加功能。功能区选项卡和功能区面板使用外部应用程序进行自定义。功能区面板按钮绑定到外部命令。
IExternalApplication
若要将外部应用程序添加到 Revit,请创建一个实现 IExternalApplication 接口的对象。IExternalApplication 接口有两个抽象方法,即 OnStartup() 和 OnShutdown(),您可以在外部应用程序中重写它们。Revit 在启动时调用 OnStartup(),在关闭时调用 OnShutdown()。
这是 OnStartup() 和 OnShutdown() 抽象定义:
代码区域 3-6:OnShutdown() 和 OnStartup()
1 | public interface IExternalApplication |
UIControlledApplication 参数提供对某些 Revit 事件的访问,并允许自定义功能区面板和控件以及添加功能区选项卡。例如,UIControlledApplication 的公共事件 DialogBoxShowing 可用于捕获正在显示的对话框的事件。以下代码段注册了在显示对话框之前调用的处理函数。
代码区域 3-7:DialogBoxShowing 事件
1 | application.DialogBoxShowing += new |
下面的代码示例说明了如何使用 UIControlledApplication 类型注册事件处理程序并在事件发生时处理事件。
代码区域 3-8:使用 ControlledApplication
1 | public class Application_DialogBoxShowing : IExternalApplication |
插件注册
需要注册外部命令和外部应用程序才能显示在 Revit 中。可以通过将它们添加到 .addin 清单文件来注册它们。外部命令和应用程序在 Revit 中的列出顺序取决于 Revit 启动时的读入顺序。
清单文件
Revit API 应用程序通过 .addin 清单文件注册到 Revit。将清单文件放置在用户系统上的两个位置之一时,Revit 会自动读取这些文件:
- C:\ProgramData\Autodesk\Revit\Addins\Revit 2018\
- C:\Users\AppData\Roaming\Autodesk\Revit\Addins\Revit 2018\
在启动期间,Revit 将读取和处理这些位置中名为 .addin 的所有文件。用户特定位置和所有用户位置中的所有文件都被视为一起,并按字母顺序加载。如果所有用户清单文件与特定于用户的清单文件同名,则忽略所有用户清单文件。在每个清单文件中,外部命令和外部应用程序将按照它们的列出顺序加载。
添加一个 ExternalCommand 的基本文件如下所示:
代码区域 3-9:清单 .addin ExternalCommand
1 | <?xml version="1.0" encoding="utf-8" standalone="no"?> |
添加一个 ExternalApplication 的基本文件如下所示:
代码区域 3-10:清单 .addin ExternalApplication
1 | <?xml version="1.0" encoding="utf-8" standalone="no"?> |
添加一个 DB 级 External Application 的基本文件如下所示:
代码区域:manifest .addin ExternalDBApplication
1 | <?xml version="1.0" encoding="utf-8" standalone="no"?> |
单个清单文件中可以提供多个 AddIn 元素。
下表描述了可用的 XML 标记:
Tag 标记 | Description 描述 |
---|---|
Assembly 程序集 | 附加模块程序集文件的完整路径。所有 ExternalCommands 和 ExternalApplications 都需要。 |
FullClassName 类的全名 | 程序集文件中实现 IExternalCommand 或 IExternalApplication 的类的全名。所有 ExternalCommands 和 ExternalApplications 都需要。 |
AddInId | 一个 GUID,表示此特定应用程序的 ID。AddInIds 对于 Revit 的给定会话必须是唯一的。Autodesk 建议您为每个已注册的应用程序或命令生成唯一的 GUID。所有 ExternalCommands 和 ExternalApplications 都需要。 |
Name 名字 | 应用程序的名称。必填;仅适用于 ExternalApplications。 |
Text | 按钮的名称。自选;仅将此标记用于 ExternalCommands。默认值为 “External Tool”。 |
VendorId 供应商 ID | Revit 中的某些操作(例如,可扩展存储的标识)可能使用的唯一供应商标识符。这必须是唯一的,因此我们建议使用域名的反向版本,例如 com.autodesk 或 uk.co.autodesk。 |
VendorDescription 供应商描述 | 包含供应商的法定名称和/或其他相关信息的描述。自选。 |
Description 描述 | 命令的简短描述将用作按钮工具提示。自选;仅将此标记用于 ExternalCommands。默认值为仅包含命令文本的工具提示。 |
VisibilityMode 可见性模式 | 外部命令可见的模式。可以为此选项设置多个值。自选;仅将此标记用于 ExternalCommands。默认情况下,在所有模式下显示命令,包括当没有活动文档时。以前编写的需要针对活动文档运行的外部命令应进行修改,以确保代码在没有活动文档时处理命令的调用,或者应用 NotVisibleWhenNoActiveDocument 模式。有关更多信息,请参阅下表。 |
Discipline 学科 | 外部命令将在其中可见的学科。可以为此选项设置多个值。自选;仅将此标记用于 ExternalCommands。默认情况下,在所有领域中显示该命令。如果列出了任何特定领域,则该命令将仅在这些领域中可见。有关更多信息,请参阅下表。 |
AvailabilityClassName 可用性类名称 | 程序集文件中实现 IExternalCommandAvailability 的类的全名。此类允许根据上下文有选择地将命令按钮灰显。自选;仅将此标记用于 ExternalCommands。默认命令是只要可见就可用的命令。 |
LargeImage 大图像 | 用于 External Tools 下拉菜单中的按钮的图标。自选;仅将此标记用于 ExternalCommands。默认情况下,显示不带图标的按钮。 |
SmallImage 小图像 | 按钮提升到快速访问工具栏时使用的图标。自选;仅将此标记用于 ExternalCommands。默认情况下,显示不带图标的快速访问工具栏按钮,这可能会使用户感到困惑。 |
LongDescription 长描述 | 命令的详细说明将用作按钮扩展工具提示的一部分,当鼠标悬停在命令上较长时间时显示。自选;仅将此标记用于 ExternalCommands。如果未提供此属性和 TooltipImage,则按钮将没有扩展的工具提示。 |
TooltipImage Tooltip图像 | 作为按钮扩展工具提示的一部分显示的图像文件,当鼠标悬停在命令上较长时间时显示。自选;仅将此标记用于 ExternalCommands。如果未提供此属性和 TooltipImage,则按钮将没有扩展的工具提示。 |
LanguageType 语言类型 | 外部工具按钮的 Text、Description、LargeImage、LongDescription 和 TooltipImage 的本地化设置。Revit 将从指定的语言资源 dll 加载资源值。该值可以是 Revit 支持的 11 种语言之一。如果未指定 LanguageType,则将自动加载当前 Revit 会话使用的语言资源。有关更多详细信息,请参阅本地化部分。 |
AllowLoadIntoExistingSession | 加载权限的标志。设置为 false 可防止 Revit 在不重新启动的情况下自动加载新添加的 .addin 清单文件中的附加模块。自选。默认情况下。Revit 将自动从新添加的 .addin 清单文件加载附加模块,而无需重新启动 Revit。 |
VisibilityMode 成员
Member Name 成员名称 | Description 描述 |
---|---|
AlwaysVisible 始终可见 | 该命令在 Revit API 支持的所有可能模式下都可用。 |
NotVisibleInProject 项目中不可见 | 当项目文档处于活动状态时,该命令是不可见的。 |
NotVisibleInFamily 族项目中不可见 | 当族文档处于活动状态时,该命令不可见。 |
NotVisibleWhenNoActiveDocument 无活动视图不可见 | 当没有活动文档时,该命令是不可见的。 |
学科成员
Member Name 会员名称 | Description 描述 |
---|---|
Any 任何 | 该命令在 Revit API 支持的所有可能领域中均可用。 |
Architecture 建筑 | 该命令在 Autodesk Revit Architecture 中可见。 |
Structure 结构 | 该命令在 Autodesk Revit Structure 中可见。 |
StructuralAnalysis 结构分析 | 当 Structural Analysis 领域编辑工具可用时,该命令可见。 |
MassingAndSite 体量与现场 | 当 体量 和 场地 领域 编辑工具可用时,该命令可见。 |
EnergyAnalysis 能量分析 | 当 Energy Analysis 领域编辑工具可用时,该命令可见。 |
Mechanical 机械 | 当 Mechanical 领域编辑工具可用时(例如,在 Autodesk Revit MEP 中),该命令可见。 |
Electrical 电气 | 当 Electrical 领域编辑工具可用时(例如,在 Autodesk Revit MEP 中),该命令可见。 |
Piping 管道 | 当管道领域编辑工具可用时(例如,在 Autodesk Revit MEP 中),该命令可见。 |
MechanicalAnalysis 机械分析 | 当 Mechanical Analysis 领域编辑工具可用时,该命令可见。 |
PipingAnalysis 管道分析 | 当“管道分析”领域编辑工具可用时,该命令可见。 |
ElectricalAnalysis 电气分析 | 当 Electrical Analysis 领域编辑工具可用时,该命令可见。 |
用于清单文件的 .NET Add-in Utility
代码区域 3-11:创建和编辑清单文件
1 | //create a new addin manifest |
代码区域 3-12:读取现有清单文件
1 | RevitProduct revitProduct1 = RevitProductUtility.GetAllInstalledRevitProducts()[0]; |
对 Revit 插件进行数字签名
Revit 会检查插件的安全凭据。如果插件未使用受信任的证书颁发机构颁发的证书进行数字签名,则 Revit 会在打开时弹出一个对话框,询问用户确认他/她是否要加载应用程序。下图显示了检测到未签名的加载项时的安全警告对话框示例。用户可以选择:1) 允许从现在开始始终加载同一插件,2) 仅加载这次并下次再次询问,以及 3) 不允许加载插件。
如果您是专业开发人员,并且您的应用程序已由受信任的证书颁发机构进行数字签名,则您的附加模块已与 Revit 中的数字签名检入兼容。以下部分适用于编写附加模块但不熟悉 Revit 中的数字签名的开发人员。
对应用程序进行数字签名
如果您是 Revit 附加模块的发布者,则必须使用自己的证书对附加模块进行签名。
要使用自己的证书对加载项进行签名,您首先需要从数字证书供应商处购买数字签名。获取证书 (cer) 或个人信息交换 (pfx) 文件后,您可以使用 signtool 对 DLL 进行签名。或者,您也可以使用在线 Authenticode 签名服务,例如 Symantec 的 Secure App Service - https://www.symantec.com/code-signing/secure-app-service/。
数字证书供应商
以下是提供数字证书的供应商的非详尽列表:
Symantec - www.symantec.com
DigiCert - www.digicert.com
VERISIGN - www.verisign.com
Thawte - www.thawte.com使用 “signtool” 进行签名
您可以使用 signtool.exe.ASPX) 工具对 .NET dll 进行签名。该工具会自动随 Visual Studio 一起安装。要运行该工具,请使用 Developer Command Prompt。以下是命令行参数的格式:
命令区域:使用 signtool1
signtool.exe sign /fd SHA256 /f <.pfx-file-name> /p .dl
其中 /fd 是要使用的文件摘要算法的标志。这里我们使用 SHA256。(SHA 代表安全哈希算法。signtool 默认值为 SHA1。我们建议使用 SHA256,这是一个更新、更安全的版本。<.pfx-file-name> 是您从供应商处获取的 .pfx(个人信息交换)文件的名称。是您在获取 PFX 文件时指定的密码。.dll 是要签名的 DLL 的名称。
例如,如果您在任意文件夹中运行命令,则上述命令可能如下所示:
1
"C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool" sign /fd SHA256 /f "C:/Dev/MyCert.pfx" /p "password123" “C:/Dev/HelloRevit.dll”
注意:signtool 的确切位置在您的环境中可能有所不同。
使用授权证书对 DLL 进行签名后,Revit 在加载附加模块时将不再弹出安全警告对话框。
您还可以在 Visual Studio 的 Post-Built Event 部分包含该命令,以用于应用程序项目属性。
命令区域:构建后事件签名1
2"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\signtool.exe" /fd SHA256 sign /f
"C:\Autodesk\MyCert.pfx" /p MyPassword "$(TargetDir)$(TargetFileName)"在签名时添加时间戳也是值得的(signtool.exe 中的 /td 和 /tr 开关);否则,当证书过期时,应用程序将变得不受信任。添加时间戳可确保应用程序在过期之前签名,就永远受信任(除非证书被吊销):
命令区域:添加时间戳1
signtool.exe timestamp /td sha256 /tr .dll
例如,以下代码使用 verisign 时间戳服务器:
命令区域:时间戳示例1
signtool.exe timestamp /td sha256 /tr "http://sha256timestamp.ws.symantec.com/sha256/" HelloRevit.dll
注意:上例中使用的 /td sha256 和 /tr 开关用于使用 sha256 时间戳进行签名。从 2017 年 1 月 1 日开始,Microsoft 会将 SHA1 时间戳视为未签名。有关更多详细信息,请参阅这篇文章。
制作自己的证书以供测试和内部使用
您可以制作自己的数字证书,以便在公司内部进行测试或使用。
创建自己的数字证书
- 使用 MakeCert.exe. ASPX)工具创建数字证书。
- 使用 Pvk2Pfx.exe 工具创建个人信息交换 (pfx) 文件。
- 对应用程序进行数字签名。
- 将数字证书导入 Windows 证书存储区。(CertMgr.msc 或 CertUtil.exe.aspx
1、创建数字证书
您可以使用 MakeCert.exe.ASPX)工具制作您自己的数字证书以供测试和内部使用。以下是命令格式:
命令区域:创建证书命令格式
1 | MakeCert.exe -r -sv .pvk -n "CN=" .cer -b -e |
其中 是你创建的 pvk 文件的名称,是你分配给 pvk 文件的密码。是认证文件或 .cer 文件的名称。是 .pfx 的名称。是要分配给 .pfx 文件的密码。
例如:
命令区域:MakeCert.exe示例
1 | "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\MakeCert.exe" -r -sv MyCert.pvk -n "CN=DevABC" MyCert.cer -b 01/01/2016 -e 12/31/2016 |
或:
命令区域:MakeCert.exe示例
1 | "C:\Program Files (x86)\Windows Kits\8.1\bin\x64\makecert.exe" -r -sv MyCert.pvk -n "CN=DevABC" MyCert.cer -b 01/01/2016 -e 12/31/2016 |
此命令将弹出“创建私钥密码”对话框。在对话框中输入私钥密码。如果系统要求输入密码,请再次输入。完成所有操作后,您将在命令窗口中看到一条消息“成功”,并创建 .cer 和 .pvk 文件。
2、转换为 PFX
下一步是使用 pvk2pfx.exe 工具将数字证书转换为个人信息交换 (pfx) 文件。在此步骤中,您需要在上述步骤中创建的 .pvk 文件、.cer 文件和密码。命令格式如下所示:
命令区域:转换为 PFX 命令格式
1 | pvk2pfx.exe" -pvk .pvk -pi -spc .cer |
其中 是存储私钥的文件的名称,是开发者的名字,是证书文件的名称,是证书生效的日期(格式为 mm/dd/yyyy),是证书的有效期结束的日期。
例如:
命令区域:转换为 PFX 示例
1 | "C:\Program Files (x86)\Windows Kits\8.1\bin\x64\pvk2pfx.exe" -pvk MyCert.pvk -pi password123 -spc MyCert.cer -pfx MyCert.pfx -po password234 |
操作成功后,命令结束,不显示错误消息,并将创建一个 .pfx 文件。
3、拥有 pfx 文件后,您可以对应用程序进行数字签名。
4、将数字证书导入 Windows 证书存储区
制作自己的数字证书时,还需要执行的另一个步骤是将其导入计算机。您可以在 Certificate Manager (CertMgr.msc.ASPX)) 或 CertUtils.exe 工具。这里我们使用 UI 工具。请参阅此处了解替代方案。
- 从开始 >> 运行 >> CertMgr.msc。(或在 Windows 8.1/10 上,右键单击“开始”>> 运行 >> CertMgr.msc)CertMgr 打开。
在 CertMgr 对话框中,右键单击 Trusted Publishers >> All Tasks >> Import … - 按照证书导入向导中的说明进行操作。单击 Next。
- 在询问“Files to Import”的对话框中,选择要导入的 pfx 文件。
- 在 “Password” 对话框中,输入密码。保持“包括所有扩展属性”的选中状态。
- 选择“将所有证书放在以下存储中”,然后单击下一步。
- 确认并完成。
如果您看到“Import a new Private signature key(导入新的私有签名密钥)”对话框,请单击“确定”。(这部分可能因您的环境而异。
对 Trusted Root Certification Authorities 重复相同的步骤。此步骤用于验证数字签名的二进制文件。
数字签名参考
The following references provide more information on digitally signing apps.
以下参考资料提供了有关对应用程序进行数字签名的更多信息。Revit Help Revit 帮助
Security: Invalid Signature
安全性:签名无效Microsoft and Other Sites Microsoft 和其他网站
How to sign an app package using SignTool
如何使用 SignTool 对应用程序包进行签名.aspx?f=255&mspperror=-2147217396)makecert.exe missing in windows 7, how to get it and use it
Windows 7 中缺少makecert.exe,如何获取和使用它The truth about SHA1, SHA-256 and Code Signing Certificates
关于 SHA1、SHA-256 和代码签名证书的真相AutoCAD references AutoCAD 参考
AutoCAD Blog AutoCAD 博客
本地化
您可以让 Revit 本地化外部命令按钮的用户可见资源(包括文字、大图标图像、长短描述以及工具提示图像)。您需要创建一个 .NET Satellite DLL,其中包含按钮的字符串、图像和图标。然后更改 .addin 文件中的标签值,使其与 Satellite dll 中的资源名称相对应,但前面要加上 @character。所以标签:
代码区域 3-13:非本地化文本输入
1 | Extension Manager |
成为:
代码区域 3-14:本地化文本输入
1 | @ExtensionText |
其中 ExtensionText 是在附属 DLL 中找到的资源的名称。
附属 DLL 应位于具有语言区域性语言名称的目录中,例如 en 或 en-US。该目录应位于包含加载项程序集的目录中。请参阅 http://msdn.microsoft.com/en-us/library/e9zazcx5.aspx 以创建托管的附属 DLL。
通过使用 LanguageType 标记显式指定语言和区域性,可以强制 Revit 使用特定语言资源 DLL,而不管 Revit 会话的语言如何。
代码区域 3-15:使用 LanguageType 标记
1 | English_USA |
例如,上面的条目将强制 Revit 始终加载 en-US Satellite 中的值,并在考虑外部命令清单文件的可本地化成员时忽略当前的 Revit 语言和区域性设置。
Revit 支持 Autodesk.Revit.ApplicationServices.LanguageType 枚举类型中定义的 11 种语言:English_USA、德语、西班牙语、法语、意大利语、荷兰语、Chinese_Simplified语、Chinese_Traditional、日语、韩语和俄语。
特性
Revit API 提供了多个用于配置 ExternalCommand 和 ExternalApplication 行为的特性。
TransactionAttribute
自定义属性 Autodesk.Revit.Attributes.TransactionMode 必须应用于 IExternalCommand 接口的实现类,以控制外部命令的事务行为。此选项没有默认值。此模式控制 API 框架在调用命令时预期如何使用事务。支持的值为:
TransactionMode.Manual - Revit 不会创建事务(但如果外部命令返回失败,它将创建一个外部事务组以回滚所有更改)。相反,您可以根据需要使用 Transactions、SubTransaction 和 TransactionGroups 的组合。您必须遵守有关使用交易和相关类的所有规则。您必须为您的交易命名,这些名称将出现在 Undo 菜单中。Revit 将检查从外部命令返回时,所有事务(包括组和子事务)是否已正确关闭。否则,Revit 将放弃对模型所做的所有更改。
TransactionMode.ReadOnly - 不会创建任何事务 (或组) ,并且在命令的生存期内不得创建任何事务。External Command 只能使用从模型中读取的方法。如果命令尝试启动事务(或组)或尝试写入模型,则会引发异常。
在任一模式下,TransactionMode 仅适用于活动文档。您可以在执行命令的过程中打开其他文档,并且可以完全控制在这些其他文档上创建和使用 Transactions、SubTransactions 和 TransactionGroups(即使在 ReadOnly 模式下也是如此)。
例如,要将外部命令设置为使用手动事务模式:
代码区域 3-18:TransactionAttribute
1 | [ ] |
请参阅 事务。
JournalingAttribute
可以选择将自定义属性 Autodesk.Revit.Attributes.JournalingAttribute 应用于 IExternalCommand 接口的实现类,以控制外部命令执行期间的日记行为。日记有两个选项:
JournalMode.NoCommandData - ExternalCommandData.JournalData 映射的内容未写入 Revit 日志。此选项允许 Revit API 调用根据需要写入日志。此选项允许调用 Revit UI 进行选择或响应任务对话框的命令正确重放。
JournalMode.UsingCommandData - 使用命令数据中提供的 IDictionary<String,String>。这将隐藏外部命令调用与 IDictionary<String,String>条目之间的所有 Revit 日志条目。调用 Revit UI 进行选择或响应任务对话框的命令可能无法正确重放。如果未指定 JournalingAttribute,则这是默认值。
代码区域 3-19:JournalingAttribute
1 | [Journaling(JournalingMode.UsingCommandData)] |
Revit 异常
当 API 方法遇到非致命错误时,它们会引发异常。Revit附加模块应捕获异常。Revit API 帮助文件指定了特定方法通常遇到的异常。所有 Revit API 方法都会引发 Autodesk.Revit.Exceptions.ApplicationException 的子类。这些异常与标准 .NET 异常非常相似,例如:
- ArgumentException ArgumentException(参数异常)
- InvalidOperationException
- FileNotFoundException
但是,其中一些子类对于 Revit 是唯一的:
- AutoJoinFailedException
- RegenerationFailedException
- ModificationOutsideTransactionException
此外,还有一种称为 InternalException 的特殊异常类型,它表示未预料到的失败路径。此类异常会附带额外的诊断信息,这些信息可以传回 Autodesk 进行诊断。
功能区面板和控件
Revit 提供了 API 解决方案来集成自定义功能区面板和控件。
这些 API 与 IExternalApplication 一起使用。自定义功能区面板可以添加到“加载项”选项卡、“分析”选项卡或新的自定义功能区选项卡中。
面板可以包括大按钮和小按钮,这些按钮可以是简单的按钮、包含多个命令的下拉按钮,也可以是拆分按钮,这些按钮是附加了默认按钮的下拉按钮。除了按钮之外,面板还可以包括单选按钮组、组合框和文本框。面板还可以包含垂直分隔符,以帮助将命令分隔到逻辑组中。最后,面板可以包含一个滑出控件,可通过单击面板底部来访问该控件。
有关开发符合 Autodesk 所用标准的用户界面的信息,请参见 API 用户界面指南部分中的功能区指南。
创建新的 Ribbon 选项卡
虽然可以将功能区面板添加到“加载项”或“分析”选项卡中,但也可以将其添加到新的自定义功能区选项卡中。仅在必要时才应使用此选项。为确保标准 Revit 功能区选项卡保持可见,自定义功能区选项卡限制为 20 个。下图显示了一个新的功能区选项卡,其中包含一个功能区面板和一些简单的控件。
下面是生成上述功能区选项卡的代码。
代码区域:“新建功能区”选项卡
1 | public Result OnStartup(UIControlledApplication application) |
创建新的 Ribbon 面板和控件
下图显示了使用各种功能区面板控件的 Add-Ins (加载项) 选项卡上的功能区面板。以下部分更详细地介绍了这些控件,并提供了用于创建功能区每个部分的代码示例。
图 14:新的功能区面板和控件
以下代码概述了创建如上图所示的功能区面板所采取的步骤。此示例中调用的每个函数将在本节后面的后续示例中提供。这些示例假定有一个位于 D:\ Sample\HelloWorld\bin\Debug\Hello.dll 的程序集,其中包含外部命令类型:
- Hello.HelloButton
- Hello.HelloOne
- Hello.HelloTwo
- Hello.HelloThree
- Hello.HelloA
- Hello.HelloB
- Hello.HelloC
- Hello.HelloRed
- Hello.HelloBlue
- Hello.HelloGreen
代码区域:功能区面板和控件
1 | public Result OnStartup(Autodesk.Revit.UI.UIControlledApplication app) |
Ribbon Panel 功能区面板
自定义功能区面板可以添加到“加载项”选项卡(默认)或“分析”选项卡中,也可以添加到新的自定义功能区选项卡中。可以将各种类型的功能区控件添加到功能区面板中,下一节将更详细地讨论这些控件。所有功能区控件都具有一些通用属性和功能。
功能区控件类
每个功能区控件都有两个与之关联的类 - 一个派生自 RibbonItemData,用于创建控件(即 SplitButtonData)并将其添加到功能区面板,另一个派生自 RibbonItem(即 SplitButton),表示将项添加到面板后的项目。RibbonItemData(和派生类)中提供的属性也可从 RibbonItem(和相应的派生类)中获得。可以在将控件添加到面板之前设置这些属性,也可以在将控件添加到面板之后使用 RibbonItem 类进行设置。
Tooltips 工具提示
大多数控件都可以设置工具提示(使用 ToolTip 属性),当用户将鼠标移到控件上时,将显示该工具提示。当用户长时间将鼠标悬停在控件上时,将使用 LongDescription 和 ToolTipImage 属性显示扩展工具提示。如果 LongDescription 和 ToolTipImage 均未设置,则不会显示扩展的工具提示。如果未提供工具提示,则当鼠标移动到控件上时,将显示控件的文本 (RibbonItem.ItemText)。
Contextual Help 上下文帮助
控件可以具有与之关联的上下文帮助。当用户将鼠标悬停在控件上并按 F1 时,将触发上下文帮助。上下文帮助选项包括链接到外部 URL、启动本地安装的帮助 (chm) 文件或链接到 Autodesk 帮助 Wiki 上的主题。ContextualHelp 类用于创建一种上下文帮助类型,然后 RibbonItem.SetContextualHelp()(或 RibbonItemData.SetContextualHelp())将其与控件相关联。当 ContextualHelp 实例与控件关联时,当鼠标悬停在控件上时,文本“按 F1 获取更多帮助”将出现在工具提示下方,如下所示。
下面的示例将新的 ContextualHelp 与按钮控件相关联。将鼠标悬停在按钮上时按 F1 将在新的浏览器窗口中打开 Autodesk 主页。
代码区域:上下文帮助
1 | private void AddPushButton(RibbonPanel panel) |
ContextualHelp 类具有一个 Launch() 方法,可以调用该方法来随时显示由此 ContextualHelp 对象的内容指定的帮助主题,这与在控件处于活动状态时按下 F1 键时相同。这允许将帮助主题与加载项应用程序创建的对话框中的用户界面组件相关联。
将图像与控件关联
所有这些控件都可以使用 LargeImage 属性具有与其关联的图像。与大型控件(如非堆叠功能区和下拉按钮)关联的图像的最佳大小为 32×32 像素,但较大的图像将进行调整以适合按钮。堆叠按钮和小控件(如文本框和组合框)应具有 16×16 像素的图像集。大按钮还应为 Image 属性设置 16×16 像素的图像。如果命令移动到快速访问工具栏,则使用此图像。如果未设置 Image 属性,则当命令移动到快速访问工具栏时,将不显示任何图像。请注意,如果使用大于 16×16 像素的图像,则不会调整它以适应工具栏。 ToolTipImage 将显示在扩展工具提示中的 LongDescription 下方(如果提供)。此图像没有建议的大小。
功能区控制可用性
可以使用 RibbonItem.Enabled 属性启用或禁用功能区控件,也可以使用 RibbonItem.Visible 属性使功能区控件可见或不可见。
功能区控件
除了以下控件之外,还可以将垂直分隔符添加到功能区面板,以对相关的控件集进行分组。
按钮
您可以向面板添加三种类型的按钮:简单按钮、下拉按钮和拆分按钮。图 14 中的 HelloWorld 按钮是一个按钮。按下该按钮时,将触发相应的命令。 除了 Enabled 属性之外,PushButton 还具有 AvailabilityClassName 属性,该属性可用于设置 IExternalCommandAvailability 接口的名称,该接口控制命令何时可用。
代码区域:添加按钮
1 | private void AddPushButton(RibbonPanel panel) |
Drop-down buttons 下拉按钮
下拉按钮展开后,可在下拉菜单中显示两个或多个命令。在 Revit API 中,下拉按钮称为 PulldownButtons。可以在下拉菜单中的项目之间添加水平分隔符。
下拉菜单中的每个命令也可以具有关联的 LargeImage,如上面的示例所示。
Split buttons 拆分按钮
拆分按钮是附加了默认按钮的下拉按钮。按钮的上半部分类似于按钮,而下半部分用作下拉按钮。图 14 中的 Option One 按钮是一个拆分按钮。
最初,按钮将是下拉列表中的顶部项目。但是,通过使用 IsSynchronizedWithCurrentItem 属性,默认命令(显示为拆分按钮的上半部分)可以与上次使用的命令同步。默认情况下,它将同步。在上面图 14 的 split 按钮中选择选项 2 将产生:
图 16:与当前项目同步的 Split 按钮
请注意,将忽略 SplitButton 的 ToolTip、ToolTipImage 和 LongDescription 属性。而是显示当前按钮的工具提示。
代码区域:添加拆分按钮
1 | private void AddSplitButton(RibbonPanel panel) |
Radio buttons 单选按钮
单选按钮组是一组互斥的切换按钮;一次只能选择一个。将 RadioButtonGroup 添加到面板后,使用 AddItem() 或 AddItems() 方法将切换按钮添加到该组。切换按钮派生自 PushButton。RadioButtonGroup.Current 属性可用于访问当前选定的按钮。
请注意,工具提示不适用于单选按钮组。相反,当鼠标移动到各个按钮上时,将显示每个切换按钮的工具提示。
代码区域:添加单选按钮组
1 | private void AddRadioGroup(RibbonPanel panel) |
Text box 文本框
文本框是供用户输入文本的输入控件。通过将 ShowImageAsButton 属性设置为 true,可以将文本框的图像用作可单击的按钮。默认值为 false。当 ShowImageAsButton 为 false 时,图像显示在文本框的左侧,当它充当按钮时,图像显示在文本框的右端,如图 14 所示。仅当用户按 Enter 键或在图像显示为按钮时单击关联的图像时,才会接受在文本框中输入的文本。否则,文本将恢复为之前的值。
除了为文本框提供工具提示外,PromptText 属性还可用于向用户指示要在文本框中输入的信息类型。当文本框为空且没有键盘焦点时,将显示提示文本。此文本以斜体显示。图 14 中的文本框具有提示文本 “Enter a comment”。
可以使用 Width 属性设置文本框的宽度。默认值为 200 个与设备无关的单位。
当用户按 Enter 键时,或者当 ShowImageAsButton 设置为 true 时,当用户单击文本框的关联图像时,将触发 TextBox.EnterPressed 事件。在实现 EnterPressed 事件处理程序时,将 sender 对象强制转换为 TextBox 以获取用户输入的值,如以下示例所示。
代码区域:TextBox.EnterPressed 事件处理程序
1 | void ProcessText(object sender, Autodesk.Revit.UI.Events.TextBoxEnterPressedEventArgs args) |
继承的 ItemText 属性对 TextBox 没有影响。用户输入的文本可以从 Value 属性中获取,该属性必须转换为字符串。 有关将 TextBox 添加到功能区面板的示例,包括如何注册上述事件,请参阅堆叠功能区项部分。
组合框
组合框是包含一组可选项的下拉列表。将 ComboBox 添加到面板后,使用 AddItem() 或 AddItems() 方法将 ComboBoxMembers 添加到列表中。 还可以将分隔符添加到列表中的单独项中,或者可以选择使用 ComboBoxMember.GroupName 属性对成员进行分组。具有相同 GroupName 的所有成员将分组在一起,并显示组名称的标头。任何未分配 GroupName 的项目都将放置在列表顶部。请注意,在对项目进行分组时,不应使用分隔符,因为它们将放置在组的末尾,而不是按添加顺序放置。
图 17:带分组的组合框
ComboBox 有三个事件:
CurrentChanged - 当 ComboBox 的当前项发生更改时触发
DropDownClosed - 关闭 ComboBox 的下拉列表时触发
DropDownClosed - 打开 ComboBox 的下拉菜单时触发
有关将 ComboBox 添加到功能区面板的示例,请参阅以下有关堆叠功能区项的代码区域。
堆叠面板项目
为了节省面板空间,您可以以 2 个或 3 个为一组的形式添加小面板项。堆栈中的每个项都可以是按钮、下拉按钮、组合框或文本框。单选按钮组和拆分按钮不能堆叠。堆叠按钮应具有通过其 Image 属性关联的图像,而不是 LargeImage。16×16 图像非常适合小型堆叠按钮。 以下示例生成图 14 中的堆叠文本框和组合框。
代码区域:将文本框和组合框添加为堆叠项
1 | private void AddStackedButtons(RibbonPanel panel) |
Slide-out panel 滑出面板
使用 RibbonPanel.AddSlideOut() 方法将幻灯片向功能区面板的底部添加。添加滑出后,面板底部会显示一个箭头,单击该箭头时将显示滑出。调用 AddSlideOut() 后,用于向面板添加新项的后续调用将添加到滑出式面板,因此必须在将所有其他控件添加到功能区面板后添加滑出式控件。
图 18:滑出
以下示例生成上面所示的滑出:
代码区域:TextBox.EnterPressed 事件处理程序
1 | private static void AddSlideOut(RibbonPanel panel) |
Revit 样式的任务对话框
TaskDialog 是简单 Windows MessageBox 的 Revit 样式替代方案。它可用于显示信息和接收来自用户的简单输入。它具有一组通用的控件,这些控件按标准顺序排列,以确保与 Revit 的其余部分保持一致的外观。
图 19:Revit 风格的任务对话框
有两种方法可以创建任务对话框并向用户显示。
第一个选项是构造 TaskDialog,单独设置其属性,并使用实例方法 Show() 向用户显示它。
第二种方法是使用静态 Show() 方法之一在一个步骤中构建和显示对话框。使用 static 方法时,只能指定选项的子集。
有关开发符合 Autodesk 使用的标准的任务对话框的信息,请参见 API 用户界面准则部分中的对话框准则。
以下示例显示如何创建和显示上面显示的任务对话框。
代码区域 3-27:显示 Revit 样式的 TaskDialog
1 | [ ] |
数据库级外部应用程序
数据库级附加模块是外部应用程序,不会向 Revit UI 添加任何内容。当应用程序的目的是将事件和/或更新程序分配给 Revit 会话时,可以使用数据库级外部应用程序。
要向 Revit 添加 DB 级外部应用程序,请创建一个实现 IExternalDBApplication 接口的对象。
IExternalDBApplication 接口有两个抽象方法:OnStartup() 和 OnShutdown(),您可以在 DB 级外部应用程序中重写它们。
Revit 在启动时调用 OnStartup(),在关闭时调用 OnShutdown()。这与 IExternalApplication 非常相似,但请注意,这些方法返回 Autodesk.Revit.DB.ExternalDBApplicationResult 而不是 Autodesk.Revit.UI.Result,并使用 ControlledApplication 而不是 UIControlledApplication。
代码区域:IExternalDBApplication OnShutdown() 和 OnStartup()
1 | public interface IExternalDBApplication |
ControlledApplication 参数提供对 Revit 数据库事件的访问。数据库级应用程序将响应的事件和更新程序可以在 OnStartup 方法中注册。