AutoCAD C# API中CommandWillStart事件无响应问题求助
AutoCAD C#二次开发:CommandWillStart事件无响应问题排查
问题场景
在AutoCAD C#二次开发中,试图通过CommandWillStart事件监听命令行输入:当输入的命令与JSON配置中的TPX/TP1匹配时,调用GetDistanceBetweenTwoPoints()方法,且不使用[CommandMethod]特性注册命令,但目前事件处理无响应。
现有代码与配置
C#代码
using System; using System.Collections.Generic; using System.IO; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Runtime; using Newtonsoft.Json; namespace Autocad_SetShortcutKey_005 { public class CommandConfig { public string Name { get; set; } public string Subname { get; set; } public string Method { get; set; } } public class CommandMappings { public List<CommandConfig> Commands { get; set; } } public class SetShortcutKeyClass : IExtensionApplication { private Dictionary<string, Action> commandDictionary; Document doc; Editor ed; public SetShortcutKeyClass() { doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; ed = doc.Editor; } public void Initialize() { // Load commands from JSON LoadCommands(); // Register for the CommandWillStart event doc.CommandWillStart += new CommandEventHandler(OnCommandWillStart); } public void Terminate() { // Unsubscribe from the CommandWillStart event doc.CommandWillStart += new CommandEventHandler(OnCommandWillStart); } private void LoadCommands() { commandDictionary = new Dictionary<string, Action>(); // Read JSON file string jsonFilePath = "commands.json"; if (File.Exists(jsonFilePath)) { string jsonContent = File.ReadAllText(jsonFilePath); var commandMappings = JsonConvert.DeserializeObject<CommandMappings>(jsonContent); foreach (var commandConfig in commandMappings.Commands) { if (commandConfig.Method == nameof(GetDistanceBetweenTwoPoints)) { commandDictionary[commandConfig.Name.ToUpper()] = GetDistanceBetweenTwoPoints; commandDictionary[commandConfig.Subname.ToUpper()] = GetDistanceBetweenTwoPoints; } } } else { ed.WriteMessage("\n No Json file."); return; } } private void OnCommandWillStart(object sender, CommandEventArgs e) { string commandName = e.GlobalCommandName.ToUpper(); if (commandDictionary.ContainsKey(commandName)) { // Execute the custom method commandDictionary[commandName].Invoke(); return; } } public void GetDistanceBetweenTwoPoints() { PromptPointOptions ppo1 = new PromptPointOptions("\nPick the first point: "); PromptPointResult ppr1 = ed.GetPoint(ppo1); if (ppr1.Status != PromptStatus.OK) return; PromptPointOptions ppo2 = new PromptPointOptions("\nPick the second point: "); PromptPointResult ppr2 = ed.GetPoint(ppo2); if (ppr2.Status != PromptStatus.OK) return; double distance = ppr1.Value.DistanceTo(ppr2.Value); Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog($"\nDistance between points: {distance}"); } } }
commands.json配置
{ "commands": [ { "name": "TPX", "subname": "TP1", "method": "GetDistanceBetweenTwoPoints" } ] }
问题排查与修复方案
1. 文档对象初始化时机错误
原代码在构造函数中获取MdiActiveDocument,此时AutoCAD扩展应用刚启动,可能还没有激活的文档,导致doc为null,后续事件绑定完全失效。
- 修复:将文档获取逻辑移到
Initialize()方法内,同时增加文档未打开时的兼容处理:
public void Initialize() { doc = Application.DocumentManager.MdiActiveDocument; if (doc == null) { Application.DocumentManager.DocumentCreated += OnDocumentCreated; return; } ed = doc.Editor; LoadCommands(); doc.CommandWillStart += OnCommandWillStart; } private void OnDocumentCreated(object sender, DocumentCollectionEventArgs e) { doc = e.Document; ed = doc.Editor; LoadCommands(); doc.CommandWillStart += OnCommandWillStart; Application.DocumentManager.DocumentCreated -= OnDocumentCreated; }
2. 事件注销逻辑错误
原Terminate()方法中用+=再次订阅事件,正确的注销方式应该是-=,同时需要保留事件处理器的引用避免匿名委托无法注销:
private CommandEventHandler _commandHandler; public void Initialize() { // ...其他代码 _commandHandler = new CommandEventHandler(OnCommandWillStart); doc.CommandWillStart += _commandHandler; } public void Terminate() { if (doc != null && _commandHandler != null) { doc.CommandWillStart -= _commandHandler; } Application.DocumentManager.DocumentCreated -= OnDocumentCreated; }
3. JSON文件路径问题
原代码使用相对路径"commands.json",AutoCAD的工作目录默认不是程序集所在目录,会导致找不到配置文件。
- 修复:通过程序集路径拼接绝对路径:
string assemblyPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); string jsonFilePath = Path.Combine(assemblyPath, "commands.json");
4. CommandWillStart事件的局限性
CommandWillStart仅触发已注册的合法命令(AutoCAD原生命令或通过[CommandMethod]注册的自定义命令),未注册的TPX/TP1会被AutoCAD直接判定为未知命令,不会触发该事件。
- 修复:新增监听
Editor.CommandInput事件,直接捕获命令行输入并拦截未注册命令:
public void Initialize() { // ...其他代码 doc.Editor.CommandInput += OnCommandInput; } private void OnCommandInput(object sender, CommandInputEventArgs e) { string input = e.Input.ToUpper().Trim(); if (commandDictionary.ContainsKey(input)) { e.Handled = true; e.AppendCommand = false; commandDictionary[input].Invoke(); } } public void Terminate() { // ...其他代码 doc.Editor.CommandInput -= OnCommandInput; }
内容的提问来源于stack exchange,提问作者Yongtae Kim
相关产品推荐
相关产品推荐

