在我的应用程序的主窗体上,我有一个事件处理程序,它是从与 UI 不同的线程调用的,因为它是由硬件设备生成的事件。 同步。对于 GUI 线程,当事件被调用时,我执行 Form.BeginInvoke()。 然后该调用将在消息循环中排队。
当用户需要关闭表单时,在关闭之前我删除了事件的处理程序,但似乎仍然可以调用调用的调用。 然后,如果处理事件的例程使用了一些在调用它时不再可用的信息,我可能会遇到问题。
例如:
Private MyDevice as New SomeDevice()
Private MyGlobalVar as MyVarType
Public Sub OnDeviceEvent()
If InvokeRequired Then
BeginInvoke(Sub() OnDeviceEvent())
Return
End If
If MyGlobalVar.Field = 0 then
'do something
end if
End Sub
Public Sub PrepareToCloseForm()
'removes the handler of the event
RemoveHandler MyDevice.DeviceEvent, AddressOf OnDeviceEvent
MyGlobalVar = Nothing
End Sub
使用上面的代码,在运行PrepareToCloseForm()之后,有时我会在以下行中收到对象空错误:
If MyGlobalVar.Field = 0 then
我可以在使用变量之前进行 Null 检查,但由于我有许多其他事件,我想要一个更优雅的解决方案。 如何确保删除处理程序后不会发生 Invoked 调用?
在删除所有处理程序以处理待处理消息之前,我是否应该调用 DoEvents?
最佳答案
您遇到的问题是,如果您关闭该事物并将 MyGlobalVar 设置为 Nothing,即使 OnDeviceEvent 对此进行了检查,当您仍在尝试使用它时,它也可能随时变得什么都没有。为了解决这个问题,您可以在访问 MyGlobalVar 时放置一个 SyncLock
Private MyDevice as SomeDevice()
Private MyGlobalVar as MyVarType
Private SyncLockObject as New Object
Public Sub OnDeviceEvent()
If InvokeRequired Then
BeginInvoke(Sub() OnDeviceEvent())
Return
End If
SyncLock SyncLockObject
If MyGlobalVar IsNot Nothing Then
If MyGlobalVar.Field = 0 then
'do something
End If
End If
End SyncLock
End Sub
Public Sub PrepareToCloseForm()
'removes the handler of the event
RemoveHandler MyDevice.DeviceEvent, AddressOf OnDeviceEvent
SyncLock SyncLockObject
MyGlobalVar = Nothing
End SyncLock
End Sub
这样,当 OnDeviceEvent 正在访问 MyGlobalVar 时,您无法将其设置为空,并且当 PrepareToCloseForm 将其设置为 Nothing 时,OnDeviceEvent 无法访问它
关于.NET 删除事件处理程序并销毁调用的事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46961976/