VB.NET自定义命令场景点击按钮后OnMouseMove不触发问题
问题根因
- 核心是
BaseStepCommand步骤命令的状态流转异常:先弹出命令窗体、再点击绘图区选位置时,焦点切到绘图视图会触发命令框架自动将当前命令置为*挂起(Suspend)*状态,选点完成后未主动触发恢复逻辑,命令长期停在挂起态,无法接收OnMouseMove事件。 - 窗体实例声明错误:
ofrmTestTool被声明为Shared静态字段且提前初始化,OnStart中又重复实例化,不同生命周期调用的窗体实例不一致,会打乱事件路由。 - 跨UI硬调用事件方法:
OnMouseDown中直接调用窗体按钮的点击处理函数,绕过了命令框架的状态校验和UI线程调度,直接打断鼠标事件监听链路。 - 场景1运行正常是因为选点发生在命令启动前,命令启动后从未被挂起,事件链路完整,鼠标事件可以正常派发。
修复方案
- 移除
ofrmTestTool的Shared修饰和提前初始化逻辑,避免多实例混乱。 - 增加布尔标记位,控制鼠标移动打印的开启状态,不要把打印逻辑直接绑死在按钮点击事件上。
- 补全
OnMouseMove重写逻辑,仅在标记位开启时执行打印。 - 选点完成(
OnMouseDown逻辑执行完)后主动调用基类Resume()方法,让命令回到激活状态,恢复鼠标事件监听。 - 弹出窗体时绑定当前命令实例到窗体
Tag属性,指定主窗口为窗体所有者,避免焦点异常切换导致的命令挂起。 - 抽离按钮点击的公共业务逻辑,禁止跨UI硬调用事件处理方法。
修复后代码
Partial Public Class frmTestTool Inherits Form ''' <summary> ''' 抽离按钮点击公共逻辑,供外部命令复用 ''' </summary> Public Sub EnableMousePrint() WriteMessage("PlaceText功能已激活,移动鼠标将持续输出文本") End Sub Private Sub btnPlaceText_Click_1(sender As Object, e As EventArgs) Handles btnPlaceText.Click EnableMousePrint() ' 同步更新命令实例的打印标记位 If Tag IsNot Nothing AndAlso TypeOf Tag Is TextWizard Then DirectCast(Tag, TextWizard).SetPrintStatus(True) End If End Sub End Class Public Class TextWizard Inherits BaseStepCommand ' 命令持有的窗体实例,不使用Static避免多实例冲突 Private _toolForm As frmTestTool ' 鼠标移动打印的开关标记 Private _mousePrintEnabled As Boolean = False Public Overrides Sub OnSuspend() MyBase.OnSuspend() End Sub Public Overrides Sub OnResume() MyBase.OnResume() End Sub Public Overrides Sub OnStart(ByVal commandID As Integer, ByVal argument As Object) MyBase.OnStart(commandID, argument) Try m_running = True m_oTxnMgr = ClientServiceProvider.TransactionMgr _toolForm = New frmTestTool() ' 绑定当前命令实例到窗体,方便双向通信 _toolForm.Tag = Me ' 指定主窗口为所有者,避免焦点切换导致命令异常挂起 _toolForm.Show(ClientServiceProvider.MainWindow) _mousePrintEnabled = False Catch commonException As CmnException ClientServiceProvider.ErrHandler.ReportError(ErrorHandler.ErrorLevel.Critical, MethodBase.GetCurrentMethod().Name, commonException, commandFailed) End Try End Sub ''' <summary> ''' 公开方法供窗体调用,更新打印开关状态 ''' </summary> Public Sub SetPrintStatus(enabled As Boolean) _mousePrintEnabled = enabled End Sub Protected Overrides Sub OnMouseDown(ByVal view As GraphicView, ByVal e As GraphicViewManager.GraphicViewEventArgs, ByVal position As Position) MyBase.OnMouseDown(view, e, position) ' 选点完成后主动恢复命令状态,重连鼠标事件监听 MyBase.Resume() ' 复用公共逻辑,不硬调窗体按钮事件 _toolForm.EnableMousePrint() _mousePrintEnabled = True End Sub ''' <summary> ''' 重写鼠标移动事件,实现打印逻辑 ''' </summary> Protected Overrides Sub OnMouseMove(ByVal view As GraphicView, ByVal e As GraphicViewManager.GraphicViewEventArgs, ByVal position As Position) MyBase.OnMouseMove(view, e, position) If _mousePrintEnabled Then WriteMessage("Hello World") End If End Sub End Class
验证结果
两种操作顺序下,点击PlaceText按钮或完成选点后,移动鼠标均可正常输出"Hello World",无事件丢失问题;移除静态实例后也解决了窗体复用导致的内存泄漏、状态残留问题。
内容的提问来源于stack exchange,提问作者Rjay
相关产品推荐
相关产品推荐

