datagridview and row unsharing - c#

I've encountered a performance issue with the C# DataGridView control, which appears to be the result of the unsharing of a large number of rows. The DataGridView is bound to a bindingsource, which is, in turn, bound to a dataview. I've gone through the laundry list of dos and don'ts from the MSDN info (not using rows.count() etc), but I just can't get it to play the game.
Even if I start with a brand new DataGridView control, on a fresh form, and bind it to a bindingsource that has a basic test table as its source, just showing the form seems to cause all of the displayed rows to become unshared. Then, every single row I select causes that row to become unshared. I'm wondering if I'm wasting my time trying to prevent this?
In my actual DataGridView control, it's necessary for me to have at least one column that is not visible, which contains ID values. It's also necessary for me to search all the values in this column for a matching ID. It would appear that, as soon as I attempt to iterate through the values to find a match, this is causing every single row to become unshared. Is there a way to do this that does not cause all the rows to become unshared as I search?

Related

DataGridView Refresh - How to not re-write the whole grid?

After adding a row to a DataGrid, I would like to update my DataGridView (with the input source of said DataGrid) using that new row. However when I use .Update() and .Refresh(), the whole of the grid gets re-drawn. When refreshing relatively quickly (around 4 times per second), this creates an unpleasing jolty effect. I would like to find a way to add my row to the DataGridView, without re-drawing the whole thing, therefore removing the DataGridView.
C# Winforms
I think what you are looking for is a data binding.
https://learn.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-bind-data-to-the-windows-forms-datagridview-control?view=netframeworkdesktop-4.8
This means the DataGrid is bound to e.g. a DataTable.

Refresh Column order in DataGridView after adding column and using SetOrdinal

I have a DataGridView that shows summary data. It is bound to a BindingSource which is bound to a DataTable. Depending on the summary type selected by the user, the program may split the data into multiple columns. In my code, I update the existing column and add columns as needed. The new column, as expected, gets added to the end of the list and I use SetOrdinal to reposition it. The DataGridView, however never moves the column unless I blank and rebind the DataSource to the BindingSource as follows:
I add columns with the following code:
this.Columns.Add(newcolumn);
this.Columns[columnname].SetOrdinal(index++);
And I refresh the source as follows:
teamstats.UpdateColumn(teamstats.Columns[columnClicked].ColumnName);
bsTBAstats.DataSource = null;
bsTBAstats.DataSource = teamstats;
This is problematic, as after I refresh the DataGridView, I have to reapply my formats (cell formts and event handlers) for each of the columns which slows down the process significantly.
Is there a more efficient way to have the DataTable refresh the column order? If the user can reorder the columns manually, why can't I do it programmatically?
The best way I've found to accomplish what I asked above is to manually resort the columns in the DataGridView to match the order of the columns in the DataTable. The following codes shows the process I used:
foreach (DataColumn c in teamstats.Columns)
dgvTBAstats.Columns[c.ColumnName].DisplayIndex = teamstats.Columns.IndexOf(c);
Seems as though the binding process should automate this, but this works. Unfortunately, if the user has manually reordered the columns, that order is lost since the opposite is true and the DataTable doesn't get reordered to match the DataGridView.
I can't seem to find a better way to bind the column order.

update DataGridView without losing selection

