Using BackgroundWorker to fetch data - vb.net

I used the data sources tab to drag and drop some fields from my database onto a form. This created the reqired textboxes/fields/designer components and also created a fill command by default, which is expected.
On my form load event, the following command takes place:
Me.TblQueueTableAdapter.dt_FillIncompleteCases(Me.BE_DataSet.tblQueue)
This command can take a while to fill on the end user's PC. I would like to display something in the meantime while the data is being retrieved so I added a new borderless form which will show before the fill event, then hide after completion.
So the problem as it stands is the main thread is being blocked due to the database fill code above, and my main thread will not display the borderless form. The process of showing and hiding works, but because the thread is blocked, the content of the borderless form is blank. I need to stop the main thread from blocking.
I know I can probably use a background worker to get this data out of the database. I could instantiate a new table adapter and use the fill command in the do work event. If I do this, I canpass back the datatable through e.result but I dont know how to set the datatable to my designer controls. How do I do this?
In the run worker completed event, I imagined something like:
Me.BE_DataSet.tblQueueDataTable = e.result
But this is a type and cannot be set in this way. What do I need to do?

Related

How to add row to end of datagridview that is filled in by a background worker inside custom control

In the project I am working on right now, there is a tab in a custom control that is filled in after the current run finishes. So once the current run finishes, the main function calls one of the custom control's public functions that uses a background worker to fill in a datagridview in the custom control. From the main function, I want to add a row to the end of the datagridview once it is filled in. However, each time I have tried to add the row, it says the datagridview has 0 rows in it and adds it as the first item. The solution I am trying to find is how to recognize when the background worker in the custom control finishes, so I know when to add the row to the end of dgv. I thought this code would do the job, but it just loops infinitely:
While dgvInCustomControl.Rows.Count = 0
Threading.Thread.Sleep(5000)
End While
My suspicion is that the main function is unable to determine how many rows there actually are in the datagridview, and that it will always add the row as the first item. Any help is appreciated on how to approach this problem!
You could raise an event from the custom control, after the BackgroundWorker has finished. Let the main class listen to that event and do whatever it needs to do when it fires.
Just keep in mind that updating windows controls from background threads is usually not working and that you should use delegate functions to invoke the update on the main thread.

Calling a form's load event when form is already loaded but has gained focus

I am creating a bike booking system in VB using winforms. I have two forms: frmBikeHire and frmBikeBookingsEdit.
On each form is a button with a click event to show and give focus to the other form.
frmBikeBookingsEdit.MdiParent = frmMDI_Main
frmBikeBookingsEdit.Show()
frmBikeBookingsEdit.Focus()
And
frmBikeHire.MdiParent = frmMDI_Main
frmBikeHire.Show()
frmBikeHire.Focus()
When a single form is open, the show command opens the other form and the load events from that form are run (refreshing the form). When the second form is already open, then the focus command brings the second form to the front. I also want the load events to run after the focus command so that the form is refreshed. Is there a simple way to re-run the load command?
I have worked this one out myself...
I have made the refresh form commands that are called on the load event, by changing them to Public Subs and then calling the refresh commands before bringing the form back into focus:
frmBikeBookingsEdit.MdiParent = frmMDI_Main
frmBikeBookingsEdit.refreshBookingDetailsGrid()
frmBikeBookingsEdit.refreshBookingsListGrid()
frmBikeBookingsEdit.Show()
frmBikeBookingsEdit.Focus()

Keep form on top of another form in modal fashion, but continue execution

I have a form in a vb.net windows form application called PolicyRefreshStatus.vb that has a ProgressBar control on it. From the main form called EditPolicy.vb I need to show PolicyRefreshStatus.vb over top of EditPolicy.vb - but the way things are wired I'm controlling the the ProgressBar and it's steps from logic inside EditPolicy.vb.
If I display the PolicyRefreshStatus.vb bar using the .show() method things work fine. The problem is if the user clicks back on the main form then PolicyRefreshStatus.vb losses focus. If I show PolicyRefreshStatus.vb as a modal form using .ShowDialog() then execution halts in EditPolicy.vb after the .ShowDialog() statement.
so for example in the code:
mPolicyRefreshStatus = New PolicyRefreshStatus
mPolicyRefreshStatus.pbMax = mPolicy.ClaimsUpdateMax
mPolicyRefreshStatus.ShowDialog()
mPolicy.UpdateFromFIS()
The line mPolicy.UpdateFromFIS() never executes because it's waiting for the PolicyRefreshStatus form to close.
How can I show PolicyRefreshStatus in a modal form but let execution continue in EditPolicy.vb?
You've got a couple of related options.
This first is to pass the unit of work to the progress bar in the form of a delegate or a class implementing an Interface. Something like this (not checked for correctness, just a rough example):
mPolicyRefreshStatus = New PolicyRefreshStatus
mPolicyRefreshStatus.pbMax = mPolicy.ClaimsUpdateMax
mPolicyRefreshStatus.UnitOfWork = AddressOf(mPolicy.UpdateFromFIS())
mPolicyRefreshStatus.ShowDialog()
Then within the progress form you can call back to the routine that actually does the work.
Another approach is to define events on your ProgressForm and then the owning/launching object can handle those events to do the work in. With this option you can create a fairly detailed set of events to be able to handle incremental work or cancels, but the concept is the same, youu are calling back from the progress form into launcher to perform the actual business logic.
You cannot show the form modally and let your routine continue. You must show the form Non-modally and then do your other stuff, closing the form when you've finished. Maybe a loop until the task has finished?
Using Show() with a parent form parameter will give you better usability. More like a tool window.

