Disposing background worker does not work - vb.net

I have a background worker that calls a form, holding a gif animation. The purpose is to display the animation while process is underway but it should close when the process is done. But it does not close even after completion of the process. Please help.
Thanks
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
frmAnimation.ShowDialog()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync()
Dim sqldatasourceenumerator1 As SqlDataSourceEnumerator = SqlDataSourceEnumerator.Instance
datatable1 = sqldatasourceenumerator1.GetDataSources()
DataGridView1.DataSource = datatable1
'I have tried CancelAsync, but did not work
BackgroundWorker1.CancelAsync()
frmAnimation.Dispose()
End Sub

BackgroundWorkers are intended to actually do the "work" of the background operation, so the main UI thread can continue rendering things onto the screen. I suspect you want the GetDataSources() function call to be done within the BackgroundWorker thread.
Try switching what's in your button click function and what's in the DoWork function of your BackgroundWorker. Specifically, I mean something like this:
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim sqldatasourceenumerator1 As SqlDataSourceEnumerator = SqlDataSourceEnumerator.Instance
datatable1 = sqldatasourceenumerator1.GetDataSources()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync()
frmAnimation.ShowDialog()
End Sub
And in addition, add some code to the RunWorkerCompleted event to handle what should be done upon completion of your background operation.
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
DataGridView1.DataSource = datatable1
frmAnimation.Close()
End Sub
You may also want to consider using frmAnimation.Show() instead of frmAnimation.ShowDialog() depending on if you want the procedure to be modal or modeless. You can read more about that here.

Related

How can I Cancel Multiple Background Workers in a For loop?

Creating a Windows app in Visual Studio 15.
Have a form where I can start up to 10 background worker tasks (BG1 to BG10). I currently cancel each BGWorker individually with:
Private Sub DSx10C_Click(sender As Object, e As EventArgs) Handles DSx10C.Click
BackgroundWorker10.CancelAsync()
BackgroundWorker10.Dispose()
Label10.Text = "Cancelled"
End Sub
I need to do a Cancel ALL option.
How can I loop through all 10 BGWorkers in a For loop?
Hope my question is a better MCVE.
How to cancel all the BackgroundWorkers,
You can do it like this:
Declare an array of BackgroundWorkers
Dim MyBackgroundWorkers() As BackgroundWorker
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'' add all your BackgroundWorkers to the array
MyBackgroundWorkers = New BackgroundWorker() {BackgroundWorker1, BackgroundWorker2, BackgroundWorker3, BackgroundWorker4, BackgroundWorker5}
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'' now you can Cancel all of them in a loop
For Each bgw In MyBackgroundWorkers
If bgw.IsBusy Then
bgw.CancelAsync()
End If
Next
End Sub
This is assuming that your BackgroundWorkers are controls you added from the toolbox at design time. If it was declared and added from code, you would need to make appropriate modifications in the Form_Load code.
Try This. Hope This helps.

Access Main thread data from the Background thread

I´m using a backgroundworker to handle processing of data while the user is still free to for instance click another button that aborts the process.
However, the code in backgroundworker requires several pieces of data, for instance it needs to know whether a radio button is checked.
Is there a way to access data in another thread from the background thread? Or should I create global variables that hold this information?
Public Class Test
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Button1.Content = "Working..."
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
If RadioButton1.IsChecked Then
MsgBox("It works")
End If
End Sub
End Class
You can pass the RadioButton checked state to the RunWorkerAsync method like this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync(RadioButton1.Checked)
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim checked As Boolean = CBool(e.Argument)
If checked Then
MessageBox.Show("It works")
End If
End Sub
Let me know if you need to be checking the RadioButton continuously from inside a loop, as that would be different.

How does the ProgressBar.PerformStep() function work?

