Windows Develop Bookmark and Share   
 index > Windows Forms General > Strange backgroundworker and datagridview problem.
 

Strange backgroundworker and datagridview problem.

Hi,

I'm working on a program to read in a large table and then making a pivot table (I'm programmatically adding rows and colums to the datgridview) out of it and displaying it to the user in a datagridview.

To not make the user think the program has hung I'm displaying a marquee style progress bar and loading the the dataset and displaying the pivoted data in a backgroundworker thread.

The weird thing is the code runs perfectly if the datagridview doesn't need scrollbars. If enough rows / columns are added so that scrollbars are needed the program freezes after the grid is made and the backgroundWorker1_RunWorkerCompleted code block isn't reached (but it is without scrollbars). I'm pretty sure it's to do with the fact that it's in a thread. Before I put the code in a thread it ran with no problems.

Any ideas?

Thanks.
Kybalion  Thursday, October 25, 2007 11:27 AM

For clarification let me remind you that the BWC is not for updating the UI on a background thread but instead for doing work on a background thread and then updating the UI thread with the results. So when you say that you are doing the update in the BWC thread don't you really mean you are doing your non-UI processing in the BWC and then calling ReportProgress to update the grid on the UI thread? You can not, under any circumstances, update the UI on any thread other than the thread that created it. This is a common flaw in people's thinking of the UI. Many people believe that if they have to update the UI and it'll take 10 seconds to do so then they should use a secondary thread but that is incorrect. If it takes you 10 seconds to update a UI then it will still take that long irrelevant of threading. Only the non-UI work can be pushed to a background thread. Assuming we are on the same page here can you specify what work you're doing on the UI side when the progress changed event is raised? A summary of the work done in the BWC thread would also be useful.

As a side note please be aware that a marquee in absolutely no way conveys to a user that the program has not hung. We have all sat at a wait cursor ora "cancelling operation" dialog with animation on a hung application. Using threading makes it more likely that your users will not be aware of a hung app rather than letting them know it has hung. Because the UI will continue to pump messages even if we put our secondary thread into an infinite loop.

