RevitAPI: 注意Revit 2016事件注册和注销行为的改变

本文章为转载,原作者卢石碧,文章链接

http://blog.csdn.net/lushibi/article/details/48312281



在以前的Revit版本中, 我们可以在一个非模态对话框中注册或者注销一个事件,但是Revit 2016做了一些改变,不再允许这样做,凡是在非Revit主线程里面的注册或者注销事件,系统会抛出异常,如果您没有捕获这个异常,将会导致系统崩溃。

官方的原话是这样的:

API events - behavioral change

Although the Revit API has never officially supported such a work-flow it is now enforced that registering to and unregistering from events must happen while executing on the main thread. An exception will be thrown if an external application attempts to register to (or unregister from) events from outside of valid API context.


解决办法:

  • 使用模态对话框,或者尽量保证事件在ExternalCommand的Execute函数或者ExternalApplication的OnStartup函数里面注册。
  • 如果一定要使用非模态对话框,那么请使用ExternalEvent事件的Raise函数,强迫程序进入Revit主线程,然后在里面进行注册事件。

代码示例:
首先定义一个类实现IExternalEventHandler,在Execute函数里面我们注册一个事件。

public class EventRegisterHandler : IExternalEventHandler  
{  
    public void Execute(UIApplication app)  
    {  
        app.Application.DocumentChanged += Application_DocumentChanged;  
    }  
  
    void Application_DocumentChanged(object sender, Autodesk.Revit.DB.Events.DocumentChangedEventArgs e)  
    {  
        // do your stuff  
    }  
  
    public string GetName()  
    {  
        return "EventRegisterHandler";  
    }  
}  

在需要执行注册的时候,创建一个ExternalEvent的实例并调用它的Raise函数,例如,点击一个按钮实现注册,可以使用如下代码:
private void button1_Click(object sender, EventArgs e)  
{  
    ExternalEvent _exEvent = null;  
    EventRegisterHandler _exEventHandler = null;  
    _exEventHandler = new EventRegisterHandler();  
    _exEvent = ExternalEvent.Create(_exEventHandler);  //ExternalEvent.Create报错
    _exEvent.Raise();  
}  

2016/3/8 更新:

有人指出button1_Click函数会抛出异常
Autodesk.Revit.Exceptions.InvalidOperationException: Attempting to create an ExternalEvent outside of a standard API execution

确实是一个问题。解决方法也比较简单,就是不要在非模态对话框里面创建ExternanlEvent,而是在IExternalCommand的Execute函数,或者IExternalApplication的OnStartup函数里面创建。
下面是一个完整例子的代码,用户运行命令EventRegistrationInModelessDialogViaExternalEvent之后可以点击非模态对话框上的按钮来注册或者注销DocumentChanged事件。
using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.Threading.Tasks;  
using Autodesk.Revit.ApplicationServices;  
using Autodesk.Revit.Attributes;  
using Autodesk.Revit.DB;  
using Autodesk.Revit.UI;  
using System.Windows.Forms;  
  
namespace TestScript  
{  
    [TransactionAttribute(TransactionMode.Manual)]  
    public class EventRegistrationInModelessDialogViaExternalEvent   
        : IExternalCommand  
    {  
        public Document doc;  
        public Autodesk.Revit.ApplicationServices.Application RevitApp;  
        ExternalEvent _exEvent;  
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)  
        {  
            EventRegisterHandler _exeventHander = new EventRegisterHandler();  //外部事件进入Revit主线程
            _exEvent = ExternalEvent.Create(_exeventHander);  //此处ExternalEvent.Create
            MyForm form = new MyForm();  
            form.ExEvent = _exEvent;  //外部事件与WinForm关联
            form.Show();  
  
            return Result.Succeeded;  
        }  
    }  
  
    public class MyForm : System.Windows.Forms.Form  
    {  
        public MyForm()  
            : base()  
        {  
            Button btn = new Button();  
            btn.Text = "Toggle DocumentChanged Event Registration";  
            btn.Click += btn_Click;  
            btn.Width = 250;  
            this.Controls.Add(btn);  
        }  
  
        public ExternalEvent ExEvent { get; set; }  //建立外部事件
  
        void btn_Click(object sender, EventArgs e)  
        {  
            if (ExEvent != null)  
                ExEvent.Raise();  //Reise()
            else  
                MessageBox.Show("external event handler is null");  
        }  
    }  
  
    public class EventRegisterHandler : IExternalEventHandler  //与《Autodesk Revit二次开发基础教程》第192页,代码片段9-4不同
    {  
        public bool EventRegistered { get; set; }  
        public void Execute(UIApplication app)  
        {  
            if (EventRegistered)  
            {  
                EventRegistered = false;  
                app.Application.DocumentChanged -= Application_DocumentChanged;  //注册事件
            }  
            else  
            {  
                EventRegistered = true;  
                app.Application.DocumentChanged += Application_DocumentChanged;  //注销事件
            }  
        }  
  
        void Application_DocumentChanged(object sender,   
            Autodesk.Revit.DB.Events.DocumentChangedEventArgs e)               //外部事件
        {  
            var sb = new StringBuilder();  
            var added = "added:" + e.GetAddedElementIds()  
                .Aggregate("", (ss, el) => ss + "," + el).TrimStart(',');  
            var modified = "modified:" + e.GetModifiedElementIds()  
                .Aggregate("", (ss, el) => ss + "," + el).TrimStart(',');  
            var deleted = "deleted:" + e.GetDeletedElementIds()  
                .Aggregate("", (ss, el) => ss + "," + el).TrimStart(',');  
            sb.AppendLine(added);  
            sb.AppendLine(modified);  
            sb.AppendLine(deleted);  
            TaskDialog.Show("Changes", sb.ToString());  
        }  
  
        public string GetName()  
        {  
            return "EventRegisterHandler";  //与类名保持一致
        }  
    }  
}  


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值