Visual Basic - timer keeps looping - vb.net

I'm new to the programming world.
I'm trying to make a simple software which will go through 5-6 forms (showing the progress bar as a picture) and on each form display progress as a picture while some other code is being run in the background. I've written my code and it just keeps looping the application for some reason and I don't know how to stop it from looping.
As I said, I'm new to visual basic and programming world, so please just go easy on me, thanks!
I just need help with stopping the timer after the HandleTimerTick() happens. I don't know how to call the timer to stop, from the previous sub or something. So, I just need a command to stop t.Tick once HandleTimerTick from the second sub starts.
If you have any simpler command to stop the code from executing for the number of seconds feel free to share. Thanks in advance!
Private Sub Delay1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim t As Timer = New Timer()
t.Interval = 2000
AddHandler t.Tick, AddressOf HandleTimerTick
t.Start()
End Sub
Private Sub HandleTimerTick()
Dim SecondForm As New Delay2
SecondForm.Show()
Me.Close()
End Sub

Use the proper signature for the Event handler In this way you get a reference to the Timer that trigger the event handler and you can stop it
Private Sub HandleTimerTick(sender As Object, e As EventArgs)
... your code to handle the event
' Stop the timer
Dim t As System.Windows.Forms.Timer
t = DirectCast(sender, System.Windows.Forms.Timer)
t.Stop
End Sub

Related

WinForms.IllegalCrossThreadCall with filewatcher

I'm new to Visual Basic and overall kind of new to coding in general.
Currently I work on a program which uses a filewatcher. But If I try this:
Public Class Form1
Private WithEvents fsw As IO.FileSystemWatcher
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
fsw = New IO.FileSystemWatcher("PATH")
fsw.EnableRaisingEvents = True
' fsw.Filter = "*.settings"
End Sub
Private Sub GetSettingsFromFile()
Some Code
More Code
CheckBox1.Checked = True
End Sub
Private Sub fsw_Changed(sender As Object, e As FileSystemEventArgs) Handles fsw.Changed
fsw.EnableRaisingEvents = False 'this is set because the file is changed many times in rapid succesion so I need to stop the Filewatcher from going of 200x (anyone has a better idea to do this?)
Threading.Thread.Sleep(100)
GetSettingsFromFile()
fsw.EnableRaisingEvents = True 'enabling it again
End Sub
End Class
But when I do this (trying to change anyhting in the form) I get this error:
System.InvalidOperationException (WinForms.IllegalCrossThreadCall)
It wont stop the program from working, but I want to understand what is wrong here and why the debugger is throwing this at me
regards
The event is being raised on a secondary thread. Any changes to the UI must be made on the UI thread. You need to marshal a method call to the UI thread and update the UI there. Lots of information around on how to do that. Here's an example:
Private Sub UpdateCheckBox1(checked As Boolean)
If CheckBox1.InvokeRequired Then
'We are on a secondary thread so marshal a method call to the UI thread.
CheckBox1.Invoke(New Action(Of Boolean)(AddressOf UpdateCheckBox1), checked)
Else
'We are on the UI thread so update the control.
CheckBox1.Checked = checked
End If
End Sub
Now you simply call that method wherever you are and whatever thread you're on. If you're already on the UI thread then the control will just be updated. If you're on a secondary thread then the method will invoke itself a second time, this time on the UI thread, and the control will be updated in that second invocation.

winform and session timeout

I have a vb.net winform and I want to know how to add sort of like a session time out to it. For example, I have a varialbe set to 10 min, within that 10 min, if there is no activity (no mouse/no keyboard interaction), I would like to log the user out. Can anyone shine some light on this subject on how to make this work?
First question, why do you want to do in a winform. Such things we generally use in web forms. But even you want to use such things in WinForms you need to use Timer Class.
Whenever you encounter activity, you can just reset the timer by calling Stop then immediately calling Start. Place whatever code you'd like in the Timer's Tick event (assuming this is a System.Windows.Forms.Timer) and you'll be all set.
I'd suggest you use the event Application.Idle.
No need to P/Invoke.
Public Class Form1
Private WithEvents _timer As Timer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' 10 seconds for testing
Me._timer = New Timer With {.Interval = 10000, .Enabled = True}
AddHandler Application.Idle, AddressOf Me.Application_Idle
End Sub
Private Sub Application_Idle(sender As Object, e As EventArgs)
Me._timer.Stop()
Me._timer.Start()
End Sub
Private Sub Timer_Tick(sender As Object, e As EventArgs) Handles _timer.Tick
Me._timer.Stop()
RemoveHandler Application.Idle, AddressOf Me.Application_Idle
' Do something to log the user out
Me.Close()
End Sub
End Class
If you are looking for a way to detect input outside your application Amit's suggestion will not work.
See Detecting idle users in Winforms if that is the case. Calling GetLastInputInfo() and checking the last input value should give you something to go off.
If you are not worried about the user leaving your application, and getting logged out after not using it, use Amit's way of resetting a timer on the input event.

Timer does not work

