Revit二次开发3、外部命令(IExternalCommand)
[个人学习笔记整理,若有错误请各位同仁告知与我]
外部命令
插件开发都可以通过IExternalCommand来添加自己的应用。Revit通过.addin来识别和加载外部插件以扩展和增强Revit的功能和应用。
基本原理
如果Revit没有其他命令在运行或者是没有处于编辑模式,那么已经注册到Revit系统的ExternalCommand就会被激活。一旦插件(菜单或按钮)被选中,对应外部命令对象就会被创建出来,并且执行外部命令中的Execute函数。执行完毕后,外部命令对象就被销毁。在两个命令之间数据不能保存在对象中,要通过其他方式来保存。
IExternalCommand接口
IExternalCommand是API通过外部命令扩展Revit时在外部命令中的接口。其接口只有一个抽象函数EXcute,用于添加自己的命令。
public interface IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
}
参数
Execute函数有三个参数:输入参数commandData(ExternalCommandData类型)、输出参数message(string类型)、输出参数elements(ElementSet类型)。
输入参数commandData
ExternalCommandData中包含了外部命令所需的Application以及一些视图的引用。在外部命令中,所有的Revit数据都可以通过这个参数直接或间接地被取到。
属性 | 说 明 |
---|---|
Application(Autodesk.Revit.UI.UiApplication) | 用于表示适用于当前外部命令的Application对象 |
View(Autodesk.Revit.DB.View) | 用于表示当前外部命令起作用的视图对象 |
JournalData(IDictionary<Stnng,String>) | 用于在Revit Journal文件中读写数据的数据字典,主要应用 于做自动化测试时与外部命令做交互使用 |
//代码片段
UIApplication uiApplication = commandData.Application;
Application application = uiApplication.Application;
UIDocument uiDocument = uiApplication.ActiveUIDocument;
Document document = uiDocument.Document;
输出参数message
外部命令可以通过这个参数来返回执行过程中的错误信息。
这个参数作用于整个外部 命令的执行过程,用户可以在外部命令执行过程中的任何时候给这个信息设值或者追加信 息。
当外部命令的 Execute 函数返回 Autodesk.Revit.UI.Result.Failed 或者 Autodesk.Revit.UI.Result.Canceled,这个错误信息将被显示在UI上。
示例:
//主要代码片段
public class command: IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
message="错误信息测试!";
return Result.Failed;
}
}
在本例中将会返回“错误信息测试!”并在弹出的对话框中进行显示:
输出参数elements
当外部命令返回Autodesk.Revit.UI.Result.Failed 或者 Autodesk.Revit.UI.Result.Cancel 并且 message 参数不为空的时候,错误或者警告对话框会 弹出来,点击上面的显示按钮,elements参数中的元素将被会被高亮显示。
示例:
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
message = "请注意所选择的墙体会亮显!";
//当前活动文档界面
UIDocument uidoc = commandData.Application.ActiveUIDocument;
//当前活动文档
Document doc = uidoc.Document;
//当前选择集元素的Id集合
ICollection<ElementId> elems = uidoc.Selection.GetElementIds();
foreach(ElementId eleid in elems)
{
//获取图元元素
Element ele = doc.GetElement(eleid);
//如果图元是墙体则添加到ElementSet中
if (ele is wall)
{
elements.Insert(ele);
}
}
//返回Failed或Canceled以显示错误对话框并提取到ElementSet返回值
return Result.Failed;
}
点选墙运行插件,会弹出错误提示,而且墙体会亮显,如下图:
返回值
Execute的返回值用于表示外部命令的执行状态(结果),有三种情况:Autodesk.Revit.UI.Result.Succeeded,Autodesk.Revit.UI.Result.Failed或者Autodesk.Revit.UI.Result.Canceled。
如果返回值为Succeeded,则所有外部命令的操作成功,对应的修改被应用。
如果返回值不为Succeeded,则Revit会把外部命令所做的所有操作和修改撤销。
示例详见下一部分。
外部命令的实现
基本框架
一个外部命令IExternalCommand插件代码的基本框架如下:
using Autodesk.Revit.DB;
...
namespace xxx
{
[Transaction(TransactionMode.Manual)]
public class RevitCommand : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
UIDocument uidoc = commandData.Application.ActiveUIDocument;
Document doc = uidoc.Document;
//···············
//一般性处理代码
//···············
using (Transaction tran = new Transaction(doc, "事务名称"))
{
tran.Start();
//·················
//Revit模型处理代码
//·················
tran.Commit();
}
//[其它处理代码]······
return Result.Succeeded;
}
}
}
一个完整的事例
根据本节内容,模拟了Revit中删除所选的图元的简单示例,虽然功能简单但示例完整,而且加入了异常处理的try…catch语句。
其基本操作,选择想删除的图元(可多选),启动插件命令后会弹出确认删除的提示对话框。
完整代码内容如下:
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System.Collections.Generic;
using System.Linq;
namespace xxx
{
[Transaction(TransactionMode.Manual)]
public class RevitCommand : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
try
{
UIDocument uidoc = commandData.Application.ActiveUIDocument;
Document doc = uidoc.Document;
List<ElementId> elems = uidoc.Selection.GetElementIds().ToList();
using (Transaction tran = new Transaction(doc, "删除构件"))
{
tran.Start();
doc.Delete(elems);
tran.Commit();
}
TaskDialogResult result = TaskDialog.Show(
"Revit",
"是否删除所选对象:\n"+
" 点击“是”删除所选对象\n 或者\n 点击“否”取消删除",
TaskDialogCommonButtons.Yes | TaskDialogCommonButtons.No
);
if (result == TaskDialogResult.Yes)
{
return Result.Succeeded;
}
else if (result == TaskDialogResult.No)
{
foreach (ElementId eleid in elems)
{
Element ele = doc.GetElement(eleid);
if (ele != null)
{
elements.Insert(ele);
}
}
return Result.Failed;
}
else
{
return Result.Cancelled;
}
}
catch
{
message = "意外的异常被被抛出!";
return Result.Failed;
}
}
}
}
此段代码根据书本内容改写,可以运行但会有错误提示,本人目前水平有限没能修改完好,待完善。同时,也希望各位同仁给予指点。
执行结果如下图,若选“是”则删除操作完成,若选“否”则删除事务回滚到删除前的状态,如果运行中出现其它未知错误则抛出Revit系统的异常信息。
说明:
【1】以上主要内容来自欧特克(中国)软件研发有限公司主编的《Autodesk REVIT二次开发基础教程》,同济大学出版社出版。
【2】由于教程对应Revit版本为2015以前版本,因为Revit版本更新,其中的一些API接口发生变化,原书的部分代码不能在现行版本的Revit中重现,本人根据所学内容对其部分代码进行了修改以适应现行的Revit版本(本人以Revit2019为主要测试主体,以后同)。
【3】本人填补了部分在学习中因为版本的不同所遇到的坑,在此对笔记的整理过程中加入了个人的部分理解与解释,希望对各位如我一样的初学者有所帮助。