Click here to Skip to main content
15,893,644 members
Please Sign up or sign in to vote.
5.00/5 (2 votes)
See more:
I have a DataGridView control that I’m filling with data from a database. Since the queries have the possibility of returning a lot of data I decided to use a BackgroundWorker object to pull the data so my application wouldn’t appear to be frozen when the query was running. I can get that to work just fine but it didn’t solve my overall problem. After pulling the data I set the DataGridView’s Datasource to it and then call a method that sets up all kinds of formatting on the DataGridView object. It loops through the columns and rows and does things like set background color, alignment, and tool tips on cells based on the data. This is all quite time consuming and my application appears to freeze up when it runs. However I’m having trouble trying to get this into a BackgroundWorker. I’ve tried two methods...

Method One:
If I pass in my DataGridView object as an argument in the BackgroundWorker I get a cross-threading error when I try to set the DataSource. This is how I've always "packaged" things to go into a background worker and I haven't run into problems before...am I not doing it correctly?
VB
'The class I use to package the DataGridView
Private Class packageFormatGrid
      Public dt As DataTable 'Data to set to the grid
      Public dgv1 As DataGridView 'Data grid
End Class
'The class I package the datagridview in and call backgroundworker from
Private Sub CallFormat(ByRef dt as DataTable)
       Dim package As New packageFormatGrid
       package.dt = dt
       package.dgv1 = dgvOutput
       bgwFormat.RunWorkerAsync(package)
End Sub
'Do Work method...
Private Sub bgwFormat_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwFormat.DoWork
       Dim package As packageFormatGrid = CType(e.Argument, packageFormatGrid)
       package.dgv1.DataSource = package.dt
       'I have other code after this point, but the above statement causes
       'a cross-threading error for dgvOutput, which is the "packaged" dgv1
End Sub


Method Two:
If I declare a new DataGridView object and pass it to the RunWorkerComplete as the result, and there set my real DataGridView equal to it, I don’t get any errors, but my grid simply doesn’t fill with anything.
VB
'Set up a new datagridview object and pass it back to other thread in result
Private Sub bgwFormat_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwFormat.DoWork
       Dim package As packageFormatGrid = CType(e.Argument, packageFormatGrid)
       Dim dgv As New DataGridView
       dgv.DataSource = package.dt
       'method that loops columns and rows and formats the datagrid view object
       FormatOutputGrid(dgv)
       e.Result = dgv
End Sub
'On run worker complete, the code doesn't error out, but my grid doesn't display any data.
'Debugging reveals that it has the correct DataSource, but I can't access cell values
Private Sub bgwFormat_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgwFormat.RunWorkerCompleted
       Dim dgv As DataGridView = CType(e.Result, DataGridView)
       dgvOutput = dgv
End Sub


It’s Monday, so I’m suspicious that I’m just not thinking clearly and I’m missing something painfully obvious. When I google all I get is articles about pulling the data with a BackgroundWorker and nothing about formatting the grid. Does anyone have any ideas?
Posted

1 solution

You can NOT modify a GUI control from a background thread. All changes to a GUI control have to be done on the thread that created the control, which is the startup thread. This includes any formatting changes and even assigning the DataSource property.

Any formatting should be done by column properties, which don't take very long. You should, also, not be going through all of the rows setting stuff. This should be done, on demand, by handling mouse, format, and painting events.
 
Share this answer
 
Comments
Kschuler 21-Mar-11 12:38pm    
Thanks for your help. It's possible that my grid will have to format a table that has several hundred columns, which is one reason it takes so long. The only time that I'm looping through the rows as well is to set the cell color when the value of the cell is null. Do you know of a way to do that with a Column property?
Dave Kreskowiak 21-Mar-11 14:05pm    
I don't know anyone who wants to look through several hundred columns. You may have justification for it on a printed copy of a table, but on a monitor, that's just plain old painful to use.

As for cell coloring, you do not set the color of each cell individually. There is no way to format color by column. But, lik I said, you can use the formatting or painting events of the DGV. You can look at http://www.getdotnetcode.com/gdncstore/free/ColorDataGridViewCellsBasedOnData/ColorDataGridViewCellsBasedOnData.htm for an example based on the CellFormatting event.
Kschuler 21-Mar-11 14:43pm    
It's an application that helps a user build an SQL statement to use on our iSeries database. We loop through columns to dynamically change column headings from the maximum 10 character names to a more friendly name saved in a system file. I was able to move the null value issue to the cell formatting event, and I even moved the column heading formatting to the AddColumn event...but performance is still slow. Not sure what else I can do to speed it up at this point without removing the nice formatted headings. Thanks for your advice and the link to the CellFormatting article.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900