I'm trying to update data I have in a datagridview (based on checks set by the user), without losing the selection (on which a calculation is made). This works for me, but is a lot slower than clearing the complete dgv, making a new datatable and binding it.
This is what I tried :
when the datagridview need to be completely updated (different amount of rows), I clear the datagridview, make a new datatable and bind it. This works nice and fast, but the selection is lost. It's no problem the selection is lost, because the data is completely new.
sometimes I only need to update the values in the datagridview (and I don't want to lose the selection). I tried to either update the values in the bound datatable (works) or the values in the datagridview directly (this also works). However, both are a lot slower than just making a whole new datagridview using the first method :-(
when updating the datagridview, I stop drawing the panel on which it is placed
all events that the datagridview fires are suspended
autoresize etc is off
Can anyone explain why updating the cellvalues is so much slower than redoing the whole thing?
Is there another way to do it without losing the selection? I could remember the selection and set it again, but then I lose the way/order cells and columns where selected.
I finally found where the big delay occured. I was completely focused on the DataGridView, but it turned out the delay happend in the DataTable that was bound to it.
In order to do it fast :
first set each row of the DataTable to BeginEdit, so changes are not acted upon. After updating the DataGridView, do not make your DataTable accept the changes, it will make you lose the selection in the DataGridView.
[code]
for (int Row = 0; Row < MyDataTable.Rows.Count; Row++) MyDataTable.Rows[Row].BeginEdit();
// do your changes in the DataGridView (not the DataTable) here
UpdateDataGridView();
// never accept the changes in the DataTable, it will lose the selection in the DataGridView. Problem is that the DataTable is never updated, but this is not a problem in my case.
//MyDataTable.AcceptChanges();
[/code]

Get the number of rows which contain a certain value in one of the columns and display the number in a label

I have a gridview and sqldatasource.
I want to display in a label, the number of rows from the gridview which contains a certain value in one of the columns (in the form_load event)
I thought about looping through all columns of the gridview but it will take a lot of time for this and maybe there's another way of doing this.
Can someone help me finding the "other way"?
Thanks,
Best solution would be to let the database handle filtering - you'll get much better performance that way than looping over the data on application server.
Perhaps create another SqlDataSource with an SQL statement containing appropriate WHERE condition and bind it to your label?

DataGrid problems. Using DataSet.Merge with "Edit Template"

I am trying to debug an issue with a WinForm application.
The application uses a DataGridView bound to a DataSet.
The user can select a row and click "Edit" and an Edit Form appears so the user can edit the row and save his changes.
If the DataGridView is sorted by one or more columns and the user edits a row more than once and changes that rows position in the DataGrid (by changing one of the sorted columns TWICE), the DataGridView gets out of sync and I get Exception errors.
Here is how the code is written:
When the user clicks a row and hits edit (the user may only select one row), that row is passed to the EditFom. The edit Form creates an empty DataSet and loads that Row. When the user is done, the calling form uses DataSet.Merge to merge those changes back into its DataSet.
Here are a couple of scenarios that tell me it is womething to do with the "merge" and sorting:
(Note, I never change the actual "sorting", I am talking about changing the value of one of the sorted by columns in one of the rows.)
If the user edits a row directly in the Grid and changes the value of one of the columns being used to sort, then changes it again, etc. The row moves around the Grid, like it should and when the user clicks save, everything saves fine.
If the user edits a row (directly in the Grid OR via the "template") and doesnt change any of the "sort" columns, just makes an edit (therby setting the "State" of the row to Modified, right...), THEN the user edits the row using the Template (which goes through the seperate DataSet and merges the data back when done), and changes one of the columns being sorted (when done, the grid should resort and the row should "move"), the row doesn't get REPAINTED, it stays in the same position in the grid that it was in before the template edit. (Although, the data saves fine and you can refresh the grid and it sorts properly.) Evidently, the DataGrid isn't being notified that the RowChanged in this scenario (or it is, but it isn't doing anything about it).
If the user edits a row directly in the Grid, change a sort column (the row moves), then edits the row using the template and changes that column again, we get the same results as 2, above. The data saves fine, but when the user leaves the edit template, the grid doesn't resort.
(This is the one that causes the Exception error.)
If the user edits a row using the template and changes a sort column and leaves the template, the datagrid resorts and the row moves properly. Then, if the user edits the SAME row using the Template Edit and changes the sort column AGAIN. When the user leaves the edit template, the datagrid doesn't resort and when the user saves the data and the grid refreshes, we get an error:
System.InvalidOperationException: DataTable internal index is corrupted: '5'.
And sometimes, we get an error complaining the primary key is missing.
Any advice on how to "debug" this? I feel like it has something to do with the "internediate" dataset the edit template uses and the "Merge". It is like the DataGrid datasource is getting out of sync with the DataGrid Rows.
I should have done some Google'ing before posting this. It seems to be a common error and I found a HUGE post about this on the MS site. Unfortunately, I haev tried most of their suggestions, but most likely I will find my answer there. I just wanted to make a note of this, in case anyone is interested:
http://social.msdn.microsoft.com/Forums/en/adodotnetdataproviders/thread/18544cd3-1083-45fe-b9e7-bb34482b68dd

Categories