VB.NET - Interrupt form loop and end form - vb.net

I have a form that goes through an endless loop and processes data. When I click a button that "closes" the form, the form keeps processing even though it is closed. I want the form to completely end and exit out of its loop statement, and then open a new form.
Here is the code I am using to close the form
frmMain.Close()
frmMain.Dispose()
Note: I am not using threads it's just a simple VB.NET application. I am not closing the main startup form.

The "correct" way of doing this is with background worker threads really. But this will also work without the need of background worker threads.
Declare a variable in the form class.
Private keepLoopAlive As Boolean
Then write your processing loop to be something like:
keepLoopAlive = True
Do While keepLoopAlive
(your code that loops here)
DoEvents
Loop
Then on your Close event do:
keepLoopAlive = False
Me.Close()
This will cause the loop to end first chance it gets, and your form should close.
Please note I've written this code from memory and not in an IDE so there may be typos.

I am not a .NET developer so this may not be valid, but if I were performing an infinite loop, I would be checking each time I started that the loop was still valid with some sort of boolean value, and if it failed, drop out of the loop.
When you close the form, set the boolean value false and it will drop out, and you can either have an outer loop that waits and restarts the loop, or you can restart the entire function some other time.

Related

Multithreading Webbrowsers

I am currently making a vb program that i plan to make very big. I have a decent knowledge of visual basic but today i came across something i do not understand. Because of the huge size of my program , i decided to try and keep the program as organized as possible by putting specific subs in modules. These subs consist of httprequest , webbrowsers(control), webclients and alot of loops. In order to prevent these subs from lagging my main application i thread them using threading.thread and i start them from my main form. But this leads to two problems.
Problem 1: The threads cannot in any way interact with the main form.
Once the a httprequest or webclient collects the information from my desired website, i am trying to make it add the info to a listbox in my main form, So what i did is it typed
Msgbox("Info Sent")
form1.listbox1.items.add(String)
The first messagebox will show but although the code right under it runs, nothing is added to the first forms listbox.I am not using delegates to transfer the information, instead, although its not a good habit, i am using checkforillegalcrossovers.
Problem 2: Threading with a webbrowser.
Threading with a webbrowser using threading.thread also does not work because it causes an active x error. After looking it up i found that a solution was to use a single threaded apartment but this would not work because i may need multiple threads running off the same sub at once.
One solution that i have found to this problem is creating another form completely and setting it invisible, and since the form is its own thread i do not need to use threading.thread , but the problem comes when i am trying to create multiple threads, or else i can somehow dynamically create the threads and put the subs inside of it programically this method wont work And even if it does i feel that it is sloppy so i will leave this for one of two last resorts.
The other solution is the most simple one in which i just put all of the code in the main form, but if i keep on doing that form1 is gonna become huge and sloppy, doing this wont solve the webbrowser problem either and even when using regions i still feel that something that 1000+ lines deserves its own class.
There must be some solution out there that solves these problems. Any help would be appreciated, Thanks.
I checked my code for updating the progress bar, and using a single thread with synclock will NOT work. They way I make it work is perform the step of the pbar each time after a thread is started as I have limited total threads (say less than 5 threads). Thus, even the progress bar steps before the threads are finished, but it will not progress further before new threads started. It is not 100% accurate but it more or less telling the progress
'update the progress bar
some_form.PBar1.PerformStep()
' This while loop is to count the existing running thread,
' and determine whether new thread should start
While 1
Dim t2 = New System.Threading.Thread(Sub() WaitForPermission())
t2.Start()
t2.Join()
If proceed_gen Then
Exit While
End If
End While
'Start doing what I need to do
Dim t1 = SomeSub()
t1.Start()
'End of code, as VB doest not have thread.detach()
Correct me if I am wrong, but you probably have to use a background worker. I know this is annoying, but this is the limitation of VB.net.
Or, you can have something like this (pseudo code, not tested)
structure some_struct
'define the strings you want to update, and their status such that
'main() knows if you need to update the stuff to the form
' You can also put how many threads are running, and the status of each thread,
'such that the main knows if all threads are completed
end structure
sub your_sub()
'Manipulate the website, and update the data structure with
'proper stuff you need
end sub
sub main(){
dim t1 = New System.Threading.Thread(Sub() your_sub())
t1.start()
' I am listing only one threads here, but start as many as you want
'check if there are strings that you need to update to the form
while 1
'check if there are any stuff you want to update from the data structure.
' Make sure you use synclock on the data structure, so each thread won't fight each other on accessing the data struct
dim should_update as boolean = false
should_update = 'Something thatyou should implement to judge whether you should update the form.
'You can start a thread and join it so the thread won't fight with other threads for accessing the data structure
dim some_string as string
if should_update
some_string = 'You may also need a thread to join to get the stuff you need. Dim the string as an array if it is required.
'You can also try pass by ref
'if you need to use thread to access the data structure to know if you need to update the form
form1.listbox1.items.add(some_string )
end if
end while
end sub
This is an ugly solution, but it will help you do the job...

Code Execution Sequence

I am a PLC programmer who is currently using a variant of VB to control a motor.
I want to call a function that will execute moves and not return to the main code until the move has been completed. Currently here is what I have:
Program 'Main Program
While 1
If move_req = 1
Function MoveMotor
End If
Wend
End Program
Function MoveMotor
MoveABS 10 ' Move to encoder position 10mm
move_complete = 1
While move_req = 1
'Do Nothing
Wend
End Function
For some reason this code isn't working and the move command is being sent over and over again. Could this be because the main program continues to run when the function is running? Is that how VB works? I am used to thinking of code sequence in terms of PLC's where they scan through everything repeatedly at a certain frequency.
Whenever the move is complete, there must be a way for it to be detected by the program. It looks like you want move_req to be set to zero when this happens, but I cannot see what would cause that. How does the machine signal the program that it's finished moving?
A second point is that when you have a loop that waits while it checks for variable change, it can cause a CPU spike. You can put a pause in the loop with some thing like System.Threading.Thread.Sleep(100) where 100 is milliseconds to pause.

Threading. How does button click interrupt/influence program flow

My project is vb.net 2010 windows desktop form.
So far, single threaded (default).
If a SUBroutine has a for...next loop in it that is running, what happens if a buttonclick event is fired and within that event a variable is changed? Like: does program execution leave the loop that was running? Or does it continue to run while that variable is changed by the buttonclick event?
What I'm aiming for:
If someone clicks the button, blnRequestStop is set to True.
Within that for...next loop, just before the "next" it checks blnRequestStop. If true then it will exit the "for" loop.
I'm guessing I need to use threads? Can anyone give me a simple example, please?
EDIT:
This code below seems to be working fine. But maybe you all see a problem?
If (btnProcess.Text = "Done!") Then
End
ElseIf (btnProcess.Text = "IMPORT") Then
bRequestStop = False
t1 = New Thread(AddressOf ProcessDo)
t1.Start()
Else
t2 = New Thread(AddressOf MyInterrupt)
t2.Start()
End If
Here is the short version of what ProcessDo and MyInterrupt do:
Private Sub ProcessDo()
For each X in blahblah
'do stuff (yes, includes interface)
if (blnInterrupt) then exit For
Next X
End
End Sub
Private Sub MyInterrupt()
blnInterrupt=true
End Sub
Yes, you probably want to do the long-running task on a background thread. Here's a code sample including how you'd get the results back to the UI thread when you're done (otherwise you'll get errors about Cross-thread operation not valid).
ThreadPool is a nice way to do some work on a background thread. You could set stopIt = True in the button click event for the stop button.
ThreadPool.QueueUserWorkItem(
Sub()
For Each thing In things
If stopIt Then Exit Sub
'Do the stuff!
Next
'We're done, update UI
Me.UpdateUI("All done!")
End Sub)
To safely update the UI, you'll need to make sure you get back to the UI thread.
Public Sub UpdateUI(result As String)
If Me.InvokeRequired() Then
'If we aren't on the UI thread, invoke this function on the UI thread
Me.BeginInvoke(Sub() UpdateUI(result))
Exit Sub
End If
'Update UI here
lblResult.Text = result
End Sub
Execution is 'stopped' (in a way) until the Loop finishes him job, so yes, you need to multi-thread.
It it is not a very long operation where you need to update UI controls during the Loop then you just can use Application.DoEvents inside the loop to be able to use other controls as normally in the application when FOR loop is working, but I advise you that this will have a negative impact on UI performance, but if it's not a long duration loop then you maybe would consider to use DoEvents instead introduce into multi-threading it's just an alternative, not recommended but, you can use it.
PS: Forgive my English