I'm quite confused about progress bar in VB.net, here is my code
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ProgressBar_my.Minimum = 0
ProgressBar_my.Maximum = 10
ProgressBar_my.Step = 1
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
ProgressBar_my.PerformStep()
Threading.Thread.Sleep(5000)
If 1 = 1 Then
ProgressBar_my.PerformStep()
ProgressBar_my.PerformStep()
End If
'Threading.Thread.Sleep(2000)
End Sub
For the above code, what I expected is that after I click Button1, the progress bar will increase the progress status by 1, then it will pause for 5 sec, then it will increase the progress status by 2 at once.
However, after I ran the above code, what I saw was that after I click Button1, the progress bar will increase by 3 continually after 5 sec.
Can someone tell me why it behaves like this and How should I program my code so that I can increase by 1, then pause 5 sec and then increase by 2?
Thanks in advance!
I think what you are seeing (or not seeing) is the fact that the progress bar takes a finite amount of time to advance each step.
When you call Threading.Thread.Sleep on the UI thread this stops the progress bar from being redrawn until after the Sleep
What you should do is update the progress bar on a background worker instead, then I think you will see the effect you desire.
Add a BackgroundWorker to your form
Change your button click code to start the worker:
Private Sub frmSO_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ProgressBar_my.Minimum = 0
ProgressBar_my.Maximum = 10
ProgressBar_my.Step = 1
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync
End Sub
Then perform the update in the DoWork event:
'define a delegate to handle updates to the UI thread
Private Delegate Sub PerformStepCallback()
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim cb As PerformStepCallback = AddressOf ProgressBar_my.PerformStep
Me.BeginInvoke(cb)
Threading.Thread.Sleep(5000)
Me.BeginInvoke(cb)
Me.BeginInvoke(cb)
End Sub
The problem is that you call Threading.Thread.Sleep(5000), which will, well, pause the current thread. But that also means that the window won't be redrawn, so you see the effect of the first call to PerformStep only after the thread is no longer paused.
You can use another thread for wait and the second update; the easiest way in this case is using the Task Parallel Library:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
ProgressBar1.PerformStep()
Task.Delay(5000).ContinueWith(Sub()
ProgressBar1.PerformStep()
ProgressBar1.PerformStep()
End Sub, TaskScheduler.FromCurrentSynchronizationContext)
End Sub
Thanks Matt Wilko for giving me the clue. Here is my code.
From the Components tab of the Toolbox, add a BackgroundWorker component named backgroundWorker2. Create DoWork and ProgressChanged event handlers for the BackgroundWorker.
The following code will initiate the Component.
Public Sub New()
InitializeComponent()
BackgroundWorker2.WorkerReportsProgress = True
BackgroundWorker2.WorkerSupportsCancellation = True
End Sub
Call RunWorkerAsync when the button is clicked and the background worker is not running.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
If BackgroundWorker2.IsBusy <> True And ProgressBar_my.Value < 6 Then
BackgroundWorker2.RunWorkerAsync()
End If
End Sub
Private Sub BackgroundWorker2_DoWork_1(ByVal sender As System.Object, _
ByVal e As System.ComponentModel.DoWorkEventArgs) _
Handles BackgroundWorker2.DoWork
Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
worker.ReportProgress(1)
System.Threading.Thread.Sleep(2000)
worker.ReportProgress(1)
worker.ReportProgress(1)
End Sub
The following event is raised when every time the ReportProgress method is called.
Private Sub backgroundWorker2_ProgressChanged(ByVal sender As System.Object, _
ByVal e As System.ComponentModel.ProgressChangedEventArgs) _
Handles BackgroundWorker2.ProgressChanged
ProgressBar_my.PerformStep()
End Sub
More information about the BackgroundWorker:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx

Visual Basic 2010 Live Logger

Hello I am trying to make a live logger in my program so I can keep track of the progress.
Like this:
http://i.stack.imgur.com/cmcTp.png
How do I make something like this.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
You can use background worker, with a listbox to accomplish what you are asking. On the reports progress method of background worker, you can specify the "userstate" object to "log" to controls on the UI thread, just make sure to set 'worker reports progress' to true:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'where you call your worker to do work
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'make sure to set worker reports progress to true
BackgroundWorker1.ReportProgress(0, "About to Messagebox") 'where 0 is a progress percent if you want it and the string is overloaded
MsgBox("This is to show how to report before an event!")
End Sub
Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
'
ListBox1.Items.Add(e.UserState)
End Sub
End Class

fill dgv in the background.

I have a dgv filled by a sp everything created with the wizard. since filling takes about 10 seconds i wanna have this in a background using a backgroundworker. I tried:
Public Class frmStart
Delegate Sub updateDGV()
Private Sub frmStart_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles MyBase.Load
BackgroundWorker1.WorkerSupportsCancellation = True
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, _
ByVal e As System.ComponentModel.DoWorkEventArgs) _
Handles BackgroundWorker1.DoWork
Me.Invoke(New updateDGV(AddressOf UpdatingForm))
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object , _
ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
Handles BackgroundWorker1.RunWorkerCompleted
msgbox("Completed")
End Sub
Private Sub UpdatingForm()
Try
me.tableadapter.fill(me.dataset.table)
Catch ex As Exception
MsgBox("Error during loading the dgv")
Finally
BackgroundWorker1.CancelAsync()
End Try
End Sub
End Class
I just see the first row in the dgv. How can i fill my whole dgv in the background, where is the mistake in the code? Additionally, i would like to see a popup during the fill process with "please wait your dgv gets filled". any idea how to accomplish that?
before i modified the code i had only the following line, which was programatically created.
me.tableadapter.fill(me.dataset.table)
Your new code is identical to the initial version. Me.Invoke is forcing UpdatingForm to be executed in UI thread. You can split in 2 parts.
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Me.ProductsTableAdapter.Fill(Me.NorthwindDataSet.Products)
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
Me.ProductsBindingSource.ResetBindings(False)
End Sub
check as well Asynchronous Data Loading using TableAdapter with Cancel Feature