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

news2025/6/30 22:26:10

前言:项目中需要一个需求,用户想调用出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事件去监控选择了什么构件的话,如果构件选择过多的时候,也是会出现错误的。大家如果遇到类似的问题,可以通过调试的方式去查看对应的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/150215.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python】pandas获取全省人口数据并作可视化分析

前言 今天我们看看自己所在的省份的人口人数&#xff0c;使用pandas并作可视化分析。 环境使用 python 3.9pycharm 模块使用 pandasPandas 是基于NumPy的一种工具&#xff0c;该工具是为解决数据分析任务而创建的。Pandas 纳入了大量库和一些标准的数据模型&#xff0c;提供…

java和vue募捐网水滴筹项目捐款爱心系统筹款系统

简介 募捐网&#xff0c;注册用户实名认证通过后可以发布募捐&#xff0c;管理员审核募捐通过后&#xff0c;前台用户可以看到该募捐信息&#xff0c;进行募捐或者举报&#xff08;管理审核举报成功后&#xff0c;会拉黑该募捐发起人&#xff09;&#xff0c;前台展示公告、爱…

83. 删除排序链表中的重复元素(链表)

文章目录题目描述方法一 暴力法方法二 递归法参考文献题目描述 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2] 示例 2…

酷开系统——家庭场景下的智能营销系统!

随着人们生活方式的改变&#xff0c;以往传统的营销资源和渠道正在慢慢陷入一个“无用”的尴尬境地&#xff0c;而作为家庭娱乐中心的智能大屏&#xff0c;近两年所表现出来的数据和效果却逐渐备受企业和品牌方关注&#xff0c;有数据显示&#xff0c;智能大屏的家庭覆盖规模正…

bug 站在一个测试的角度看bug

如何描述一个bug ?如何定义bug的级别 ?bug的生命周期 ?如何开始第一次测试 ?测试的执行和bug管理 ?产生争执怎么办 ?如何描述一个bug?作为一名测试人员&#xff0c;提bug是最基础的工作&#xff0c;那我们如何才能把bug提的清晰易懂呢?发现问题的版本 开发人员获取对应…

k8s之基于kubeadm搭建k8s集群

写在前面 你可能知道搭建k8s集群的kind&#xff0c;minikube工具&#xff0c;但是他们都太简单了&#xff0c;不能满足生产级的要求&#xff0c;想要真正的部署生产级别的k8s集群&#xff0c;我们还需要另外一个集群管理工具kubeadm ,本文就一起看下如何使用该工具来搭建k8s集…

STM32MP157驱动开发——Linux下的单总线驱动

STM32MP157驱动开发——Linux下的单总线驱动0.前言一、DS18B20 及工作时序简介1.DS18B20 简介2.DS18B20 时序简介4.DS18B20温度读取流程二、DHT11 及工作时序简介1.DHT11 简介2.DHT11 工作时序简介三、驱动开发1.DS18B20驱动1&#xff09;修改设备树2&#xff09;驱动编写2.测试…

IB生物:干细胞与生命的各种功能

国际学校生物老师解读IB生物&#xff0c;感兴趣的同学记得收藏哦~IB生物分为SL(standard level)和HL(higher level)SL有6个topic∶细胞生物&#xff0c;分子生物&#xff0c;遗传学&#xff0c;生态学&#xff0c;物种进化以及多样性和人体生理。HL除了上述6个topic外还要加上∶…

Python入门基础实例讲解——两个数字比大小,并输出最大值

嗨害大家好鸭&#xff01; 我是小熊猫~ 今天也是给大家带来干货的一天~ pycharm永久激活码可以从这里找到我&#xff1a; 输出&#xff1a;print&#xff08;&#xff09; print() 方法用于打印输出&#xff0c;最常见的一个函数。 比较运算符 >&#xff1a; 大于&#…

关于校园网的各种连接问题

校园网网络使用异常&#xff0c;掉线、卡顿以及无法连接网络&#xff0c;经网络上收据的信息&#xff0c;大致分为五类&#xff1a;1.能获取到校园网地址如10.*.*.*&#xff0c;但无法跳出认证界面。2.物理链路故障&#xff1b;3.IP配置故障&#xff1b;4. 网络正常&#xff0c…