What Would Cause A Form To Freeze Upon Executing Code

I'm trying to figure why my form freezes up when executing some code. I also can't minimize or move the form. Is it because of the WaitForExit being used in the process?
The below code is tied to a button click.
If Checkbox1.checked = True Then
Call Test()
End If
If Checkbox2.checked = True Then
Goto NextStep
Else
Goto StopProcessing
End If
Here is the test sub I'm calling. Calls an exe with an optional argument.
Using psinfo As New Process
psinfo.StartInfo.FileName = "C:\Temp\Test.exe "
psinfo.StartInfo.Arguments = Arg1
psinfo.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
psinfo.Start()
psinfo.WaitForExit()
End Using
The WaitForExit was added (so I thought) to not process the next statement (next statement being the If statement for Checkbox2) until the process was complete. Is this not the case?
The WaitForExit was added (so I thought) to not process the next statement (next statement being the If statement for Checkbox2) until the process was complete.
When you call WaitForExit, it will block until the process (Test.exe) completes.
Since you're running this on the user interface thread, it will cause your form to "freeze" until the process completes fully.
If you need this to not occur, you would need to wait on a background thread. You could, potentially, move this code into a BackgroundWorker and use it to synchronize with your main window - but you will need to handle "waiting" for the process to finish in a different manner (ie: disable your UI up front, run the process, re-enable when complete).
Note that, with the Process class, another alternative would be to add EnableRaisingEvents on the process, then adding a handler to Process.Exited. This will let you not WaitForExit(), but instead get notified via an event when the process completes.

