.NET删除事件处理程序并销毁调用的事件

时间:2017-10-26 19:05:08

标签: .net vb.net winforms

在我的应用程序的主窗体上,我有一个事件处理程序,它是从与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吗?

1 个答案:

答案 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时无法访问它