If your grid takes a long time to update then you might want to consider an alternative UI instead. Using paging you can dramatically cut down on the data to be displayed. A grid with more than a screen full or two of data is not that useful and just confuses users in general. Filtering and paging eliminate some of these issues. Using either also reduces the amount of time an update takes to occur and can remove the need for BWC (and your problem) altogether. Of course just caching the data (if it isn't too bad) also eliminates the need for a background update.

Another alternative is to use the BWC to update the data in the background but still allow the user to interact with the UI (aka no marquee). This is predominantly one of the strengths of BWC. This is especially useful if the operation takes a while because the user might not even care about the grid but would have to wait for the update anyway. It depends on how your application is laid out. If you go this route then you would update the grid in blocks (say 1, 5 or 10 rows at a time) as the data is processed on the background thread. Meanwhile the user can interact with the application and potentially cancel the updating process. You should provide some sort of indicator that the grid is still updating and when it completes so the user knows when it is safe to continue. The Add/Remove Progarms list in Vista (and maybe XP, can't remember) is an example on how NOT to do this. The GAC assembly list in Reflector is also an example of a bad way to do background updating. In both of these cases the user has no way to know when the list is finished populating so they don't know if the item they're looking for doesn't exist or just hasn't been displayed yet. But they do provide the cancellation option which is good since I don't need to see the entire list before I make a decision necessarily.

Michael Taylor - 10/25/07

http://p3net.mvps.org

TaylorMichaelL  Thursday, October 25, 2007 12:00 PM

For clarification let me remind you that the BWC is not for updating the UI on a background thread but instead for doing work on a background thread and then updating the UI thread with the results. So when you say that you are doing the update in the BWC thread don't you really mean you are doing your non-UI processing in the BWC and then calling ReportProgress to update the grid on the UI thread? You can not, under any circumstances, update the UI on any thread other than the thread that created it. This is a common flaw in people's thinking of the UI. Many people believe that if they have to update the UI and it'll take 10 seconds to do so then they should use a secondary thread but that is incorrect. If it takes you 10 seconds to update a UI then it will still take that long irrelevant of threading. Only the non-UI work can be pushed to a background thread. Assuming we are on the same page here can you specify what work you're doing on the UI side when the progress changed event is raised? A summary of the work done in the BWC thread would also be useful.

As a side note please be aware that a marquee in absolutely no way conveys to a user that the program has not hung. We have all sat at a wait cursor ora "cancelling operation" dialog with animation on a hung application. Using threading makes it more likely that your users will not be aware of a hung app rather than letting them know it has hung. Because the UI will continue to pump messages even if we put our secondary thread into an infinite loop.

If your grid takes a long time to update then you might want to consider an alternative UI instead. Using paging you can dramatically cut down on the data to be displayed. A grid with more than a screen full or two of data is not that useful and just confuses users in general. Filtering and paging eliminate some of these issues. Using either also reduces the amount of time an update takes to occur and can remove the need for BWC (and your problem) altogether. Of course just caching the data (if it isn't too bad) also eliminates the need for a background update.

Another alternative is to use the BWC to update the data in the background but still allow the user to interact with the UI (aka no marquee). This is predominantly one of the strengths of BWC. This is especially useful if the operation takes a while because the user might not even care about the grid but would have to wait for the update anyway. It depends on how your application is laid out. If you go this route then you would update the grid in blocks (say 1, 5 or 10 rows at a time) as the data is processed on the background thread. Meanwhile the user can interact with the application and potentially cancel the updating process. You should provide some sort of indicator that the grid is still updating and when it completes so the user knows when it is safe to continue. The Add/Remove Progarms list in Vista (and maybe XP, can't remember) is an example on how NOT to do this. The GAC assembly list in Reflector is also an example of a bad way to do background updating. In both of these cases the user has no way to know when the list is finished populating so they don't know if the item they're looking for doesn't exist or just hasn't been displayed yet. But they do provide the cancellation option which is good since I don't need to see the entire list before I make a decision necessarily.

Michael Taylor - 10/25/07

http://p3net.mvps.org

TaylorMichaelL  Thursday, October 25, 2007 12:00 PM
Thanks for the reply. It was very helpful! Basically I've been told that a marquee style bar would be enough, so I put the code that gets the dataset in a thread, when the thread is finished RunWorkerCompleted calls a metod to populate the datagrid.

Thanks again
Kybalion  Thursday, October 25, 2007 2:55 PM

So you are updating the datagrid in the RunWorkerCompleted event handler which runs on the UI thread. In that case threading is not an issue at all here. Note that if the dataset can be retrieved in a fraction of a second or less than using a secondary thread is not worth the overhead.

What is confusing me is that in your original post you said the event wasn't being raised if you populated the grid with more data than could be displayed. How can the grid be populated without going through the event handler?

Could you perhaps post some pseudo code with what you're doing in your DoWork handler along with the RWC handler?

Michael Taylor - 10/25/07

http://p3net.mvps.org

TaylorMichaelL  Thursday, October 25, 2007 3:09 PM
Here's my DoWork and RunWorkerCompleted


Code Block

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
myDS = GetData(select, connectionString);
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
PivotTable();
}



The dataset myDS takes about 9 - 10 seconds to retrieve. As I said though, it works fine now. The progress bar continues to move while the Dataset is being filled and the pivoted data is being displayed fine in the datagridview.


Kybalion  Thursday, October 25, 2007 3:58 PM

So do you still have the problem where the grid does not populate properly if scrollbars are shown?

Michael Taylor - 10/25/07

http://p3net.mvps.org

TaylorMichaelL  Thursday, October 25, 2007 4:03 PM
Nope. It's scrolling fine as well
Kybalion  Thursday, October 25, 2007 4:08 PM

You can use google to search for other answers

Custom Search

More Threads

• Drag and Drop across TabPages in a TabControl
• VB TreeView - Daft Newbie:(
• Solution-Explorer > Embedded-Resource Files > How can I access them ?
• DataGridView - Combobox Column
• DataGridView EDITING and EDITING in VB 6.0 DataGrid
• Creating a GetEnumerator method
• Minumum Memory Requirements for an application
• create and display form using C++
• shortcut menu, left click, add menu items in reverse order
• Print Windows Form