I try to run a timer from my winform application. For some reason the function that should run on the timer's tick (IsTimeOffsetValid) is not called nor stopped on break point, and basically nothing happens. I attached a code sample below.
I appreciate the help.
Module Module1
Sub main()
Dim OutputForm As New Form17
Application.Run(OutputForm)
End Sub
End Module
Public Class Form17
Private TimerServerOffset As New System.Timers.Timer
Private Sub Form17_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
AddHandler TimerServerOffset.Elapsed, New System.Timers.ElapsedEventHandler(AddressOf IsTimeOffsetValid)
TimerServerOffset.Interval = 1
TimerServerOffset.Start()
End Sub
Private Sub IsTimeOffsetValid()
MsgBox("IsTimeOffsetValid")
End Sub
End Class
Apart from errors in the code that you posted there are other issues with the design.
Read this question: System.Timers.Timer vs System.Threading.Timer
The callback is called on a worker thread (not the UI thread) so displaying a message box could be a big problem.
then switch to a more fitting timer. If all you want to do is validate the inputs every second, switch to the System.Windows.Forms.Timer. The tick handler runs on the UI thread so you can change the UI in the handler.
Then consider changing the interval a message box popping up every millisecond is not possible and not user friendly.
Finally, I would suggest NOT using a timer for this: just handle changes to the input fields and respond to changed inputs or use the standard validation events of the WinForms controls. This is much cheaper (on the CPU) and will not mess with the focus.

Timer can be stopped in backgroundworker, but can't be started

Recently, I've been working with a system.form.timer in the UI thread. I've have noticed that while I can stop a timer on a background thread, I cannot start it back up unless I use BeginInvoke even though I do not receive a cross-threading exception. On a system.timers.timer however it seems that I can stop and start it from the background thread created by the timer. Why is this? Is a system.form.timer allowed to be stopped, but not enabled from a background thread? This seems a bit odd to me.
System.Form.Timer Code
DOESN'T WORK
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim BW As BackgroundWorker = New BackgroundWorker
AddHandler BW.DoWork, AddressOf CheckTimer
BW.RunWorkerAsync()
End Sub
Private Sub CheckTimer()
Timer1.Stop()
Timer1.Start()
MsgBox("Stopped and Started Timer")
End Sub
WORKS
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim BW As BackgroundWorker = New BackgroundWorker
AddHandler BW.DoWork, AddressOf CheckTimer
BW.RunWorkerAsync()
End Sub
Private Sub CheckTimer()
Timer1.Stop()
Me.BeginInvoke(New TimerStart(AddressOf TimerStartFunction))
MsgBox("Stopped and Started Timer")
End Sub
Private Delegate Sub TimerStart()
Private Sub TimerStartFunction()
Timer1.Start()
End Sub
System.Timers.Timer Code
WORKS
Dim aTimer As System.Timers.Timer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
aTimer = New System.Timers.Timer(5000)
AddHandler aTimer.Elapsed, AddressOf OnTimedEvent
aTimer.Enabled = True
End Sub
Sub OnTimedEvent()
aTimer.Stop()
aTimer.Start()
MsgBox("Stopped and Started Timer")
End Sub
The Winforms Timer class is somewhat thread-safe, not enough to keep you happy. When you call its Start() method then it creates a hidden window that turns WM_TIMER messages into Tick events.
When you do this on a worker thread then you tend to have a problem, these WM_TIMER messages are only dispatched when the thread runs a message loop. Worker threads don't normally do this, they don't call Application.Run(). So the timer just won't tick.
Calling the Stop() method is otherwise okay, it knows how to find that hidden window back even through the code runs on the wrong thread. The workaround you found with BeginInvoke() works because it now correctly calls Start() on the UI thread and gets the hidden window created with the correct owner thread, one that pumps. System.Timers.Timer doesn't have this problem, it doesn't rely on WM_TIMER to tick but uses a System.Threading.Timer instead. Which is supported by a dedicated worker thread managed by the CLR. Do note that this timer is pretty dangerous. Calling MsgBox() on a worker thread is fundamentally wrong, for one. High odds that the user never sees it since it will be behind a UI window.
That explains it, I can't otherwise offer better advice since I can't see what you are really trying to do. Be careful, you are playing with fire.

[VB.NET]abort code/task after a time

Can i set time limit for a task or a code? for example if i want to show message boxes for 10 seconds and then stop or change the the message body ?
Yes, check out timers. There are three different kinds of timers:
System.Timers.Timer
System.Threading.Timer
System.Windows.Forms.Timer
Which one will work best for you will depend entirely on your specific situation. Given the limited information you provided, I suspect that the easiest way to do what you need to do is to create your own message-box-like form and place a System.Windows.Forms.Timer component on the form (you can find it in the form designer's tool box). Have the form start the timer in its own Shown event. And then show the form using the ShowDialog method.
You can start a Thread and abort it when you want:
Dim t1 As New Threading.Thread(AddressOf MyMethod)
t1.Start()
Timer1.Start()
Private Sub MyMethod()
' Do what you want
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Timer1.Enabled = False
t1.Abort()
End Sub