TabControl.SelectedIndex being changed, but SelectedIndexChanged even not firing

All,
I have a TabControl in an application that started behaving strangely. Some background...
This program was converted from VB6 to VB .NET 2008, and used to refer to forms using their class names. In other words, I might have a form class called frmFoo. In the code for the program you might see:
frmFoo.Show()
or
frmFoo.UserDefinedProperty = True
During some recent changes, I created variables to represent instances of my forms much like these:
Public MyForm as frmFoo
MyForm = New frmFoo
MyForm.Show()
In doing so, I also removed code from the form's Load event handler and put it in the form's constructor.
When the form loads, or when a document is loaded and should influence the TabControl's selected index, something like the following will not necessarily fire the SelectedIndexChanged event.
MyForm.tbsForm.SelectedIndex = ValueReadFromFile
...or...
MyForm.tbsForm.Tabs(ValueReadFromFile).Select
Sorry to be so wordy, but there's more. If I open the form and look at the TabControl to verify that it's been set properly, everything works like it's supposed to. The misbehaving TabControl is contained within another TabControl, so I have to click the parent TabControl to see it. If I can see it, and run a test, the test always works. If I can't see it, and run a test, the first test I run will not fire the event. ...paging Dr. Heisenberg...
It's almost as if the control has to be initialized first by changing the value or making it visible onscreen...I'm totally lost on this one. It's the most unusual behavior I've ever seen. And everything worked perfectly before I began using variables to represent forms and placed the Load event code into the form constructors.
Can anyone help, or at least put me out of my misery?
SH
-------------------------------------------------------------- Edit #2
I just performed a test after having attempted to eliminate some of the variability in the behavior. But I wanted to confirm the previously-stated behavior.
I opened the program and read a file. This file contained a value that should have triggered the event handler. Without making the control visible, I can change the SelectedIndex property of the tab control without the event firing.
I closed the program down again, and reopened it. This time, selected the parent tab that allowed the child tab (the one whose event I'm concerned with) to become visible. I then selected a different tab in the parent control, meaning that the child control was no longer visible. When I opened the same file as before, it fired the event.
I'm tempted to implement a flag that confirms that the control has been repainted or whether the parent tab has been displayed. I may have to fire the event in code if the flag isn't set.
I want to reiterate that everything worked when the program referred to the forms by their class names and much of the arrangement of controls on the forms was done in the load event. Now the program creates variables and the arrangement of the controls is done in the form's constructor. I'm sure this has something to do with the problem I'm having, but I can't understand how. Any wisdom to share?
MyForm.tbsForm.SelectedIndexChanged = ValueReadFromFile
doesn't make a lot of sense. Is tha trying to assign a handler to the SelectedIndexChanged event? or is ValueReadFromFile the name of the tab?
What you're saying is that you have two tab controls, say, A and B. Tab control B is contained within a tab of A, and unless A has the tab page selected that contains the tab control B, the SelectedIndexChanged event of B will not fire if you change its tab programatically?
In which different ways have you tried to select a tab within the child tab control, and when is this code being executed?

Informing the user that a DataGridView is being populated

I am writing a program in VB.Net to manage text messages sent through an API. It allows you to view messages in a datagridview and filter by date, sent/unsent etc...
To load the messages I'm executing an SQL statement and retrieving a DataTable which then gets set as the DataSource for my DataGridView control.
The problem is that depending on the filters selected the user could be selecting a lot of records and it would take some time for the DataSource to update. I want to inform the user of this load time by providing a progress bar or label of some kind.
I have used progress bars before when looping through data but this is loading it all at once. I thought of displaying a label when the user clicks to load the data and then hiding it when the data is loaded. But this happens instantaneously even when the data is still loading.
Is there an event on the DataGridView I can use perhaps? Something like .DataSourceLoadStart and .DataSourceLoadFinished.
I know I'm just making those events up... but hopefully it makes it clearer as to what I want.
You could set the label to be visible when load is clicked and try the: DataGridView.DataBindingComplete Event to hide it, this event gets called when the binding is complete.
MSDN Link - DataBindingComplete
A little off topic but... I wonder if you could attach a AJAX update panel with activity/loading image to a gridview? I don't think I've ever seen it done but here's a great application for it.