|
I have a DataGridView (dgvNotes) that is bound to a datasource via a BindingSource (m_NotesBindingSource).
Given this scenario: dgvNotes has 5 rows. When I select the 5th screen row (RowIndex=4), delete it, the CurrentRow changes to the row above it (RowIndex=3). This works as expected, except that this row does not have the highlight on it even though it is the CurrentRow.
I can see this behavior when I step into the code. I can also see the CurrentCell does contain the value of the 4th row on screen (RowIndex=3). I thought that if CurrencCell contained valid data, the SelectedRow would be set to the row that contains the CurrentCell.
| | VBCoder13 Friday, August 01, 2008 8:02 PM | Are you by any chance deleting the row programmatically?
If so, I think you have a point.
With older controls, such as the ListBox and ListView, handling deletion of items and selection was entirely down to the programmer. The delete key is not handled at all.
With the DataGridView a good deal of the work is done for you. As you may now, if you had pressed the Delete key to delete the row, everything works perfectly.
However, if you delete the row programmatically the Framework appears to be missing the programming logic to re-select the previous row, where you delete the last row in the control...
You can use the following routine to do this, which only makes sense where DataGridView.SelectionMode is FullRowSelect.
TheDataGridView.AllowUserToAddRowscan be either enabled or not (true or false).
void DeleteSelectedRow(DataGridView dgv)
{
// Determine row count, excludng any new row
int rowCount = (dgv.AllowUserToAddRows) ? dgv.Rows.Count - 1 : dgv.Rows.Count;
// Get index of currently selected row
int selectedIndex = (dgv.SelectedRows.Count == 1) ? dgv.SelectedRows[0].Index : -1;
// If no row selected or user is trying to delete new row, ignore request
if (selectedIndex == -1 || selectedIndex == rowCount)
{
return;
}
// Delete row
dgv.Rows.Remove(dgv.Rows[selectedIndex]);
rowCount--;
// If more rows and last row was deleted, select new last row
if (rowCount > 0 && selectedIndex == rowCount)
{
dgv.Rows[selectedIndex - 1].Selected = true;
}
} | | Daniel B· Monday, August 04, 2008 5:10 PM |
Unelss you change the DataGridView.SelectionMode to FullRowSelect, the DataGridView (dgv) is essentially working at the cell level, with the option to select whole rows.
So when you delete a row, it reverts to the selecting the first cell, in the next available row. This is by desgn and makes perfect sense in cell selection (& editing) mode.
If you had requested FullRowSelect, the 4th screen row,from your scenario, would be selected (try changing the property in the Designer to see this in action).
After deleting the row (in cell mode), you should actually find CurrentCell is referencing the first cell of the 4th on screen row, as opposed to the whole row (DataGridView.CurrentRow). | | Daniel B· Sunday, August 03, 2008 8:10 PM | Thanks for the answer Daniel, but I have FullRowSelect on.
This is from the Immediate window:
? dgvNotes.SelectionMode FullRowSelect
| | VBCoder13 Monday, August 04, 2008 12:55 PM | Are you by any chance deleting the row programmatically?
If so, I think you have a point.
With older controls, such as the ListBox and ListView, handling deletion of items and selection was entirely down to the programmer. The delete key is not handled at all.
With the DataGridView a good deal of the work is done for you. As you may now, if you had pressed the Delete key to delete the row, everything works perfectly.
However, if you delete the row programmatically the Framework appears to be missing the programming logic to re-select the previous row, where you delete the last row in the control...
You can use the following routine to do this, which only makes sense where DataGridView.SelectionMode is FullRowSelect.
TheDataGridView.AllowUserToAddRowscan be either enabled or not (true or false).
void DeleteSelectedRow(DataGridView dgv)
{
// Determine row count, excludng any new row
int rowCount = (dgv.AllowUserToAddRows) ? dgv.Rows.Count - 1 : dgv.Rows.Count;
// Get index of currently selected row
int selectedIndex = (dgv.SelectedRows.Count == 1) ? dgv.SelectedRows[0].Index : -1;
// If no row selected or user is trying to delete new row, ignore request
if (selectedIndex == -1 || selectedIndex == rowCount)
{
return;
}
// Delete row
dgv.Rows.Remove(dgv.Rows[selectedIndex]);
rowCount--;
// If more rows and last row was deleted, select new last row
if (rowCount > 0 && selectedIndex == rowCount)
{
dgv.Rows[selectedIndex - 1].Selected = true;
}
} | | Daniel B· Monday, August 04, 2008 5:10 PM | Oh, man!
I've updated my original post (above) as my routine runs into trouble if you called it from a button Click handler.
The problem is, if the user is allowed to add rows andthey have selected the new input row (the very last row in the dgv) but has not started entering any data, when the user clicks the button the dgv looses focus and it sets the CurrentRow property to the last real row, but leaves the selection on the new input row.......
This is a bug in the dgv, clear and simple but correcting the selection now is asking for trouble and may break existing users of the dgv, including the routine I provided, which relies on SelectedRows being as they were before the dgv looses focus (when user clicks button).
Instead, the dgv should work as most would expect. When it looses focus and the new input row is selected, which hasn't been edited,it should remain the CurrentRow and still be selected when focus returns.
| | Daniel B· Monday, August 04, 2008 6:29 PM | The problem presents itself 3 different ways:
1) When the delete key is pressed while the last row is selected 2) The BindingSource has a "sort" applied (m_CustomerNoteBindingSource.Filter = "status = 'A'"; ) and the "status" column is programmatically changed via: CurrentRow["status"] = "D"; 3) The row is deleted programmatically via: CurrentRow.Delete();
All 3 of these cause the "SelectedRow" to be removed from the DataGridView, and no new row becomes the "SelectedRow". I added code similar to your code that states: if RowCount > 0 and SelectedRows == 0 then dgvNotes.Rows[dgvNotes.Rows.Count - 1].Selected = true;.
So your post at least gives me comfort in knowing that someone else can re-create the problem.
Thanks for your help Daniel.
| | VBCoder13 Monday, August 04, 2008 9:59 PM | As mentioned, the Delete key works fine for me.
What version of the Framework are you using?
If it's not the 3.5, you might find applying a Framework service pack may get the Delete key working at least.
I you don't mind marking my post with code as an answer I would appreciate it as it does offer a solution to someone using Framework 3.5 who wants to delete rows programmatically.
| | Daniel B· Monday, August 04, 2008 10:14 PM | I've tried using Delete key with Framework 2.0 and no problem.
Actually, I first forget to set the SelectionMode to FullRowSelect and it did exactly what you described, highlighted the first cell in the previous row. This really does make me wonder whether you are doing something in your code that is causing this. In a clean project, do you hvae the same problem?
I can also find no evidence. searching Google. that this is an issue (would be a rather elementary mistake for Microsoft to make).
| | Daniel B· Tuesday, August 05, 2008 3:15 AM |
|