BackgroundWorker not updating GUI at other Form - vb.net

As stated I have a BackgroundWorker that runs a sub function DoHeavyWork().
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
If BackgroundWorker1.CancellationPending = True Then
e.Cancel = True
Else
'DO HEAVY WORK
DoHeavyWork()
End If
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
ProgressBar1.Value = e.ProgressPercentage
Label8.Text = e.ProgressPercentage.ToString() + " %"
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If e.Cancelled = True Then
ProgressBar1.Value = 0
Label8.Text = ""
ElseIf e.Error IsNot Nothing Then
MessageBox.Show(e.Error.Message)
Else
MessageBox.Show("Completed!")
End If
End Sub
Inside this sub function DoHeavyWork(), there are codes to update another form's GUI.
Private Sub DoHeavyWork()
For i As Integer = 1 To fresult_counter
Dim fresult As New Button
fresult.Name = "fresult_" & i
fresult.Text = result(index_acc(i - 1)).ToString
fresult.TextAlign = ContentAlignment.MiddleLeft
fresult.Width = 265
fresult.AutoSize = True
fresult.BackColor = Color.White
With fresult.FlatAppearance
.BorderColor = Color.White
.BorderSize = 2
.MouseDownBackColor = Color.DeepSkyBlue
.MouseOverBackColor = Color.DeepSkyBlue
End With
fresult.Anchor = AnchorStyles.Left
fresult.FlatStyle = FlatStyle.Flat
fresult.UseVisualStyleBackColor = False
fresult.Location = New Point(0, 22 * (i - 1))
Form1.TabControl2.TabPages(1).Controls.Add(fresult)
BackgroundWorker1.ReportProgress(i)
Next
End Sub
The problem is it did not update the GUI but the progress bar is working. I've tried getting the set of code out of the BackgroundWorker and it works fine. Is there something I did not set to enable BackgroundWorker to update the GUI?

As mentioned by jmcilhinney, the solution for my answer is very simple.
Just let the BackgroundWorker update the progress bar at the background. And when it finished doing it's work, the progress bar will be at 100 which means it is completed.
Once it is completed, simply add the update GUI codings (in my case: 'Form1.TabControl2.TabPages(1).Controls.Add(fresult)') at the sub function when BackgroundWorker has completed:
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If e.Cancelled = True Then
ProgressBar1.Value = 0
Label8.Text = ""
ElseIf e.Error IsNot Nothing Then
MessageBox.Show(e.Error.Message)
Else
MessageBox.Show("Completed!")
Form1.TabControl2.TabPages(1).Controls.Add(fresult)
End If
End Sub

Related

Run timer in background in visual basic form

