Hi,
Simple question, hopefully there's a simple answer:
How can I maintain the same selected row even after a sort on a DataGridView
In other words, after new items have been added to the binding source and a sort has been forcefully been carried out (in the custom BindingList), how can I ensure that the selected row is the same row as the one selected before the sort
Bear in mind, I'm doing the sorting in a custom BindingList so I can't just handle the Sorted or SortCompare events and implement my own logic there.
Thanks,
Jiten

Maintaining the selected row after sorting a DataGridView
Reed Robison
That works perfectly. Thanks very much!
tamccann
-mark
DataGridView Program Manager
Microsoft
This post is provided "as-is"
Jimmy Bogard
I'll get someone to investigate this possibility and report back.
Set the CurrentCell property causes the grid to scroll that cell into view.
-mark
DataGridView Program Manager
Microsoft
This post is provided "as-is"
Thomas Roethlisberger
That looks good.
I'm not sure I follow what is going on here. Can you explain this a bit more Also note you don't want to store off the DataGridViewRow, but some data in the row (like a field in the row that corresponds to the primary key).
-mark
DataGridView Program Manager
Microsoft
This post is provided "as-is"
MKB
this
.itemsDataGridView.CurrentCell = rowToSelect.Cells[0];This still doesn't make the DataGridView automatically scroll to the selected row and bring it into view :(
Jean-Marc Flamand dit le_beluet
There are two issues.
First, I realized that the ColumnHeaderMouseClick event is too late -- the grid has already sorted the column, so you'll need to use an event prior to the click -- CellMouseDown. You can check the RowIndex being -1 for mouse down actions on the column header cells. You just need to keep track of what rows are selected.
The next issue is when handling the DataBindingComplete event -- while you can set a row as being selected with no problems, you probably really want to set the current cell as well. Setting the current cell in the DataBindingComplete event is ignored, so we have to set it after the event fires. The easiest way I know to do that is to use C# anonymous delegates and "post" the work that I want to do so that it will occur after the DataBindingComplete event.
Here is my code for my CellMouseDown and DataBindingComplete event. I'm assuming that only one row is selected. Also note that there is a big difference between a row being selected and keeping track of what current cell is, unless you have full row selection enabled.
-mark
private string customerID;
private void customersDataGridView_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
if (!String.IsNullOrEmpty(customerID) && e.ListChangedType == ListChangedType.Reset)
{
int row = customersBindingSource.Find("Customer ID", customerID);
customersDataGridView.BeginInvoke((MethodInvoker)delegate()
{
customersDataGridView.Rows[row].Selected = true;
customersDataGridView.CurrentCell = customersDataGridView[0, row];
});
}
}
private void customersDataGridView_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.RowIndex == -1)
{
customerID = customersDataGridView.SelectedRows[0].Cells["customerIDColumn"].Value.ToString();
}
}
DataGridView Program Manager
Microsoft
This post is provided "as-is"
bener
Hi Mark,
After stepping through the debugger (with checkpoints on SelectionChanged and DataBindingComplete event handlers) i've noticed that the SelectionChanged handler gets called twice BEFORE the DataBindingComplete (when my underlying BindingList calls OnListChanged). This means that the old selected row value is being lost.
Also, i've checked that the Find method is looking up the value in the new list and this works fine.
Thanks,
Jiten
Max Komarov
Do you have your custom bindinglist available where you can send it to me so I can try this out also I'm curious specifically on the SelectionChanged being fired twice. Look in the debugger and check the dgv.SelectedRows.Count property. When the grid receives a reset it actually removes all rows and then rebinds to the "new" list, so there might be an extra SelectionChanged event but the count of rows selected would be 0.
-mark
DataGridView Program Manager
Microsoft
This post is provided "as-is"
Destroy89
Thanks very much.
Here's some more information on my databinding implementation (just in case):
CustomSortableBindingList => BindingSource.DataSource => DataGridView.DataSource
Cheers,
Jiten
stebe000
Thanks for the suggestion Mark. Unfortunately it isn't working 100%.
I've had to use the ColumnHeaderMouseClick event because I couldnt find the ColumnHeaderMouseDown.
Seems as though it only works the first time a column is clicked for a sort. After this, it is the same previous row that is always coming up as the currently selected row (I've stepped through the debugger to verify this).
Here are the exact steps i'm following:
1. Create a local variable to store the Item ID.
2. Handle the ColumnHeaderMouseClick event:
3. Handle the DataBindingComplete event:
[1] - I get the currently selected row with the following code:
DataGridViewRow
row = null;if (this.itemsDataGridView.SelectedRows.Count > 0)
this.itemsDataGridView.SelectedRows[0];How does this sound to you
Also, on a similar note, I need to be able to maintain the selected row even after new rows have been added through the custom BindingList (note: I do a manual merge of items and then force a sort and OnListChanged [with ListChangedType.Reset] all within the custom BindingList). Any thoughts on how i coudl do this
Alex1123123
Hi Mark,
I am indeed storing a unique string value from the row's binded data.
In step 3.2, i mentioned that if the local variable has not been set then it is set for the first time there. Problem is, in step 2.2 the row always seems to return the same string ID as in step 3.2. This means that the first row is always the one being selected. Seems as though the SelectedRows is not being updated in time for the event. ( )
On a side note, how do I make the row I select programmatically to be in focus (and visible without scrolling) in the DataGridView
Thanks,
Jiten
kunalmukherjii
Hi Mark,
I'm stil having problems sorting out these issues.
I'd appreciate any further help.
Thanks,
Jiten
Jesse Cheng
Hi Mark,
I've emailed you the custom binding list implementation.
You're right about the extra SelectionChanged events, where the count of the rows selected is 0. In total, the event fires 3 times when a reset occurs.
Also, when the DGV first loads up, and is bound to, SelectionChanged fires 7 (!) times. Mind you, I do re-initialise the bindingsource at runtime when it first loads so this causes some additional events to be fired.
Thanks,
Jiten
John_C
I'm not sure I know where the problem is. I tried something similar -- In the SelectionChanged event I remember the customer ID like so:
I use the same DataBindingCompleted code as above. Next I put a button on my form that calls resetbindings and selection/focus remains correct. Can you debug your code a bit and ensure you are getting the correct "id" value. Also ensure that in your "Find" method you lookup the value using the new list.
private void customersDataGridView_SelectionChanged(object sender, EventArgs e)
{
if (customersDataGridView.SelectedRows.Count > 0)
{
customerID = customersDataGridView.SelectedRows[0].Cells["customerIDColumn"].Value.ToString();
}
}
-mark
DataGridView Program Manager
Microsoft
This post is provided "as-is"