前言:项目中需要一个需求,用户想调用出Revit中自带的绘制模型线方法,然后再绘制结束时,可以拿到绘制的模型线,然后实现后面的算法。这里记录一种方法,通过DocumentChange事件+修改Tag的PropertyChanged事件来实现对应的需求。
以下示例使用的都是Revit2019的环境进行开发,其他版本会涉及到对应的API的不同,可以自行修改

1.背景

用户需要运行命令后,点击选择墙面,然后在墙面上绘制模型线,在推出绘制模式的时候,可以提取线,并且删除绘制的线

2.代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.DB.Events;
using System.ComponentModel;
using Autodesk.Windows;
using System.Windows;namespace RevitTest
{[Transaction(TransactionMode.Manual)]public class DUMDemo : IExternalCommand{/// <summary>/// 创建的构件/// </summary>private List<ElementId> _createIDList = new List<ElementId>();/// <summary>/// 判断是否已经载入/// </summary>private bool _subscribed;/// <summary>/// 外部事件/// </summary>private ExternalEvent _external;public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements){var tReference = commandData.Application.ActiveUIDocument.Selection.PickObject(ObjectType.Face, "选择面");CreateLine(commandData.Application, tReference);return Result.Succeeded;}public void CreateLine(UIApplication uiapp, Reference selRef){Document doc = uiapp.ActiveUIDocument.Document;using (Transaction ts = new Transaction(doc, "CreatModelCurve")){ts.Start();Face face = doc.GetElement(selRef).GetGeometryObjectFromReference(selRef) as Face;Plane tPlan = Plane.CreateByNormalAndOrigin(face.ComputeNormal(new UV()), selRef.GlobalPoint);doc.ActiveView.SketchPlane = SketchPlane.Create(doc, tPlan);ts.Commit();}RevitCommandId revitCommand = RevitCommandId.LookupCommandId("ID_OBJECTS_PROJECT_CURVE");if (revitCommand != null && uiapp.CanPostCommand(revitCommand)){//加入document改变事件uiapp.Application.DocumentChanged += PostElement;//添加标签修改事件foreach (var tab in ComponentManager.Ribbon.Tabs){if (tab.Id == "Modify"){if (_subscribed){tab.PropertyChanged -= TabPropertyChangedEvent;_subscribed = false;}else{tab.PropertyChanged += TabPropertyChangedEvent;_subscribed = true;}break;}}//添加外部事件BaseEvent selectChangeEvent = new BaseEvent();selectChangeEvent.EventAction = app =>{Transaction trans = new Transaction(app.ActiveUIDocument.Document, "删除线");trans.Start();try{app.Application.DocumentChanged -= PostElement;app.ActiveUIDocument.Document.Delete(_createIDList);_createIDList.Clear();}catch (Exception ex){MessageBox.Show(ex.Message);}trans.Commit();};_external = ExternalEvent.Create(selectChangeEvent);uiapp.PostCommand(revitCommand);}}/// <summary>/// 监控构件修改事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void PostElement(object sender, DocumentChangedEventArgs e){List<ElementId> collection = e.GetAddedElementIds().ToList();_createIDList.AddRange(collection);}/// <summary>/// 修改标签事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void TabPropertyChangedEvent(object sender, PropertyChangedEventArgs e){if (!(sender is RibbonTab)){return;}if (!string.Equals(e.PropertyName, "Title", StringComparison.CurrentCultureIgnoreCase)){return;}if (_subscribed == false){(sender as RibbonTab).PropertyChanged -= TabPropertyChangedEvent;MessageBox.Show($"{_createIDList.Count}");_external.Raise();}else{_subscribed = false;}}}/// <summary>/// 外部事件/// </summary>public class BaseEvent : IExternalEventHandler{/// <summary>/// 实现方法的委托函数/// </summary>public Action<UIApplication> EventAction { get; set; }public void Execute(UIApplication app){EventAction?.Invoke(app);}public string GetName(){return "事件";}}
}

3.代码分析

3.1 调用Revit中自带的模型线生成方法

通过直接调用内置方法的CommandId来实现放置模型线的方法

RevitCommandId revitCommand = RevitCommandId.LookupCommandId("ID_OBJECTS_PROJECT_CURVE");
uiapp.PostCommand(revitCommand);

3.2 注册DocumentChange事件

注册DocumentChange事件,通过这个事件去监控构建的添加,然后收集到集合中

     uiapp.Application.DocumentChanged += PostElement;
     /// <summary>/// 监控构件修改事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void PostElement(object sender, DocumentChangedEventArgs e){List<ElementId> collection = e.GetAddedElementIds().ToList();_createIDList.AddRange(collection);}

3.3 注册修改Tab的PropertyChanged事件

通过tabs去遍历所有的tab,然后ID为"Modify"的Tab对应的是修改按钮。因为进入绘制模型线的时候,Tab会变成“修改 | 放置线”,结束绘制的时候,变回“修改”,因此给tab直接加上属性修改的事件来监控整个流程的开始和结束

                foreach (var tab in ComponentManager.Ribbon.Tabs){if (tab.Id == "Modify"){if (_subscribed){tab.PropertyChanged -= TabPropertyChangedEvent;_subscribed = false;}else{tab.PropertyChanged += TabPropertyChangedEvent;_subscribed = true;}break;}}
     /// <summary>/// 修改标签事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void TabPropertyChangedEvent(object sender, PropertyChangedEventArgs e){if (!(sender is RibbonTab)){return;}if (!string.Equals(e.PropertyName, "Title", StringComparison.CurrentCultureIgnoreCase)){return;}if (_subscribed == false){(sender as RibbonTab).PropertyChanged -= TabPropertyChangedEvent;MessageBox.Show($"{_createIDList.Count}");_external.Raise();}else{_subscribed = false;}}

3.4 注册外部事件

外部事件的作用是在结束整体功能的时候,去除DocumentChange事件,以免照成事件加载多次的现象

//添加外部事件BaseEvent selectChangeEvent = new BaseEvent();selectChangeEvent.EventAction = app =>{Transaction trans = new Transaction(app.ActiveUIDocument.Document, "删除线");trans.Start();try{app.Application.DocumentChanged -= PostElement;app.ActiveUIDocument.Document.Delete(_createIDList);_createIDList.Clear();}catch (Exception ex){MessageBox.Show(ex.Message);}trans.Commit();};_external = ExternalEvent.Create(selectChangeEvent);

BaseEvent是自己定义的外部事件接口,大家可以根据自己的想法来封装

4.写在最后

对得到的构件进行操作的话,逻辑应该写在外部事件里面。

这里提供了一个监控生成构建的解决方案,但是做很复杂的操作时,有可能会出现外部事件丢失的情况。如果是想通过PropertyChanged事件去监控选择了什么构件的话,如果构件选择过多的时候,也是会出现错误的。大家如果遇到类似的问题,可以通过调试的方式去查看对应的问题。

Revit二次开发小技巧(十七)实时监控模型线的生成相关推荐

  1. Revit二次开发小技巧(十四)封闭墙体最大外轮廓

    前言:当前方法使用在既定的情况下,选择闭合的墙体,然后找到对应的外轮廓,并不支持存在开口的情况,仅提供一种思路.Revit版本为2019 代码: using Autodesk.Revit.Attrib ...

  2. Revit二次开发小技巧(十六)寻找最短路径

    最近遇到一个需求,指定两个配电箱,然后找到两个配电箱之间最短的桥架路径.运用了Dijkstra算法去计算最短路径,以配电箱实体.三通.四通为节点,简化中间弯头计算的方式. 背景 选择起点和终点的配电箱 ...

  3. Revit二次开发小技巧(十二)创建带洞口的墙

    这里记录一下项目上遇到的问题,就是创建带洞口的墙的时候,会发现创建接口仅有一个线集合传进去(如下图).当墙体有洞口的时候,线段就只能再一个集合中传进去了. 这时候会遇到一点问题,就是直接把两个轮廓的线 ...

  4. 用友NC二次开发小技巧:服务端执行SQL语句的方法

    大家好,今天给大家分享一下NC二次开发过程中的一个非常有用的小技巧:执行SQL语句. 我们在NC二开的过程中,经常需要直接查询数据库或者直接修改数据库表的字段值.这是一个非常简单并且通用的需求.下面给 ...

  5. Revit二次开发小火车工具集的复现

    这是复现了腿腿教学网麻蛋讲师所做的小火车工具集插件的代码.下面是Github的链接有需要可以下载. https://github.com/yingdajun/BabyTrainCopyDemo

  6. 【STM32开发小技巧】CUBEMX改变工程模板(FreeMarker一键生成定制文件)

    前言 一.使用默认模板 二.使用自定义模板 效果展示 总结 前言 ps:可直接跳到效果展示 众所周知CUBEMX可以生成代码,图形界面可以方便用户进行STM32的配置,有天我就在想能否用户改变生成后的 ...

  7. Revit二次开发——读取CAD文字实现更新模型的思路

    更新模型 与内地BIM项目中 设计院终版图纸一波流翻模的模式不同 香港BIM项目的模式是:设计出图-BIM出碰撞报告-设计再改图-BIM再碰撞报告-反反复复- 模型频繁更新 是BIM项目服务过程中不可 ...

  8. Revit二次开发实现BIM盈利(以橄榄山快模为例解说) 视频讲座下载

    应笔墨闲谈群的邀请, 在10月11号晚8:30分在其群做了一次关于BIM二次开发的讲座. 因为參与者基本上都是从设计院和施工单位来的,所以对Revit二次开发做了纵览性的解说, 以非程序猿能听懂的方式 ...

  9. 小六六平时的开发小技巧二(Nacos在服务配置中心的妙用)

    前言 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/bin392328206/six-finger 絮叨 小六六打算开一个系列把自己平时的一些开发经验分享出来和 ...

最新文章

  1. nodejs之connect
  2. 【计算机网络】网络安全 : 数据加密模型 ( 加密模型 | 密钥 | 密码学 | 密码安全 )
  3. 生成任意内容任意类型的文件
  4. c++和python的区别、javascript_python和c++的区别
  5. 数据库开发——MySQL——基本操作
  6. linux内核常用函数或宏
  7. 极简代码:害死人不偿命的(3n+1)猜想 (15分)
  8. raptor算法流程图例题_RAPTOR流程图+算法程序设计教程
  9. 离线语音识别软件_从音乐识别软件起家,这家公司如何备战车载AI语音市场GGAI对话...
  10. 从51能不学编程只学c语言,51单片机C语言学习笔记8:单片机C51编程规范
  11. 多个线程并发执行完成后再执行主线程-java(有点内容版)
  12. (转)“宇宙之王”高盛在历史的交叉口,不得不全面走向机器自动化
  13. 【软件】一个简单好用的取色器TakeColor(百度云免费下载链接)
  14. Xshell6 plus绿色永久版_SSH连接工具_站长必备工具集
  15. 注册表(安全 活动桌面)
  16. P4238 【模板】多项式乘法逆
  17. 腾亚幕墙Web开发基础教程
  18. (私人收藏)64个精致的页面loadinggif动画
  19. 前端学HTTP之web攻击技术
  20. 计算机软技能,在个人简历中有哪些软技能可以写?

热门文章

  1. html关闭ios橡皮筋效果,禁止ios浏览器页面上下滚动 (橡皮筋效果)
  2. linux权限drwx,linux权限基础知识详解
  3. 《快速掌握PyQt5》专栏整理成书出版啦!
  4. 【Vue】获取cookie
  5. 李洵同款爱心加红蓝动态线条爱心
  6. git 强制更新本地代码与服务器端一致
  7. ipad vs android,安卓和苹果平板简评 iPad2018和华为平板M610.8英寸版区别对比
  8. 我的宝宝有了他/她的乳名!
  9. 计算机科学与探索类别,图像目标类别检测综述-计算机科学与探索.pdf
  10. 查看端口被占用命令(Windows+Linux)