如何让ExternalEvent执行完成后再运行后续任务?
解决Revit ExternalEvent执行顺序问题
Revit的ExternalEvent.Raise()并非同步执行事件处理器,它只是将外部事件加入Revit的事件队列,当前UI线程会继续执行后续代码,因此Othertasks()会先于RunTestFunction()完成。以下是两种实现需求的方案:
方案一:将后续任务移至ExternalEvent处理器中
直接把需要延后执行的Othertasks()放到事件处理器的Execute方法内,在RunTestFunction()完成后调用,逻辑简单直接。
修改后的代码
首先调整事件处理器类,通过构造函数传入后续执行的方法:
public class ExternalEventhandle: IExternalEventHandler { private readonly Action _postExecuteAction; // 构造函数接收后续要执行的任务 public ExternalEventhandle(Action postAction) { _postExecuteAction = postAction; } public void Execute(UIApplication app) { UIDocument UIdoc = app.ActiveUIDocument; Document doc = UIdoc.Document; // 优先执行目标任务 RunTestFunction(); // 任务完成后执行后续操作 _postExecuteAction?.Invoke(); } public string GetName() { return "BtnClickedExternalEvent"; // 返回有意义的事件名称,避免空字符串 } }
然后初始化外部事件并修改按钮点击方法:
// 类成员变量,提前初始化外部事件 private ExternalEvent _btnClickedEvent; // 在类构造函数或初始化方法中创建事件实例 public YourClassConstructor() { _btnClickedEvent = ExternalEvent.Create(new ExternalEventhandle(Othertasks)); } private void BtnClicked() { _btnClickedEvent.Raise(); }
方案二:使用TaskCompletionSource异步等待(适合保留原方法结构)
如果Othertasks()需要访问按钮点击方法中的局部变量,或不想改动原方法结构,可以用TaskCompletionSource实现异步等待,避免阻塞UI线程。
修改后的代码
调整事件处理器类,添加TaskCompletionSource用于通知任务完成:
public class ExternalEventhandle: IExternalEventHandler { public TaskCompletionSource<bool> CompletionSource { get; set; } public void Execute(UIApplication app) { try { UIDocument UIdoc = app.ActiveUIDocument; Document doc = UIdoc.Document; RunTestFunction(); // 标记任务完成 CompletionSource?.SetResult(true); } catch (Exception ex) { // 捕获异常并传递 CompletionSource?.SetException(ex); } } public string GetName() { return "BtnClickedExternalEvent"; } }
将按钮点击方法改为异步方法,等待外部事件完成后再执行后续任务:
private async void BtnClicked() { var tcs = new TaskCompletionSource<bool>(); // 初始化事件处理器并绑定CompletionSource var eventHandler = new ExternalEventhandle { CompletionSource = tcs }; var btnClickedEvent = ExternalEvent.Create(eventHandler); btnClickedEvent.Raise(); // 异步等待外部事件执行完成 await tcs.Task; // 执行后续任务 Othertasks(); }
注意事项
GetName()方法不要返回空字符串,提供有意义的名称有助于调试Revit事件。- 方案一中建议提前初始化
ExternalEvent实例,避免每次点击都重复创建,提升性能。 - 方案二中使用
async void是因为UI事件处理方法的特殊性,若为普通方法建议返回Task。
内容的提问来源于stack exchange,提问作者Dinesh
相关产品推荐
相关产品推荐