SpringCloud高级应用-1(SpringCloud技术栈概览)

1、SpringCloud技术栈 开发分布式系统可能具有挑战性&#xff0c;复杂性已从应用程序层转移到网络层&#xff0c;并要求服务之间进行更多的交互。将代码设为“cloud-native”就需要解决12-factor&#xff0c;例如外部配置&#xff0c;服务无状态&#xff0c;日志记录以及连接…

【矩阵论】8. 常用矩阵总结——单阵,正规阵,幂0阵,幂等阵,循环阵

矩阵论 1. 准备知识——复数域上矩阵,Hermite变换) 1.准备知识——复数域上的内积域正交阵 1.准备知识——Hermite阵&#xff0c;二次型&#xff0c;矩阵合同&#xff0c;正定阵&#xff0c;幂0阵&#xff0c;幂等阵&#xff0c;矩阵的秩 2. 矩阵分解——SVD准备知识——奇异值…

基于Promethus+Grafana搭建监控系统

简介 ● 监测数据类型&#xff1a;JVM数据、在线人数、消息时延等 ● 接入Prometheus性能监测工具&#xff0c;暴露服务器性能监测数据 ○ 模式&#xff1a;pull/push ● 接入Grafana可视化数据 搭建流程 准备环境 Java客户端配置 <!-- The client --> <depende…

IDEA 的Http接口调试工具

简介 这个工具我们可以完成绝大部分http请求&#xff0c;是一个不错的post-man替代工具 插件安装 在使用之前先确保 HTTP Client插件的安装&#xff0c;如果已经安装请无视这一步 > 安装后记得重启IDE编辑器确保插件可以正常使用 插件使用 描述&#xff1a; 所有HTTP请求…

2023年1月6日星期五-PPP/BPP相关学习-旧版重写

1. 独立均匀分布 matlab的rand指令可以帮助我们生成[0,1]的均匀分布的数据&#xff0c;这样&#xff0c;如果我们想要[a,b]的分布数据&#xff0c;只需要a(b-a)*rand就可以了。 [a,b] 均值μ&#xff0c;标准差 均值 标准差 matlab代码&#xff1a; %% 生成一个n行p列的矩…

Excel 中合并单元格的快捷键(ALT+H+M+M)

要在 excel 中合并单元格,首先选择要合并到一个单元格中的单元格,然后可以使用从ALT开始的快捷键,然后同时按H+M+M。 一旦我们使用快捷键执行该函数,它将弹出一条警告消息“合并单元格时,仅保留左上角的值,而放弃其他值“。如果我们继续,单元格将被合并,只保留一个值。…

Nature chemistry|机器学习可以克服自组装肽发现中的人类偏见

题目&#xff1a;Machine learning overcomes human bias in the discovery of self-assembling peptides 文献来源&#xff1a;Nature Chemistry | Volume 14 | December 2022 | 1427–1435 代码&#xff1a;https://doi.org/10.5281/zenodo.6564202&#xff08;非商业化证书…

Java安全:SecurityManager与AccessController

前言 什么是安全&#xff1f; 程序不能恶意破坏用户计算机的环境&#xff0c;比如特洛伊木马等可自我进行复制的恶意程序。程序不可获取主机及其所在网络的私密信息。程序的提供者和使用者的身份需要通过特殊验证。程序所涉及的数据在传输、持久化后都应是被加密的。程序的操…

Hudi的核心概念 —— 文件布局(File Layout)

文章目录文件布局&#xff08;File Layout&#xff09;Hudi 存储分为两个部分文件布局&#xff08;File Layout&#xff09; Hudi 将一个表映射为如下文件结构 Hudi 存储分为两个部分 &#xff08;1&#xff09;元数据&#xff1a;.hoodie 目录对应着表的元数据信息&#xff…

Vivado综合设置之-no_lc

本文详细讨论了当勾选或者不勾选-no_lc时的差异&#xff0c;也详细介绍了using O5 and O6以及using O6 output only的具体含义。 -no_lc表示NO LUT Combining&#xff0c;即无LUT整合&#xff0c;默认不勾选&#xff0c;即默认有LUT整合。LUT整合可以减少对LUT的使用量&#x…