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

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

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

baobao熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值