原文链接:
Idling Enhancements and External Events
Revit 2013 的一个重要的 API 改进就是空闲事件与无模态对话框的交互。相应的,这篇博文将讨论与之相关的几个主题:
Revit 2013 中空闲事件被更新成拥有两种运行模式。空闲事件使用 Revit 2013 的默认模式时,Revit 在每次开始一个空闲会话时就会触发一次空闲事件。而空闲会话的启动条件分两种情况:
Revit 之前版本中的模式在 2013 中作为非默认模式(这就意味着我们之前的空闲事件代码需要更新为显示地指定为新版本的非默认模式)。非默认模式中空闲会话会一直保持开启状态的。这可以保证程序能使用用户离开电脑的这段时间。但是缺点是因为要一直维护空闲会话,所以会导致部分系统资源始终被占用,降低了性能。
Revit 2013 为空闲事件参数提供了方法 SetRaiseWithoutDelay(),用于控制空闲事件的运行模式。如果希望使用非默认模式,则必须在每次空闲事件被触发时,显示地调用 SetRaiseWithoutDelay() 方法。如果当次没有调用,则 Revit 将自动进入默认模式,直到下一次调用 SetRaiseWithoutDelay() 方法为止。
没有活动文档时的空闲事件
与 Revit 2012 不同,空闲事件在 Revit 没有活动文档时也会被触发了。
外部事件框架
空闲事件提供了一种 Revit 与外部异步过程的交互通道。Revit 是不允许外部过程直接调用其 API 的,但是外部过程可以向 Revit 发送请求,让其在下一次空闲事件时处理。一个典型应用就是在 Revit 插件中使用非模态对话框。不过由于非模态对话框在很多时候是没有用户交互的,所以导致空闲事件处理函数在这些时候不用做任何处理就直接返回了(译者注:不低碳啊!)。
Revit 2013 提供了一种更简单和高效的异步处理方式:外部事件框架。外部事件框架的处理有些类似默认模式时的空闲事件。不同的地方在于,外部事件只有在程序显示地触发时才会启动处理逻辑,而不像空闲事件一样经常出现处理函数无事可做的情况。
1. 实现一个继承自 IExternalEvent 接口的外部事件;
2. 调用 ExternalEvent.Create() 创建一个外部事件对象;
3. 当外部异步过程提交一个需要 Revit 处理的请求时,调用外部事件对象的 Raise() 方法;
4. Revit 在下一个可用的空闲周期中调用外部事件对象的 Execute() 方法;
外部事件框架对开发非模态对话框特别有帮助,因为可以避免会话无事可做的情况。
外部事件接口的定义:
RevitWebcam 例程续篇
我使用新版的空闲事件和外部事件更新了 RevitWebcam 例程,你可以下载代码(RevitWebcam_2013.zip)比较历史版本和新版本的区别。
你还可以参考 SDK 例程 ModelessForm_ExternalEvent and ModelessForm_IdlingEvent。
在事件响应函数中调用 OpenAndActiveDocument() 方法
在 Revit 2012 中,OpenAndActiveDocument() 方法是无法在任何事件响应函数中被调用的。在 Revit 2013 中,这个限制基本被取消了。以下是几个典型的应用场景:
原始活动文档没有正在处理的事务(包括事务组)时,可以在外部事件处理函数中调用;
对于常规事件(例如:空闲事件、ApplicationInitialized 事件)处理函数来说,如果当前没有活动文档且事件没有嵌套在另外一个事件或者外部命令中时,可以调用;
通常情况下,相对于空闲事件处理函数而言,ApplicationInitialized 事件处理函数更适合用于打开第一个文档。
Revit 2013 的一个重要的 API 改进就是空闲事件与无模态对话框的交互。相应的,这篇博文将讨论与之相关的几个主题:
- 空闲事件的重复性
- 没有活动文档时的空闲事件
- 新的外部事件框架
- RevitWebcam 例程续篇
- 在事件相应函数中使用 OpenAndActiveDocument() 方法
Revit 2013 中空闲事件被更新成拥有两种运行模式。空闲事件使用 Revit 2013 的默认模式时,Revit 在每次开始一个空闲会话时就会触发一次空闲事件。而空闲会话的启动条件分两种情况:
1. 用户正在操作 Revit 用户界面
鼠标停止移动一段时间之后;或者一个外部命令完成之后;2. 用户没有操作 Revit 用户界面
空闲会话的启动是随机的,很多时候 Revit 会很长时间内都不启动空闲会话(这就意味着当用户离开电脑时,无法保证这段时间被程序使用);
Revit 之前版本中的模式在 2013 中作为非默认模式(这就意味着我们之前的空闲事件代码需要更新为显示地指定为新版本的非默认模式)。非默认模式中空闲会话会一直保持开启状态的。这可以保证程序能使用用户离开电脑的这段时间。但是缺点是因为要一直维护空闲会话,所以会导致部分系统资源始终被占用,降低了性能。
Revit 2013 为空闲事件参数提供了方法 SetRaiseWithoutDelay(),用于控制空闲事件的运行模式。如果希望使用非默认模式,则必须在每次空闲事件被触发时,显示地调用 SetRaiseWithoutDelay() 方法。如果当次没有调用,则 Revit 将自动进入默认模式,直到下一次调用 SetRaiseWithoutDelay() 方法为止。
没有活动文档时的空闲事件
与 Revit 2012 不同,空闲事件在 Revit 没有活动文档时也会被触发了。
外部事件框架
空闲事件提供了一种 Revit 与外部异步过程的交互通道。Revit 是不允许外部过程直接调用其 API 的,但是外部过程可以向 Revit 发送请求,让其在下一次空闲事件时处理。一个典型应用就是在 Revit 插件中使用非模态对话框。不过由于非模态对话框在很多时候是没有用户交互的,所以导致空闲事件处理函数在这些时候不用做任何处理就直接返回了(译者注:不低碳啊!)。
Revit 2013 提供了一种更简单和高效的异步处理方式:外部事件框架。外部事件框架的处理有些类似默认模式时的空闲事件。不同的地方在于,外部事件只有在程序显示地触发时才会启动处理逻辑,而不像空闲事件一样经常出现处理函数无事可做的情况。
1. 实现一个继承自 IExternalEvent 接口的外部事件;
2. 调用 ExternalEvent.Create() 创建一个外部事件对象;
3. 当外部异步过程提交一个需要 Revit 处理的请求时,调用外部事件对象的 Raise() 方法;
4. Revit 在下一个可用的空闲周期中调用外部事件对象的 Execute() 方法;
外部事件框架对开发非模态对话框特别有帮助,因为可以避免会话无事可做的情况。
外部事件接口的定义:
public interface IExternalEventHandler
{
// 事件处理函数
void Execute( UIApplication app );
// 事件处理函数的名称
string GetName();
}
在一个程序中创建外部事件对象并使用一个线程来驱动它:
_event = ExternalEvent.Create( new WebcamEventHandler() );
Thread thread = new Thread( new ThreadStart( Run ) );
thread.Start();
以下是部分的线程执行函数。它使用了外部事件,通过调用其 Raise() 方法发送请求。在外部事件的 Execute() 方法被 Revit 调用时,程序就获得了一个安全的 Revit 上下文来调用 Revit API 了。
static void Run()
{
_running = true;
while( _running )
{
_data = new GreyscaleBitmapData( _width, _height, _url );
byte[] hash = _data.HashValue;
if( null == _lastHash || 0 != CompareBytes( hash, _lastHash ) )
{
_lastHash = hash;
_event.Raise();
}
Thread.Sleep( _intervalMs );
}
}
RevitWebcam 例程续篇
我使用新版的空闲事件和外部事件更新了 RevitWebcam 例程,你可以下载代码(RevitWebcam_2013.zip)比较历史版本和新版本的区别。
你还可以参考 SDK 例程 ModelessForm_ExternalEvent and ModelessForm_IdlingEvent。
在事件响应函数中调用 OpenAndActiveDocument() 方法
在 Revit 2012 中,OpenAndActiveDocument() 方法是无法在任何事件响应函数中被调用的。在 Revit 2013 中,这个限制基本被取消了。以下是几个典型的应用场景:
原始活动文档没有正在处理的事务(包括事务组)时,可以在外部事件处理函数中调用;
对于常规事件(例如:空闲事件、ApplicationInitialized 事件)处理函数来说,如果当前没有活动文档且事件没有嵌套在另外一个事件或者外部命令中时,可以调用;
通常情况下,相对于空闲事件处理函数而言,ApplicationInitialized 事件处理函数更适合用于打开第一个文档。