前段时间做Revit开发项目时遇到一个棘手的问题,我们都知道Revit运行环境是不允许多线程并发的,也就是说同一时刻只能有一个事务或操作运行,然后可以根据具体情况去触发不同的响应事件,如DocumentOpend,DocumentChanged等,那么问题是什么呢?问题是有时我们希望通过外部命令PostCommand调用Revit本身的命令,如调用绘制桥架命令,但是我们希望在此命令执行后去触发事件,后来经过测试发现PostCommand不会阻止线程的运行,而且还是外部命令运行完后才触发,那么我们就无法拿到PostCommand触发完成后的事件了,所以我们需要一个全局监控事件,来监控活动文档的改变,所以想到了DocumentChanged事件。但是发现在DocumentChanged事件里不能开始事务,也没用了,最后想到用Revit空闲事件和DocumentChanged事件相结合来做,首先我们在外部命令下注册这两个事件,由DocumentChanged事件触发空闲事件,在空闲事件里执行响应的事务,最后再注销两个事件,到此问题得到有效解决。当然除了Idling还可以用ExternalEvent来做配合!
本代码实现调用PostCommand命令放置一个门,然后触发相应的事件再删除此门,也可以扩展其他功能,本目的就是为了测试事务是否能成功开启
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.DB.Mechanical;
using System.Xml;
using Autodesk.Revit.UI.Events;
namespace HelloWorld
{
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class Test : IExternalCommand
{ //定义一个字段通过属性变化来触发空闲事件
public static Boolean IdleFlag = false;
//记录DocumentChanged事件发生改变的构件
IList listId = new List();
//定义一个全局UIApplication,用来注销指定事件
UIApplication uiApp = null;
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
uiApp = commandData.Application;
UIDocument uiDoc = uiApp.ActiveUIDocument;
Document Doc = uiDoc.Document;
uiApp.PostCommand(RevitCommandId.LookupPostableCommandId(PostableCommand.Door));
uiApp.Idling += new EventHandler(IdlingHandler);
uiApp.Application.DocumentChanged += new EventHandler(DocumentChangedForSomething);
return Result.Succeeded;
}
private void DocumentChangedForSomething(object sender,Autodesk.Revit.DB.Events.DocumentChangedEventArgs e)
{
listId.Clear();
ICollection < ElementId > collection= e.GetAddedElementIds();
listId.Add(collection.ElementAt(0));
IdleFlag = true;
uiApp.Application.DocumentChanged -= new EventHandler(DocumentChangedForSomething);
}
//Revit空闲事件
public void IdlingHandler(object sender, IdlingEventArgs args)
{
UIApplication uiapp = sender as UIApplication;
if (!IdleFlag)
{
return;
}
ExecuteIdlingHandler.Execute(uiapp, listId);
IdleFlag = false;
uiApp.Idling -= new EventHandler(IdlingHandler);
}
}
public static class ExecuteIdlingHandler
{
public static void Execute(UIApplication uiapp,IList listId)
{
UIDocument uidoc = uiapp.ActiveUIDocument;
if (uidoc != null)
{
Transaction ts = new Transaction(uidoc.Document, "delete");
ts.Start();
uidoc.Document.Delete(listId);
ts.Commit();
}
}
}
}