How to call multiple subs with a BackgroundWorker - vb.net

I have not yet used BackgroundWorker but believe I need to use these in my code.
My app does a lot of database work, running many SQL queries in sequence. My problem appears typical, that the main form becomes unresponsive.
I want to be able to display progress using a progressbar and a toolstripstatuslabel. I am doing this already, but without the BackgroundWorker.
My code is - unsurprisingly - divided into a several subs, which are called in sequence by the main form.
All the examples I have seen include just simple BackgroundWorker DoWork events. What is the correct way to deal with calling other code? Just call the modules as usual in the DoWork event? I do understand these must contain no user interface code.
Am using VB.Net 2010
Thanks!

Related

Is there a way to execute code in VB.NET after *any* event

In VB.NET, is there a way to execute code after any event for which I have written an explicit handler, other than placing a call as the last line of each individual event handler? In ASP.NET I can put code in PreRender but there is no equivalent of that in VB.NET because there is no page life cycle.
I understand that for desktop apps the model is very different and that PreRender doesn't fit the desktop model but I hoped it would illustrate what I meant. In ASP.NET I often determine whether controls are visible, or enabled, in PreRender, after events have been processed and the underlying database has changed as a result. It seems reasonable to want to do something similar in VB.NET - multiple events can alter the underlying database, and multiple controls may need refreshed as a result, so write a routine that determines the visibility and enablement of the controls, and call it after explicitly-handled events have been dealt with.
I've tried the form validating/validated events but can't make them work.

Exporting thousand lines from datagridview to excel using vb.net

Hi I'm currently having a datagridview with thousand (about 3000+) rows of record and 9 columns. I was using this method I found to export the datagridview to excel. There was no problem exporting hundred of rows but when it comes to thousand of rows, it hangs and it wouldn't respond to anything.
What problem could it be? and if there's any other way that is faster/better than this?
Thank you!
The code is being executed on the UI thread so of course your application would freeze while it's executing. If you want the UI to remain responsive then you'd have to execute the code on a secondary thread. The issue there is that the data is coming from a control, so that part at least must be executed on the UI thread.
I would suggest that one possibility is to use a BackgroundWorker and do the work in the DoWork event handler. You can set up a loop that calls ReportProgress, which raises the ProgressChanged event on the UI thread and allows you to get the data in pages, then write it out to your spreadsheet on the background thread. I'll follow up with an example.

.NET - Cross-Thread Call on DataGridView

I am new to multi-threading and I stumbled across an error which I was hoping someone could explain to me why was happening.
My initial program code did not have multi-threading and I was populating some charts with data from a datagridview. I was getting values like this:
Val = dgv.Rows(counter).Cells(columnName).Value
Since I was populating four charts using the same grid, I wanted to put this chart population process on multiple threads. I got an error when trying to update GUI elements (such as labels and a progress bar) and stumbled across this thread:
.NET Controls: Why aren't all calls thread-safe?
So my fix was to have the main thread update the GUI elements, and the backgroundworkers just report progress to the main thread.
However, I still getting a cross-thread error when trying to read the value using the function above. I'd like to know why this is the case.
I solved my problem using Invoke (which I believe is the correct way of doing it), ie. something like this:
dgv.Invoke(New ReadDGVCallBack(AddressOf ReadDGV), counter, "Name")
where "Name" is the column name.
However, I still am curious to know why I can't read a value from a datagridview from another thread. Since I am not modifying it, shouldn't it be fine if data is just being read? Could someone shed some light on this?
Thanks for all the help

An effective way to display multiple labels

I am looking for an effective, quick way to show multiple labels in a quick fashion. What's a good way to do this other than replacing all the .text properties of the labels one after another? It is my understanding that whenever you update a .text property the UI has to be repainted which will add to latency if you have 50+ controls to update.
I know threading is an option but when I tried this I didn't see much of a difference as I wasn't able to load 2 labels at once, I still had to wait for the UI thread before the labels would update. What other ways are there to effectively load 50+ labels quickly? The way it is now takes quite awhile(3-4s) and I feel this could be lowered. The information is being taken from a backend system so I don't have the option for datasets/etc.
You have to separate the code that retrieves the data from the database (which you do using a background thread) and the code that updates the UI (which should happen as quickly as possible because you don't want to block the UI for too long).
My suggestion would be to use the BackgroundWorker component to do retrieve the data for all 50 labels. When the BackgroundWorker raises the RunWorkerCompleted event you call the forms' SuspendLayout function, update all the values of the labels and then you call ResumeLayout. SuspendLayout stops a control from redrawing until you call ResumeLayout.
More info: BackgroundWorker, SuspendLayout, ResumeLayout

Issue with OpenFileDialog and threading

I just upgraded from VS 2005 to VS 2012. This is a new issue that I do not understand. I am using the default "Form1" class the VS automatically creates. I added a button to open a file open dialog and when I click the button I get this error:
Current thread must be set to single thread apartment (STA) mode before OLE calls can be >made. Ensure that your Main function has STAThreadAttribute marked on it. This exception >is only raised if a debugger is attached to the process.
I have added " to Public Class Form1:
<STAThread()> Public Class Form1
But I get this...
Attribute 'STAThreadAttribute' cannot be applied to 'Form1' because the attribute is not >valid on this declaration type.
I have searched but get some info telling me that I need to set the entry point (Form1 I believe) to be Single Thread Attribute but the above code does not work.
How?
The <STAThread()> attribute cannot be added to classes like your form. It only works when it is applied to the Main function, which is the entry point of your application.
But VB.NET hides this function from you because it is rare that one needs to mess with Main in a WinForms application. It is just needed to get the plumbing set up for your app, which the compiler can manage for you. This is controlled by the "Application Framework" checkbox in the project options. If this is checked, the compiler automatically generates the Main function and the required plumbing. You can disable this option, but it makes life quite a bit harder for the average WinForms developer because you'll have to write and maintain your own Main function.
The real question here is why this is a problem at all. The compiler-generated Main function for a WinForms application is always going to have the STAThread attribute applied to it. That is just how the WinForms framework is designed to run. If that is not happening, then there is something badly wrong with your project. I would recommend scrapping it and starting over letting Visual Studio create a new WinForms project from one of the built-in templates. Everything should Just Work™.
The other option, of course, is that you're trying to display the OpenFileDialog on a separate thread (other than your main UI thread). But from your description in the question (adding a button to the form to display the dialog), it doesn't sound like this is the case. Regardless, the solution is not to do that. For example, if you're using a BackgroundWorker to do work on a non-UI thread in order to keep the UI responsive, that's great, but you'll want to do all of the UI stuff like showing an OpenFileDialog on the main UI thread before invoking the BackgroundWorker. There is a way to set a particular thread's apartment state using the SetApartmentState function, but I really don't recommend showing an OpenFileDialog on a background thread.