How to CORRECTLY implement a multithreaded progressbar during a LINQ query?

Okay so here's the thing:
I have a linq query which loads approx. 1000 lines into a variable, during that process I want to display a progressbar, not necessarily stating the percentage, can be marquee style, doesnt matter.
This progressbar is on a modal form to precent the user from interacting with the app for the time the query's running.
Now here's my code:
Private Sub LoadBar()
Try
Dim load As New frmLoadbar
load.Text = "Loading bunch of data..."
load.ShowDialog()
Catch e As Threading.ThreadAbortException
Threading.Thread.ResetAbort()
End Try
End Sub
In another sub:
Dim myThreadDelegate As New Threading.ThreadStart(AddressOf LoadBar)
Dim th As New Threading.Thread(myThreadDelegate)
th.Name = "TimeConsuming"
th.Start()
Dim XY = db.Table.GetEnumerator
While XY.MoveNext
Dim item As New ListViewItem
item.Text = XY.Current.Name
item.Tag = XY.Current
ListBox1.Items.Add(item)
End While
Autos.Dispose()
Try
th.Abort()
Catch ex As Exception //here's where i 'swallow the re-thrown exception
End Try
Not thats one of the ugliest code i've ever written.It works i just dont want that rethrown exception.
Some explanation:
I want the modal form to close after the query is done.
For that reason I 'abort' the thread running the form.
Since aborting a thread throws a double-exception i have to 'swallow'
that exception.
Now i know i could implement this like the following:
Coding a loop into the form holding the progressbar, which checks
periodically for a boolean's value, and if its true the form could
close itself.
From the other form - on the worker thread - i could change that
booleans value to true after the query's finished.
But here comes my question:
Whats the best way to implement this?
I know it can be done with a background worker, which has been
specifically invented for this reason, but can i use the background
worker as the thread to show the progressbar?
If not (and i have to run the query on the background worker and
showing the modal form from my original form), would that mean that
the query would "work in the background"?
Would that mean that the query would be slower?
I've looked into other tutorials, but for one reason or another, either i wasnt able to copy it (due to complexity) or I wasn't convinced that it was better than this.
Thank you for your time you took to answer.
You could show the modal form and then run a BackgroundWorker from that form. The progress and completed events would be on the UI thread so you can update a progress bar while it is running and close the form in the completed event handler.
Okay, so for future reference, if someone needs clear help with code samples, Microsoft has it (thats a first..)
You can download it here:
Multithreading
Assuming Windows Forms, you do this with a BackgroundWorker component.