Background process hangs application vb.net - vb.net

I have a background process:
Public Shared Function CheckForInternetConnection() As Boolean
Try
Using client = New WebClient()
Using stream = client.OpenRead("http://www.google.com")
Return True
End Using
End Using
Catch
Return False
End Try
End Function
This process ties up my application, causing it to hang until completed.
I'm trying to incorporate this into a "BackGroundWorker" and tie it to a progress bar.
However, though the application no longer hangs when the process is running, the progress bar does.
I'd like the progress to progress from 0 - 50% during the above function, however currently, the progress bar sits at 0% until the process is complete, them jumps to 50%.
Private Sub bgwLongTask_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwLongTask.DoWork
For i As Integer = 1 To 10
' If we should stop, do so.
If (bgwLongTask.CancellationPending) Then
' Indicate that the task was canceled.
e.Cancel = True
Exit For
End If
CheckForInternetConnection()
LoadingScreen.CheckForIllegalCrossThreadCalls = False
Me.Text = i
' Notify the UI thread of our progress.
bgwLongTask.ReportProgress(i * 10)
Next i
End Sub
Private Sub bgwLongTask_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgwLongTask.ProgressChanged
If e.ProgressPercentage >= 0% And e.ProgressPercentage <= 50% Then
lblStatus.Text = "Checking Netowrk ..."
Else
lblStatus.Text = "Loading ..."
End If
prgPercentComplete.Value = e.ProgressPercentage
End Sub
By using:
LoadingScreen.CheckForIllegalCrossThreadCalls = False
Me.Text = i
I can see that the progress bar doesn't even start until CheckForInternetConnection() has completed.
Can someone please help me sort this out?
Much appreciated. Thanks.

You're looping from 1 to 10 calling CheckForInternetConnection() in every iteration, that doesn't makes sense. In this case the long-running process is CheckForInternetConnection() method, so you need to somehow "report progress" while the method is executing.
Possible way to notify user that the program is processing something when we can't calculate progress percentage of the process is using progress bar in indeterminate mode (by setting Style to Marquee in WinForm or setting IsIndeterminate to True in WPF).

Related

(VB.NET) Quick way for a Simple Splashscreen for WinForms [duplicate]

This question already has answers here:
How to create a Splash screen for VB.net program
(3 answers)
Closed 6 days ago.
My program took ~5-10 seconds to load and sometimes people using it would end up trying to open it again, which caused problems. I found a quick and easy way to make a "splashscreen" (in a sense) that pops up for a set amount of time immediately on execution. I found that the first order of events in a WinForm EXE loading was Handle Created. The answer is not a true splashscreen, but for a couple lines of code that can be easily added to a project, I think some people will like it.
The below code will show a MessageBox immediately on running the EXE and closes after 10 seconds.
Imports System.Threading
Private Sub Control1_HandleCreated(ByVal sender As Object, ByVal e As EventArgs) Handles Me.HandleCreated
Dim SplashScreen As New Thread(
Sub()
CreateObject("WScript.Shell").Popup("Program Initializing, Please Wait...",10, "Setup Tool")
End Sub)
SplashScreen.Start()
End Sub
I use Threading so that the MessageBox will not freeze the code and the program will open with or without the OK button being pressed. Doing a regular MessageBox.Show() will prevent any more code from running until the user clicks OK I have found.
The best way I have found to implement a splash screen which keeps the user informed via messages and/or a progress bar or animated wheel is the following.
Have a startup form eg Form1, and have it carry out all the tedious startup procedures which might cause any animated or progress bar graphic to get stalled in the event queue. Add a "BackgroundWorker" object to Form1 from the Toolbox and in my case I just named it BackgroundWorker1.
Before starting these routines, usually in the Form1_Load event, make a call to the BackgroundWorker.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
CallBackgroundWork()
StartRoutines() 'this is the heavy lifting routines to get the app working. Set the LoadingStatusflag (declared as a Global Variable"
to various values to tell the splashscreen to display different messages
Loadingstatus = 10 'triggers splashform to exit
CancelBackgroundWork()
End Sub
These are the other subs to support this
Sub CallBackgroundWork()
BackgroundWorker1.WorkerSupportsCancellation = True
BackgroundWorker1.WorkerReportsProgress = True
' call this method to start your asynchronous Task.
BackgroundWorker1.RunWorkerAsync()
End Sub
Sub CancelBackgroundWork()
' to cancel the task, just call the BackgroundWorker1.CancelAsync method.
BackgroundWorker1.CancelAsync()
End Sub
Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'' The asynchronous task we want to perform goes here
FormSplash.Show()
End Sub
My splashscreen has some label controls and pictureboxes and the FormSplash_Load event runs a stopwatch loop of 40ms and loads a series of images (24 in total) of a spinning wheel. This keeps running while the splashscreen is active. By setting the global variable Loadingstatus to various values within different part of the loading sequence in Form1 it can trigger the loop routine to display different messages example shown. An easy way to communicate between threads as you can't directly access objects between threads The wheel keeps spinning no matter how intensive the load routine in Form1 as it is running in another thread. I used a stopwatch loop as starting a timer doesn't work for me - maybe an event queue issue in splash form.
Private Sub FormSplash_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.Show()
Me.Opacity = 1 'show this form
'now start a loop that gets ended by other thread through variable Loadingstatus flag
Dim ggtimer As New Stopwatch, lastvalue As Integer, FProgPosition as integer
ggtimer.Start()
lastvalue = ggtimer.ElapsedMilliseconds
nextimage:
FProgPosition += 1
If FProgPosition = 24 Then FProgPosition = 1 'has 24 frames in the animated image
Do 'loop for 40 ms
If ggtimer.ElapsedMilliseconds - lastvalue > 40 Then
lastvalue = ggtimer.ElapsedMilliseconds
Exit Do
End If
Loop
PictureBoxProgress1.Image = FProgIMG(FProgPosition)
PictureBoxProgress1.Refresh()
If Loadingstatus = 10 Then GoTo endsplash
If Loadingstatus = 1 Then
If CoreTempRunning = False Then
Me.LabelCoreTemp.Text = "CoreTemp is NOT Running"
Me.LabelCoreTemp.ForeColor = Color.White
'insert cross picturebox
PictureBoxCoreTemp.Image = My.Resources.ResourceManager.GetObject("Cross24x24")
loaderrorflag2 = True
Else
Me.LabelCoreTemp.Text = "CoreTemp is Running"
Me.LabelCoreTemp.ForeColor = Color.White
'insert tick picturebox
PictureBoxCoreTemp.Image = My.Resources.ResourceManager.GetObject("Tick24x24")
loaderrorflag2 = False
End If
Me.PictureBoxCoreTemp.Visible = True
Me.PictureBoxCoreTemp.Refresh()
Me.LabelCoreTemp.Left = Me.Width * 2 / 3 - Me.LabelCoreTemp.Width
Me.LabelCoreTemp.Refresh()
GoTo nextimage
endsplash:
ggtimer.Stop()
Me.Opacity = 0.01
Me.Hide()
End Sub

