在 Revit 二次开发项目中,你是否碰到过做一个类似 Revit 项目浏览器这种需求呢?在打开你插件对话框之后,就算不关闭它,用户也可以正常操作 Revit 的其他功能。Revit API 提供了可停靠对话框( DockablePane)来实现这类的功能。
首先新建对话框,需要注意的是,这里要选择 Page, 而不是 Window。
创建完成后(我这里命名为 Dialog),打开 Dialog.xaml.cs。Dialog 类需要实现 IDockablePaneProvider 接口,同时需要添加命名空间 Autodesk.Revit.UI。
接着我们需要实现 IDockablePaneProvider 接口的 SetupDockablePane 方法。一般这里用来设置一些对话框的初始状态,我在这里把初始位置设置为了漂浮状态。具体如下。
到此,我们对话框就设置好了。
然后,跟通常一样,我们需要一个按钮来打开这个对话框。新建一个类(这里命名为 App),实现 IExternalApplication 接口。在 OnStartup 方法中添加一个 PushButton 来执行 TestCommand (稍后实现)。此外,我们还需要注册我们的 Dialog 对话框。注册时需要给一个 Guid。
最后,我们实现 TestCommand, 通过注册对话框时的 Guid 找到我们的对话框,打开它就可以了。
在 Revit 中点击按钮,我们就能看到这样的效果。它也可以像项目浏览器那样吸附在右边或者底边。
这样做对话框的话会带来一个问题。TestCommand 类中,当程序执行完 dp.Show(),会马上执行下面的 return。这样导致我们打开了对话框之后就退出了 Revit API 的环境,也就失去了执行 Revit 相关功能的机会。例如,对话框里做了一个按钮,点击按钮我们在当前项目中新建一个族实例,类似这种功能都不能正确执行。这时候,我们就需要用到 Revit API 中的 ExternalEvent。
首先,我们新建一个 RequestHandler 类,实现 IExternalEventHandler 接口。需要实现该接口的两个方法:
1. GetName:这里随便返回一个 string 作为这个 handler 的名称即可。
2. Execute:这里是真正执行 Revit 相关操作的地方。
其次,我们修改 Dialog 类的构造函数,用 RequestHandler 对象来创建一个 ExternalEvent 对象,如下。
然后,给 Dialog 添加一个按钮,并添加点击事件。在点击事件中,我们调用 externalEvent.Raise(),这样 RequestHandler 类的 Execute 就会执行,从而里面的 Revit 操作也就顺利执行了。
还有最后一个问题!现在 RequestHandler 类的 Execute 方法默认只有一个入参:UIApplication。如果我们 Dialog 对话框有两个按钮,它们分别执行不同的 Revit 操作,比如一个新建族实例,一个删除族实例。这时候就需要 Execute 方法多一个入参,比如 int,用来区别不同的按钮指令。我们需要包装一下 ExternalEvent。新建 ExternalEventWrapper 类,代码如下。
原来 RequestHandler 类是实现了 IExternalEventHandler 类,现在我们改为继承 ExternalEventWrapper<T>。T为想要的入参类型,我们这里为 int。重写 Execute 方法,这时候我们就有两个入参了:UIApplication和int。通过不同的int值我们来区分新建族实例和删除族实例。
回到 Dialog 类,改用我们的新的 RequestHandler。
最后我们再添加一个按钮,两个按钮分别调用 requestHandler.Raise(0) 和 requestHandler.Raise(1)。这样它们就能分别新建和删除族实例了。