控制ElementTypeDuplicated事件后,如何覆盖IDD_SYMBOL_ATTRIB对话框结果?
解决Revit中覆盖ElementTypeDuplicated事件对应对话框结果的问题
我明白你遇到的痛点了——ElementTypeDuplicated事件确实是在用户输入新名称并确认对话框后才触发的,这时候事件参数里的信息已经是最终结果,直接修改参数自然不会生效。要实现你想要的效果,得换个思路:在对话框弹出时就介入控制,而不是等事件触发后再补救。
下面给你两种可行的方案,你可以根据需求选择:
方案1:拦截对话框并修改输入内容
利用Revit API的DialogBoxShowing事件,监听ID为IDD_SYMBOL_ATTRIB的对话框,在它显示时直接修改输入框里的名称,这样用户确认后就会用你指定的名称完成复制。
示例代码
首先订阅DialogBoxShowing事件:
private ControlledApplication _controlledApp; public void Initialize() { _controlledApp = new ControlledApplication(); _controlledApp.DialogBoxShowing += OnDialogBoxShowing; }
然后编写事件处理方法(需要引用System.Windows.Automation程序集,用来操作对话框控件):
using System.Windows.Automation; private void OnDialogBoxShowing(object sender, DialogBoxShowingEventArgs e) { // 确认当前弹出的是目标对话框 if (e.DialogId.Equals("IDD_SYMBOL_ATTRIB", StringComparison.OrdinalIgnoreCase)) { // 通过对话框句柄获取自动化元素 var dialogElement = AutomationElement.FromHandle(e.DialogHandle); if (dialogElement == null) return; // 找到名称输入框(注意:不同Revit版本的控件Automation ID可能有差异,需用Inspect工具确认) var nameInput = dialogElement.FindFirst( TreeScope.Descendants, new PropertyCondition(AutomationElement.AutomationIdProperty, "txtName")); // 示例ID,实际需验证 if (nameInput != null && nameInput.Current.IsEnabled) { // 设置输入框的值为你想要的名称 var valuePattern = nameInput.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern; valuePattern?.SetValue("你的自定义类型名称"); } } }
方案2:取消默认对话框,手动复制ElementType
如果不想依赖UI自动化,也可以直接取消默认的对话框,自己调用API完成复制流程,完全控制新类型的名称。
示例代码
先订阅SelectionChanged事件获取用户选中的ElementType,再在DialogBoxShowing里处理:
private ElementType _pendingDuplicateType; // 提前保存用户选中的ElementType public void Initialize() { _controlledApp.SelectionChanged += OnSelectionChanged; _controlledApp.DialogBoxShowing += OnDialogBoxShowing; } private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) { // 保存用户选中的第一个ElementType _pendingDuplicateType = e.GetSelectedElements() .FirstOrDefault(el => el is ElementType) as ElementType; } private void OnDialogBoxShowing(object sender, DialogBoxShowingEventArgs e) { if (e.DialogId.Equals("IDD_SYMBOL_ATTRIB", StringComparison.OrdinalIgnoreCase) && _pendingDuplicateType != null) { // 取消默认对话框 e.Cancel = true; // 手动启动事务复制类型 using (var trans = new Transaction(_pendingDuplicateType.Document, "自定义复制类型")) { trans.Start(); // 直接指定新名称 var newTypeId = _pendingDuplicateType.Duplicate("你的自定义类型名称"); trans.Commit(); // 可选:选中新生成的类型 _pendingDuplicateType.Document.SelectElement(newTypeId); } // 清空临时变量 _pendingDuplicateType = null; } }
备选方案:事后修改类型名称(不推荐)
如果以上两种方案都不适用,你也可以在ElementTypeDuplicated事件触发后,修改新生成类型的名称,但这样用户会先看到自己输入的名称,然后被替换,体验不够流畅:
private void OnElementTypeDuplicated(object sender, ElementTypeDuplicatedEventArgs e) { var doc = (sender as ControlledApplication).ActiveUIDocument?.Document; if (doc == null) return; var newTypeId = e.GetNewTypeId(); using (var trans = new Transaction(doc, "重命名复制类型")) { trans.Start(); var newType = doc.GetElement(newTypeId) as ElementType; if (newType != null) { newType.Name = "你的自定义类型名称"; } trans.Commit(); } }
关键说明
ElementTypeDuplicated是事后通知事件:它在类型已经复制完成后触发,所以此时修改事件参数无法改变已经完成的操作。- 优先选择方案1或2:这两种方案都是在对话框显示阶段介入,能完全控制最终的类型名称,用户体验更好。
内容的提问来源于stack exchange,提问作者Tiago Cerqueira
相关产品推荐
相关产品推荐