Running a BackGroundWorker more than once

I wonder if you can help?, please bear in mid I’m an absolute novice.
I trying to update a program I made a few years ago for booking in serial numbers into a CRM application.
Currently it runs the following command for each of the 100 textboxes and has worked a treat booking in more than 81000 serial numbers.
If TextBox1.Text.Length > 1 Then
Clipboard.SetText(TextBox1.Text)
RetBat1 = Shell("C:\Windows\BookIN.exe", , True)
Endif
The new version of the app I’ve added a listbox1 with the serial numbers in, I’m then running the below For Each loop.
The For Each loop copies each Item into the clipboard and the BookIN.exe tabs to the right location in the CRM and pastes the information, then clicks a button in the CRM for a new Line and then runs again. This works fine, but I want to add a stop button or a stop checkbox.
For Each items In ListBox1.Items
Clipboard.SetText(items)
RetBat1 = Shell("C:\Windows\BookIN.exe", , True)
Next
I have tried adding the Retbat1 to a backgroundworker, which checks if Checkbox1.checked then exit the for each loop.
The first serial number works, but when the backgroundworker runs more than once I get the following error.
If CheckBox1.Checked = True Then
BackgroundWorker1.CancelAsync()
Else
Dim RetBat1 As String
RetBat1 = Shell("C:\Windows\BookIN.exe", , True)
End If
System.InvalidOperationException: 'This BackgroundWorker is currently busy and cannot run multiple tasks concurrently.'
Sorry if this makes not sense, thanks James
The way it would go is that you would run the BackgroundWorker and have your loop in the DoWork event handler and check whether a cancellation has been requested within that loop. As you've described it, you would then handle the CheckedChanged even of your CheckBox and request the cancellation when the event is raised. I would not use a CheckBox though, because that implies that you can uncheck it to uncancel the work. I would suggest using a Button and handling its Click event, e.g.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'We must get the data from the UI here and pass it into the background thread.
Dim items = ListBox1.Items.Cast(Of String)().ToArray()
'Start the background work and pass in the data.
BackgroundWorker1.RunWorkerAsync(items)
'Enable the Cancel button.
Button2.Enabled = True
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
'Disable the Cancel button so it cannot used again.
Button2.Enabled = False
'Request that background processing be cancelled.
BackgroundWorker1.CancelAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'Get the data that was passed in.
Dim items = DirectCast(e.Argument, String())
'Process each item.
For Each item In items
'Check whether processing has been cancelled.
If BackgroundWorker1.CancellationPending Then
'Cancel processing.
e.Cancel = True
Exit For
End If
'Process the current item here.
Next
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If e.Cancelled Then
MessageBox.Show("The background operation was cancelled")
Else
'Disable the Cancel button.
Button2.Enabled = False
MessageBox.Show("The background operation completed successfully")
End If
End Sub
The Cancel Button should be disabled by default and notice that this code ensures that it is only enabled when background processing is in progress. Note that the other Button probably ought to be disabled while the processing is in progress too. If you don't do that, at least check IsBusy on the BackgroundWorker. The visual feedback to the user is better though.

