把这套代码的关键点扒出来终于找到差异点了之前我漏看了它的交互逻辑它不是在NodeMouseDoubleClick里面直接跑CAD数据库写代码这是最核心的区别。事件流程拆解tv_Features_NodeMouseDoubleClickCancelActiveCommand();if(e.Node.Nodes.Count0)return;_bAddtrue;_SelectedCodee.Node.Name;SetFocus2ACAD();双击里面只做标记赋值完全没有任何CAD数据库、事务、图层、插入块代码。仅仅给两个成员变量打标记_bAddtrue、_SelectedCode赋值然后SetFocus。真正执行业务写库的入口tv_Features_MouseLeaveTreeView鼠标离开事件用户双击树节点之后鼠标会离开TreeView控件触发MouseLeave。此时才进入AddGxPoint才会执行using(DocumentLock lockDoc acDoc.LockDocument())才调用Editor.GetPoint()交互拾取点。为什么这套代码能跑通你的直接双击里面写绘制会eLockViolation关键1消息栈发生切换NodeMouseDoubleClick属于树控件鼠标双击消息Windows鼠标消息回调内部它里面只做简单变量赋值不碰CAD数据库不调用Editor交互很快返回这个Windows消息回调直接结束。鼠标挪开触发MouseLeave已经是下一轮Windows消息。重点并且在AddGxPoint内部第一行交互是Tools.Editor.GetPoint()Editor.GetPoint()这个API有一个非常关键的内部行为调用GetPoint时ZWCAD会让出当前消息栈切换进入CAD原生交互上下文内部自动处理消息泵释放CADUI持有的部分内部读锁。等到真正执行到后面DocumentLock、事务、图层创建、插入块的时候已经处于CAD交互模式内部锁环境就不一样了。这就是这套代码能跑的核心秘密不是靠CancelActiveCommand、不是靠SetFocus是靠GetPoint交互调用把执行上下文切进CAD内部消息循环。你原来的代码在双击回调内部直接一路执行到GetPoint整套业务逻辑全部跑在同一个双击消息栈里面还没释放旧的Windows消息上下文就去操作LayerTable写就会eLockViolation。参考工程双击消息只设置标记立刻退出下一轮消息(MouseLeave)进来再调用GetPointGetPoint会把环境切到CAD交互环境。关键2DocumentLockusing (DocumentLock lockDoc acDoc.LockDocument())在进入GetPoint之前就拿到文档锁防止文档被其他地方修改。关键3它的CCreateEnt.CreateLayer内部图层创建是在GetPoint拾取点完成之后才执行图层创建。此时已经进入CAD交互上下文CADUI的LayerTable读锁已经释放所以EnsureLayerExist可以正常执行不会eLockViolation。复现对比你的旧代码 vs 参考工程你的旧逻辑报错TreeView_DoubleClick() { //同一个Windows消息栈内 打开事务 → 创建图层(写LayerTable) → GetPoint拾取点 → 插入块 }图层写操作发生在GetPoint之前还没进入CAD交互上下文LayerTable被CADUI占用eLockViolation。参考工程逻辑正常运行TreeView_DoubleClick() { _bAddtrue; _SelectedCodexxx; //仅内存变量赋值直接return本消息结束 } //鼠标离开树下一轮Windows消息触发MouseLeave TreeView_MouseLeave() { AddGxPoint(); { using(DocumentLock) { //第一步先调用Editor.GetPoint() // GetPoint内部切换CAD消息泵释放UI读锁 // 拾取点完成之后才去执行 CreateLayer 创建图层插入块 } } }图层创建、写LayerTable发生在GetPoint之后GetPoint已经把执行环境切进CAD交互循环此时LayerTable写锁可以正常拿到。两个可行方案给你选择不用上SendStringToExecute命令方案A模仿参考工程思路改动小贴合现有代码TreeView双击事件不要直接调用OnStartDrawElement。只做两件事保存选中的codeDefine到实例成员变量设置一个标记_isDrawPending true调用CancelActiveCommand()、SetFocus2ACAD()双击事件直接return不要做任何CAD数据库操作。增加一个触发时机可以学它用MouseLeave或者用Application.Idle事件。在这个后续触发的函数里面再调用OnStartDrawElement(codeDefine)。在OnStartDrawElement内部先using(DocumentLock lockDoc db.Document.LockDocument())第一行CAD交互先执行ed.GetPoint()拾取点✅拾取点完成之后再做图层EnsureLayerExist、导入块、插入块。核心改动顺序先GetPoint后创建图层调换你现有代码的执行顺序你原来代码是先创建图层再GetPoint顺序反了所以报错。方案B继续SendStringToExecute直接进入CommandMethod上下文天然正确。重点提醒参考工程不是魔法不是DocumentLock/SetFocus/CancelActiveCommand单独修好锁真正起决定性的两点双击消息快速返回业务逻辑放到下一轮消息周期先调用Editor.GetPoint利用GetPoint内部CAD消息泵切换上下文之后再执行图层表写操作。你原来代码顺序创建图层写LayerTable报错GetPoint拾取点参考代码顺序GetPoint拾取点切换CAD交互上下文创建图层写LayerTable正常顺序调换就是关键。MouseLeave这个方案有小体验瑕疵鼠标稍微一晃离开树面板就触发绘制产品实际开发更推荐Application.Idle事件而不是MouseLeave。如果你需要我可以给你只改执行顺序的思路不写完整大段代码。
阅读完成 · 觉得有帮助?