0

I have a WPF application written in VB.net. I'm trying to access a form control during a timer event, but the code is throwing an exception. Below is my code:

Public WithEvents attendanceFetchTimer As System.Timers.Timer

Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
    attendanceFetchTimer = New System.Timers.Timer(cfgAttFetchInterval)
    AddHandler attendanceFetchTimer.Elapsed, New ElapsedEventHandler(AddressOf getAllDeviceAttendance)
    attendanceFetchTimer.Enabled = True
End Sub

Private Sub getAllDeviceAttendance(ByVal sender As Object, ByVal e As ElapsedEventArgs) Handles attendanceFetchTimer.Elapsed
    If(checkBox1.isChecked) Then 
        'Do something here change the textbox value
        txtStatus1.Text = "Getting Attendance Data Done!"
    End If

End Sub

The problem is that when I debug, the checkBox1.isChecked is showing this message:

"Cannot evaluate expression because we are stopped in a place where garbage collection is impossible, possibly because the code of the current method may be optimized."

and in the console this error message is displayed:

"A first chance exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll"

The same problem happens when I try to change the text of txtStatus1.

Mark
  • 8,140
  • 1
  • 14
  • 29
vincent
  • 243
  • 1
  • 7
  • 17
  • System.Timers.Timer is a very poisonous class, only ever use it when you understand *exactly* what it does. And what you are doing it not legal, you cannot access UI components in the Elapsed event handler. Use a DispatcherTimer instead. – Hans Passant Aug 10 '15 at 17:49
  • I have closed your question as a duplicate. Please see my answer in the linked question to understand how to properly work with WPF in a multi threaded scenario, using DataBinding. If the linked answer doesn't satisfy your needs, please feel free to post a new question. – Federico Berasategui Aug 10 '15 at 20:07

1 Answers1

0

The System.InvalidOperationException looks like it is caused by cross-thread access to a UI component. The System.Timers.Timer by default fires the Elapsed event on a thread pool thread. Using DispatcherTimer and the Tick event will get things on the right thread for accessing the UI in WPF.

It also looks like you may have duplicate event handlers wired up, since you have both WithEvents/Handles and AddHandler, but I'm not entirely sure how that works in WPF. You probably want something like (untested):

Private attendanceFetchTimer As System.Windows.Threading.DispatcherTimer

Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
    attendanceFetchTimer = New System.Windows.Threading.DispatcherTimer()
    AddHandler attendanceFetchTimer.Tick, AddressOf getAllDeviceAttendance
    attendanceFetchTimer.Interval = TimeSpan.FromMilliseconds(cfgAttFetchInterval)
    attendanceFetchTimer.Start()
End Sub

Private Sub getAllDeviceAttendance(ByVal sender As Object, ByVal e As EventArgs)
    If(checkBox1.isChecked) Then 
        'Do something here change the textbox value
        txtStatus1.Text = "Getting Attendance Data Done!"
    End If
End Sub
Mark
  • 8,140
  • 1
  • 14
  • 29