在我的应用程序的主窗体上,我有一个事件处理程序,它是从与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()之后,有时我会在以下行中得到一个对象Null错误:
If MyGlobalVar.Field = 0 then
在使用变量之前我可以进行Null检查,但由于我还有很多其他事件,我想要一个更优雅的解决方案。 我如何确保在删除处理程序后不会发生调用调用?
在删除所有处理程序以处理待处理消息之前,我应该调用DoEvent吗?
答案 0 :(得分:3)
你遇到的问题是,如果你关闭了这个东西并将MyGlobalVar设置为Nothing,即使OnDeviceEvent检查了它,当你还在尝试使用它时,它可能随时变成什么都没有。要解决这个问题,您可以将SyncLock放在MyGlobalVar的访问权限
上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设置为空而你无法访问它OnDeviceEvent在PrepareToCloseForm将其设置为Nothing时无法访问它