Progress Bar will not work, even when all the program does is show a Progress Bar

I have a form which, at present, is doing nothing but opening. The form has 2x controls - a 'Close' button and a Progress Bar. However, when I open the form, I get nothing. The Progress Bar just sits there doing nothing.
I've tried both Marquee (which I understand may not work in Windows 8) and Continuous, but I can't get anywhere with either.
This is how I'm showing the form when the program starts -
Sub main()
Dim ProgressForm As New formProgress
ProgressForm.ShowDialog()
End Sub
And below are the properties for the Progress Bar. Am I missing something that would get this bar working? Thanks.
Additional Information
For my full program, I did originally try using the Block style for the Progress Bar, but I kept getting the following error when trying to update the Progress Bar from a BackgroundWorker. This is why I am trying to get a simple Marquee/Continuous bar working instead.
Additional information: Cross-thread operation not valid: Control 'proWorking' accessed from a thread other than the thread it was created on.
if you use marquee style you have to set marqueeanimationspeed to some value
//
// progressBar1
//
this.progressBar1.Location = new System.Drawing.Point(91, 118);
this.progressBar1.MarqueeAnimationSpeed = 50;
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(100, 23);
this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Marquee;
this.progressBar1.TabIndex = 0;
and use continuous style with marqueeanimationsspeed 0 to stop it
For the Progressbar to do something (apart from the Marquee Style) you need to set the Value property. If you have .Minimum=0 and .Maximum=100 then a .Value of 50 means that the Progressbar is half full. If you should use Continuous or Blocks Style depends on the Visual Styles settings and doesn't make a real difference here on Win 7 (maybe it does for example under Win XP).
The Marquee style means that you don't know how far your task has proceeded. The Progressbar then shows a continously moving piece (is only visible at runtime!!). I just tested it in Win 7 and it works.
Here's a little boilerplate I use with a BackgroundWorker and a ProgressBar and Label.
Public Class BackgroundWorkerUI
Private args As New ProgressArgs
Private Sub bw_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles bw.DoWork
'set ProgressBar style to Marquee
args.Style = ProgressBarStyle.Marquee
bw.ReportProgress(0) 'triggers the progress changed event to update UI on correct thread
'some long operation
Threading.Thread.Sleep(5000)
'Set ProgressBar style to Continuous
args.Style = ProgressBarStyle.Continuous
For i As Integer = 0 To 100
If bw.CancellationPending Then
e.Cancel = True
Exit For
End If
args.Current = i
args.Max = 100
args.Status = String.Format("({0} of {1}) Updating...", args.Current, args.Max)
bw.ReportProgress(0)
'some operation
Threading.Thread.Sleep(100)
Next
End Sub
Private Sub bw_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles bw.ProgressChanged
lblStatus.Text = args.Status
If args.Style = ProgressBarStyle.Marquee Then
bar.Style = args.Style
bar.MarqueeAnimationSpeed = 15
Else
bar.Style = ProgressBarStyle.Continuous
bar.Minimum = args.Min
bar.Maximum = args.Max
bar.Value = args.Current
End If
End Sub
Private Sub bw_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bw.RunWorkerCompleted
If e.Error IsNot Nothing Then
MessageBox.Show(e.Error.Message, "Background Worker Exception", MessageBoxButtons.OK, MessageBoxIcon.Error)
Else
If e.Cancelled Then
lblStatus.Text = "Operation canceled"
Else
lblStatus.Text = "Done"
End If
End If
End Sub
Private Sub BackgroundWorkerUI_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
If bw.IsBusy Then
Dim r = MessageBox.Show("A background process is still running. Are you sure you want to quit?", "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
If r = Windows.Forms.DialogResult.Yes Then
bw.CancelAsync()
End If
e.Cancel = True
End If
End Sub
Private Class ProgressArgs
Inherits EventArgs
Public Property Status As String
Public Property Current As Integer
Public Property Min As Integer
Public Property Max As Integer
Public Property Style As ProgressBarStyle
Public Sub New()
Status = ""
Current = 0
Min = 0
Max = 0
Style = ProgressBarStyle.Continuous
End Sub
End Class
End Class

vb.net multi threading

I have been doing some coding for a system and need to use threading instead of normal timers in VB.NET.
It works fine but the problem lies in the blink timings, when the button is clicked then it blinks as expected, if in testing it is clicked more than once then the blinking time roughly multiplies by the original sleep thread time (750ms), this continues to happen for every click.
What can I do to make the blink not speed up? Below is the code!
Private _flash As Boolean = False
Private Sub btnButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnButton1.Click
_flash = True
Dim FlashThread As New Thread(New ThreadStart(AddressOf FlashLabel))
FlashThread.Start()
End Sub
Private Sub FlashLabel()
Dim _color As Color = Color.Gray
While _flash
If label1.ForeColor.Equals(_color) Then
label1.ForeColor = Color.Red
Else
label1.ForeColor = Color.Gray
System.Threading.Thread.Sleep(750)
End While
End Sub
Every time the button is clicked, you are starting a new thread, so if you click the button twice, it will start two threads, both of which are toggling the colors at 750 millisecond intervals, so it appears as if there was one thread doing it twice as fast. A simple way around this is to simply skip starting the new thread if the _flash flag is already set, for instance:
Private Sub btnButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnButton1.Click
If Not _flash Then
_flash = True
Dim FlashThread As New Thread(New ThreadStart(AddressOf FlashLabel))
FlashThread.Start()
End If
End Sub
You never cancel the original thread, so when you click the button a second time you now have two threads running and causing the blink to happen.
So you can either cancel the thread in another action or only start the thread the first time and then set _flash to true and false after that.

Pause and resume a Thread (Background Worker)

I am working in VB.Net and I need to pause one thread as it waits for the other to finish.
I've seen a very close question but can't seem to figure it out (And couldn't comment on that post Pause/Resume loop in Background worker)
My scenario is that I have 2 background workers. Worker1 is passing fileNames to Worker2 which processes the files. I need to pause Worker1 if Worker2 hasn't finished. I.e. Worker1 only releases the next fileName after Worker2 has finished
Any ideas on how to do this?
WORKING CODE AFTER COMMENTS FROM #user1666788
Code below is for the scenario stated above of two background workers where one has to wait for the other to finish before proceeding.
Dim isFinished as boolean
Dim currentFiile as integer
Private Sub StartWork_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StartWork.Click
bgWorker1.WorkerSupportsCancellation = True
isFinished = True
currentFile = 0
bgWorker1.RunWorkerAsync()
End Sub
Private Sub bgWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgWorker1.DoWork
If isFinished = False Then
bgWorker1.CancelAsync()
End If
isFinished = False
For i = currentFile To fileNames.Count - 1
Dim fileName As String = fileNames(i)
LoadRules(myValidator.GetFileType(fileName))
If i = fileNames.Count Then bgWorker1.CancelAsync()
Exit Sub
Next
End Sub
Private Function LoadRules(ByVal fileType As String) As Boolean
' Function to load some rules for file processing
Try
' Start Thread for actual file processing using bgworker2
bgWorker2.WorkerSupportsCancellation = True
bgWorker2.RunWorkerAsync()
Return True
Catch ex As Exception
End Try
End Function
Private Sub bgWorker2_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgWorker2.DoWork
Try
' Do your thing here
' for x is 0 to 1million
' next
' Mark is finished to true
isFinished = True
' Set currentFile
currentFile += 1
' The bgWorker1 is restarted when bgWorker2 has finished.
' Note however that bgWorker1 will "Continue" where it left off due to the property "currentFile"
bgWorker1.RunWorkerAsync()
'++++++++++++++++++++++++++++++++++++
Catch ex As Exception
End Try
End Sub
There you go. Its working as expected. Now need to figure out how to "monitor" progress of writing a file to disk so that I can start off another process after the file has fully been created.....
I had a similar issue as this. from what I've been told by VS it can't be done.
However I found a way around the subroutines for pausing/resuming threads no longer being used.
The easiest way is to check progress, and if it's still working end the call.
Here is an example, imagine S1 as your first thread and S2 as your second.
sub S1()
if(processingfile)then exit sub
'Insert code here for sending next file for processing
end sub
sub S2()
processingfile = true
'Insert code for processing files
processingfile = false
end sub
That is more or less how I worked around the problem. I hope my advice helped :)
Oh and one more thing, you might want to sleep the first thread before checking if the file is processing so that it doesn't use up a bunch of CPU power. But that's just a guess, I haven't tried it without a short sleeping period