first I'm new in this, and I have this code that shows a prompt to restart or postpone the restart for a while, the issue is that i want to hide the message and bring it back after the time specified by the user.
I'm using a "visual basic form" and the time that restart will be postponed it's selected from a "ComboBox"
My code is as follows.
Imports System.Management
Imports System.Security.Permissions
Imports System
Imports System.IO
Imports System.Collections
Imports System.SerializableAttribute
Public Class Form2
Dim PostponeReboot As Integer = 50
Private Const CP_NOCLOSE_BUTTON As Integer = &H200
Protected Overloads Overrides ReadOnly Property CreateParams() As CreateParams
Get
Dim myCp As CreateParams = MyBase.CreateParams
myCp.ClassStyle = myCp.ClassStyle Or CP_NOCLOSE_BUTTON
Return myCp
End Get
End Property
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Form1.Hide()
Label4.Text = SystemInformation.UserName
Button1.Enabled = False
ComboBox1.Enabled = False
Timer1.Interval = 1000
End Sub
Private Sub CheckBox1_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChanged
If CheckBox1.Checked Then
CheckBox2.Enabled = False
Button1.Enabled = True
ComboBox1.Enabled = False
ElseIf CheckBox1.Checked = 0 Then
CheckBox2.Enabled = True
Button1.Enabled = False
ComboBox1.Enabled = False
End If
End Sub
Private Sub CheckBox2_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox2.CheckedChanged
If CheckBox2.Checked Then
CheckBox1.Enabled = False
ComboBox1.Enabled = True
Button1.Enabled = True
ElseIf CheckBox2.Checked = 0 Then
CheckBox1.Enabled = True
ComboBox1.Enabled = False
Button1.Enabled = False
End If
End Sub
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
If ComboBox1.Text = "1 Hora" Then
PostponeReboot = 10
ElseIf ComboBox1.Text = "2 Horas" Then
PostponeReboot = 20
ElseIf ComboBox1.Text = "4 Horas" Then
PostponeReboot = 40
ElseIf ComboBox1.Text = "Seleccione" Then
Button1.Enabled = False
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If CheckBox1.Checked Then
MessageBox.Show("Rebooting")
'Shell("shutdown -r -f -t 60")
Form1.Close()
End
ElseIf CheckBox2.Checked Then
MessageBox.Show(PostponeReboot)
Timer1.Start()
Me.Hide()
End If
If PostponeReboot = 0 Then
Me.Show()
Else
Me.Hide()
End If
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
PostponeReboot = PostponeReboot - 1
'Label5.Text = PostponeReboot
End Sub
End Class
In the first "If" sentence of below I want to start the timer and hide the form, and in the second "If" i want to bring it back the form, but the form remains hidden.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If CheckBox1.Checked Then
MessageBox.Show("Rebooting")
'Shell("shutdown -r -f -t 60")
Form1.Close()
End
ElseIf CheckBox2.Checked Then
MessageBox.Show(PostponeReboot)
Timer1.Start()
Me.Hide()
End If
If PostponeReboot = 0 Then
Me.Show()
Else
Me.Hide()
End If
End Sub
I've tried putting the second "If" sentence in another place but don't work, what I'm doing wrong.
I assume here that your Timer1 class raises the Timer1.Tick event every x time after Timer1.Start() is called. The fact that the form can hide tells me Timer1.Start() isn't a blocking method. As such, your second if statement will be verified right after you hide the form, without waiting for the PostponeReboot variable to reach zero. This particular button handler would then exit and your form would remain hidden. What I see is that you already have an event handler for each tick of your timer. Why not use this handler to verify the state of your PostponeReboot variable?
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
PostponeReboot = PostponeReboot - 1
If PostponeReboot = 0 Then
Timer1.Stop() 'I would assume
Me.Show()
End If
End Sub
Although, I would recommend you to try other solutions, like having your timer raise an event only when it reaches the elapsed time (so you don't have to handle each ticks unnecessarily). I would also recommend looking into an Universal Windows App with Toast Notifications as you could set a Notification to appear at a set time (handled by Windows) so that you don't have to have a thread running in the background for this.

Switch textboxes to enter automatically after time

So I am making this sort of clock thing and I find it hard to discover a way to switch from textbox to another textbox every second. I've tried timers and dispatchtimer but I didn't succeed so I am looking for some expert tips.
The code below works.
Here's my vb.net script:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddHandler TextBox1.Enter, AddressOf TextBox1_Enter
AddHandler TextBox2.Enter, AddressOf TextBox2_Enter
AddHandler TextBox3.Enter, AddressOf TextBox3_Enter
AddHandler TextBox4.Enter, AddressOf TextBox4_Enter
AddHandler TextBox5.Enter, AddressOf TextBox5_Enter
AddHandler TextBox6.Enter, AddressOf TextBox6_Enter
AddHandler TextBox7.Enter, AddressOf TextBox7_Enter
AddHandler TextBox8.Enter, AddressOf TextBox8_Enter
AddHandler TextBox9.Enter, AddressOf TextBox9_Enter
AddHandler TextBox10.Enter, AddressOf TextBox10_Enter
AddHandler TextBox11.Enter, AddressOf TextBox11_Enter
AddHandler TextBox12.Enter, AddressOf TextBox12_Enter
End Sub
Private Sub TextBox1_Enter(sender As Object, e As EventArgs)
BackColor = Color.Red
End Sub
Private Sub TextBox2_Enter(sender As Object, e As EventArgs)
BackColor = Color.Blue
End Sub
Private Sub TextBox3_Enter(sender As Object, e As EventArgs)
BackColor = Color.Yellow
End Sub
Private Sub TextBox4_Enter(sender As Object, e As EventArgs)
BackColor = Color.Green
End Sub
Private Sub TextBox5_Enter(sender As Object, e As EventArgs)
BackColor = Color.Pink
End Sub
Private Sub TextBox6_Enter(sender As Object, e As EventArgs)
BackColor = Color.Teal
End Sub
Private Sub TextBox7_Enter(sender As Object, e As EventArgs)
BackColor = Color.SteelBlue
End Sub
Private Sub TextBox8_Enter(sender As Object, e As EventArgs)
BackColor = Color.LightGray
End Sub
Private Sub TextBox9_Enter(sender As Object, e As EventArgs)
BackColor = Color.Gold
End Sub
Private Sub TextBox10_Enter(sender As Object, e As EventArgs)
BackColor = Color.BlueViolet
End Sub
Private Sub TextBox11_Enter(sender As Object, e As EventArgs)
BackColor = Color.Orange
End Sub
Private Sub TextBox12_Enter(sender As Object, e As EventArgs)
BackColor = Color.Brown
End Sub
End Class
I am also posting a design of a clock for better imagination of the idea.
Well, i'm no professional (which will be evident by the long way i've come up with a solution, i'm sure someone who does it for a living could get it done much more eloquently) but here's what i came up with as it seemed like a fun task.
I've got it stating a timer on launch, then when the button is clicked a new thread is started in the background, that new thread increments a counter every second, and timer1_tick is constantly checking what the counter value is and adjusting the form and textboxes accordingly, it's changing the colour, putting the number in and making it the focused item.
You'll need the following items on Form1:
Textboxes 1 to 12 (in the pattern you provided with 12 being the top one)
A button (Button1)
Drag a timer (Timer1) onto Form1
Then replace the code on Form1 with the below
Imports System.Threading
Public Class Form1
Dim WorkerThread As New Thread(AddressOf DoWork)
Public StartStop As Boolean
Dim Counter As Integer
Private Sub DoWork()
StartStop = False
Do Until StartStop = True
Counter = 0
Do Until Counter = 13
Counter = Counter + 1
Application.DoEvents()
If Counter < 13 Then Threading.Thread.Sleep(1000)
Loop
Loop
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
WorkerThread.Start()
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Timer1.Start()
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
ClearAllTBs()
If Counter = 1 Then
TextBox1.BackColor = Color.Bisque
TextBox1.Text = "1"
TextBox1.Focus()
End If
If Counter = 2 Then
TextBox2.BackColor = Color.Beige
TextBox2.Text = "2"
TextBox2.Focus()
End If
If Counter = 3 Then
TextBox3.BackColor = Color.CornflowerBlue
TextBox3.Text = "3"
TextBox3.Focus()
End If
If Counter = 4 Then
TextBox4.BackColor = Color.Crimson
TextBox4.Text = "4"
TextBox4.Focus()
End If
If Counter = 5 Then
TextBox5.BackColor = Color.DarkCyan
TextBox5.Text = "5"
TextBox5.Focus()
End If
If Counter = 6 Then
TextBox6.BackColor = Color.DarkMagenta
TextBox6.Text = "6"
TextBox6.Focus()
End If
If Counter = 7 Then
TextBox7.BackColor = Color.Gold
TextBox7.Text = "7"
TextBox7.Focus()
End If
If Counter = 8 Then
TextBox8.BackColor = Color.Fuchsia
TextBox8.Text = "8"
TextBox8.Focus()
End If
If Counter = 9 Then
TextBox9.BackColor = Color.DarkViolet
TextBox9.Text = "9"
TextBox9.Focus()
End If
If Counter = 10 Then
TextBox10.BackColor = Color.MediumSeaGreen
TextBox10.Text = "10"
TextBox10.Focus()
End If
If Counter = 11 Then
TextBox11.BackColor = Color.Navy
TextBox11.Text = "11"
TextBox11.Focus()
End If
If Counter = 12 Then
TextBox12.BackColor = Color.BlueViolet
TextBox12.Text = "12"
TextBox12.Focus()
End If
Application.DoEvents()
End Sub
Private Sub Form1_Closed(sender As Object, e As EventArgs) Handles Me.Closed
StartStop = True
WorkerThread.Abort()
End Sub
Private Sub ClearAllTBs()
TextBox1.BackColor = Color.White
TextBox2.BackColor = Color.White
TextBox3.BackColor = Color.White
TextBox4.BackColor = Color.White
TextBox5.BackColor = Color.White
TextBox6.BackColor = Color.White
TextBox7.BackColor = Color.White
TextBox8.BackColor = Color.White
TextBox9.BackColor = Color.White
TextBox10.BackColor = Color.White
TextBox11.BackColor = Color.White
TextBox12.BackColor = Color.White
TextBox1.Text = ""
TextBox2.Text = ""
TextBox3.Text = ""
TextBox4.Text = ""
TextBox5.Text = ""
TextBox6.Text = ""
TextBox7.Text = ""
TextBox8.Text = ""
TextBox9.Text = ""
TextBox10.Text = ""
TextBox11.Text = ""
TextBox12.Text = ""
End Sub
End Class

Regain focus after a background task is completed

I have a datagridView(dgv) in the active tab(tabControl) that is filled with data obtained from a web service, when i start the query i create a separated thread that will assign the data to the dgv on his RunWorkerCompleted event, but then the dgv doesn't select a row when i make a click on it, in order to work properly i have to select the other tab and select again the tab containing this dgv
-the dgv still responds to the event cellContentClick
some code:
Private Sub backgroundWorker1_DoWork(sender As System.Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
Try
If UCA1.getAlumnos(codCarrrera, anio, ciclo, carnet_opc).alumnosArray IsNot Nothing Then
For i As Integer = 0 To UCA1.getAlumnos(codCarrrera, anio, ciclo, carnet_opc).alumnosArray.Length - 1
Dim a As sv.edu.uca.wsprb.alumnos = UCA1.getAlumnos(codCarrrera, anio, ciclo, carnet_opc).alumnosArray(i)
'here i add the rows
'TablaFAlumno.Rows.Add(...)
If i < 10 Then
BackgroundWorker1.ReportProgress(10)
End If
Next
Else
TablaFAlumno.Rows.Clear()
End If
Catch ex As System.Net.WebException
MessageBox.Show("->" + ex.Message)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Private Sub backgroundWorker1_ProgressChanged(sender As System.Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
If ProgressBar1.Value = 0 Then
ProgressBar1.Visible = True
End If
If ProgressBar1.Value < 100 Then
ProgressBar1.Value += 10
End If
End Sub
Private Sub backgroundWorker1_RunWorkerCompleted(sender As System.Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If e.Error IsNot Nothing Then
MessageBox.Show("E -->" + e.Error.Message)
ElseIf e.Cancelled = True Then
ProgressBar1.Visible = False
MessageBox.Show("C -->" + e.Error.Message)
End If
ProgressBar1.Visible = False
dgvAlumnos.DataSource = TablaFAlumno
End Sub
try ad the end :
ProgressBar1.Visible = False
'TabControl name with Ficha Alumno
Me.TabControl1.SelectedIndex = 0
dgvAlumnos.DataSource = TablaFAlumno
dvgAlumnos.Select()
End Sub

My progress bar is disappearing

My progressbar is disappearing as soon as I start running any code. Why's that?
That's really strange.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
StartThinking()
For Each z In ListBox1.Items
Dim u = FindIPAddress(z)
ListBox2.Items.Add(If(IsNothing(u), "Not found!", u))
Next
StopThinking()
End Sub
Sub StartThinking()
Cursor = Cursors.WaitCursor
ProgressBar1.Minimum = 0
ProgressBar1.Style = ProgressBarStyle.Marquee
End Sub
Sub StopThinking()
ProgressBar1.Minimum = ProgressBar1.Maximum
ProgressBar1.Style = ProgressBarStyle.Blocks
Cursor = Cursors.Arrow
End Sub

VB.net stopping a backgroundworker

I want to create a button that could stop my background worker and end all the process it is working on.
Here is my sample backgroundworker code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Try
If BackgroundWorker1.IsBusy <> True Then
BackgroundWorker1.RunWorkerAsync()
End If
Catch ex As Exception
End Try
End Sub
Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim counter As Integer = 1
Do
'updated code with stop function----------------
BackgroundWorker1.WorkerSupportsCancellation = True
If BackgroundWorker1.CancellationPending Then
e.Cancel = True
ProgressBar1.Value = 0
Exit Do
End If
'updated code with stop function----------------
ListBox1.Items.Add(counter)
ProgressBar1.Value = ((counter - 1) / limit) * 100
counter = counter + 1
Loop While(counter <= 999999999999999999)
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As System.Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
Try
Catch ex As Exception
End Try
End Sub
Private Sub BackgroundWorker1_Completed(sender As System.Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
Try
Catch ex As Exception
End Try
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False
End Sub
'updated code with stop function----------------
Private Sub StopButton_Click(sender As Object, e As EventArgs) Handles StopButton.Click
If BackgroundWorker1.IsBusy Then
If BackgroundWorker1.WorkerSupportsCancellation Then
BackgroundWorker1.CancelAsync()
End If
End If
End Sub
'updated code with stop function----------------
I want to reset the loop and return the Progress Bar to 0% when i stop the backgroundworker.
Is this possible?
The code above has been updated and it is now working fine.
I have added this code inside my do loop:
BackgroundWorker1.WorkerSupportsCancellation = True
If BackgroundWorker1.CancellationPending Then
e.Cancel = True
ProgressBar1.Value = 0
Exit Do
End If
I created a button that stops the worker:
Private Sub StopButton_Click(sender As Object, e As EventArgs) Handles StopButton.Click
If BackgroundWorker1.IsBusy Then
If BackgroundWorker1.WorkerSupportsCancellation Then
BackgroundWorker1.CancelAsync()
End If
End If
End Sub
The Backgroundworker class has the method CancelAsync() which you need to call to cancel the execution of the bgw.
You need to set the Backgroundworker.WorkerSupportsCancellation property to true and inside the while loop you need to check the CancellationPending property wether the value is true which indicates a call to the CancelAsync() method.
If CancellationPending evaluates to true, you would ( which you should have done already ) call one of the overloaded ReportProgress() (Docu) methods to set your ProgressBar value to the desired value.
EDIT: You should set the Cancel property of the DoWorkEventArgs to true so you can check the Cancelled property of the RunWorkerCompletedEventArgs inside the RunworkerCompletedevent.
You also shouldn not access any controls which lives in the UI thread. You better use the ProgressChanged(Docu) event.
See: BackgroundWorker Docu
Public Class Form1
Private iVal As Integer = 0
Private Sub bgw_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgw.DoWork
For iVal = iVal To 100 Step 1
bgw.ReportProgress(iVal)
Threading.Thread.Sleep(99)
If (bgw.CancellationPending = True) Then
e.Cancel = True
Exit For
End If
Next
End Sub
Private Sub bgw_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgw.ProgressChanged
pbar.Value = e.ProgressPercentage
lblProgrss.Text = e.ProgressPercentage.ToString() & "%"
End Sub
Private Sub bgw_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted
If (e.Cancelled = True) Then
pic.Visible = False
pbar.Value = iVal
lblProgrss.Text = iVal & "%"
btnstart.Text = "Start"
btnstart.BackColor = Color.Green
Else
pic.Visible = False
btnstart.Text = "Start"
btnstart.BackColor = Color.Green
iVal = 0
End If
End Sub
Private Sub btnstart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnstart.Click
If (btnstart.Text = "Start") Then
btnstart.Text = "Stop"
btnstart.BackColor = Color.Red
pic.Visible = True
bgw.RunWorkerAsync()
Else
If (bgw.IsBusy = True) Then
btnstart.Text = "Start"
btnstart.BackColor = Color.Green
bgw.CancelAsync()
End If
End If
End Sub
End Class