93

I need to force the DataGridView to show the selected row.

In short, I have a textbox that changes the DGV selection based on what is typed into the textbox. When this happens, the selection changes to the matching row.

Unfortunately if the selected row is out of the view, I have to manually scroll down to find the selection. Does anyone know how to force the DGV to show the selected row?

Thanks!

kereberos
  • 1,253
  • 1
  • 10
  • 20

9 Answers9

163

You can set:

dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.SelectedRows[0].Index;

Here is the MSDN documentation on this property.

competent_tech
  • 44,465
  • 11
  • 90
  • 113
60

This one scrolls to the selected row without put it on top.

dataGridView1.CurrentCell = dataGridView1.Rows[index].Cells[0];
IgorOliveira
  • 1,639
  • 15
  • 14
  • 4
    Definitely more user-friendly than `DataGridView.FirstDisplayedScrollingRowIndex`, thanks! – Nolonar Jul 30 '15 at 14:24
  • 6
    Unlike FirstDisplayedScrollingRowInde, this also moves the row arrow to the correct row, selects row, and unselects any other row. – Polyfun Aug 21 '15 at 12:07
  • 1
    `dataGridView1.CurrentCell = dataGridView1.SelectedRows[0].Cells[0]` – Mahmood Dehghan Apr 08 '18 at 07:08
  • 2
    However, if the first column has been hidden, this WILL throw an exception. – sgriffin Jul 03 '18 at 14:44
  • Note that if the `.CurrentCell` is *already* the one that it's being changed to, it won't scroll it into view even if it's not currently visible. You can fix that by setting `dataGridView1.CurrentCell = null;` before setting it to the actual cell. – Matthew Watson Jul 27 '22 at 12:24
27

Consider also this code (uses the from competent_tech suggested way):

private static void EnsureVisibleRow(DataGridView view, int rowToShow)
{
    if (rowToShow >= 0 && rowToShow < view.RowCount)
    {
        var countVisible = view.DisplayedRowCount(false);
        var firstVisible = view.FirstDisplayedScrollingRowIndex;
        if (rowToShow < firstVisible)
        {
            view.FirstDisplayedScrollingRowIndex = rowToShow;
        }
        else if (rowToShow >= firstVisible + countVisible)
        {
            view.FirstDisplayedScrollingRowIndex = rowToShow - countVisible + 1;
        }
    }
}
Georg
  • 1,946
  • 26
  • 18
  • 3
    A very functional answer...worthy of far more votes. – ulatekh Aug 22 '16 at 01:49
  • 1
    I agree, so I have upvoted it! It works better than any of the other solutions. – JonP Dec 05 '16 at 12:24
  • 3
    Works great - I made rowToShow opptional and set it to the last row if not set by the caller. Now it scrolls to the bottom by default. Could add another signature to give it a better name. – rheitzman Sep 11 '17 at 17:49
  • 1
    Thanks. This works a lot better than other answers. Tip for other users: I modified it a bit to pass in firstVisible because my list was also being refreshed before I needed to call EnsureVisibleRow (after refreshing the DataGridView contents, FirstDiaplayedScrollingRowIndex was always reset to zero so I had to save it before the refresh) – Brian O Carroll May 10 '19 at 15:13
  • Small bug: the condition should be: `else if (rowToShow >= firstVisible + countVisible - 1)` (I just wrote the same solution because I missed this reply!) – P.W. Jun 08 '20 at 09:49
  • Hello @P.W., please check again. For example, if the first visible row is 3 and the window height is 5, 8 is the first invisible row (3 + 5). So we have to do when: `rowToShow >= firstVisible + countVisible (>= 8)` or `rowToShow > firstVisible + countVisible - 1 (> 7)` – Georg Jun 11 '20 at 11:40
  • Hi @Georg, yes you are right, sorry about that (and thanks). Maybe I confused `>=` with `>` at that time. I will go correct my code, despite it is working fine with this condition as well ;) – P.W. Jun 12 '20 at 12:33
11

Just put that line after the selecting the row:

dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.SelectedRows[0].Index;
Fischermaen
  • 12,238
  • 2
  • 39
  • 56
1
int rowIndex = -1;
foreach (DataGridViewRow row in dataGridView1.Rows)
{
    if (row.Cells[0].Value.ToString().Equals(searchString))
    {
        rowIndex = row.Index;
        break;
    }
}
if (rowIndex >= 0)
{
    dataGridView1.CurrentCell = dataGridView1[visibleColumnIndex, rowIndex];
}

visibleColumnIndex - selected cell must be visible

Dobry
  • 161
  • 5
1

Please note that setting FirstDisplayedScrollingRowIndex when your DataGridView is not enabled will scroll the list to desired row, but scrollbar will not reflect its position. Simpliest solution is re-enabling and disabling your DGV.

dataGridView1.Enabled = true;
dataGridView1.FirstDisplayedScrollingRowIndex = index;
dataGridView1.Enabled = false;
user3175253
  • 588
  • 4
  • 10
1

// This works, it's case sensitive and finds the first occurrence of search

    private bool FindInGrid(string search)
    {
        bool results = false;

        foreach (DataGridViewRow row in dgvData.Rows)
        {
            if (row.DataBoundItem != null)
            {
                foreach (DataGridViewCell cell in row.Cells)
                {
                    if (cell.Value.ToString().Contains(search))
                    {
                        dgvData.CurrentCell = cell;
                        dgvData.FirstDisplayedScrollingRowIndex = cell.RowIndex;
                        results = true;
                        break;
                    }

                    if (results == true)
                        break;
                }
                if (results == true)
                    break;
            }
        }

        return results;
    }
Mac
  • 176
  • 1
  • 3
0

Doing something like this:

dataGridView1.CurrentCell = dataGridView1.Rows[index].Cells[0];

will only work if the first column is visible. If it is hidden, you'll get an exception. This is safer:

var column = dataGridView1.CurrentCell != null ? dataGridView1.CurrentCell.ColumnIndex : dataGridView1.FirstDisplayedScrollingColumnIndex; dataGridView1.CurrentCell = dataGridView1.Rows[iNextHighlight].Cells[column];

This will reset the selection without scrolling if the target row is already on screen. It also preserves the current column choice which can matter in cases where you've allowed inline editing.

sgriffin
  • 337
  • 1
  • 9
0

I made the next search function it works wel for scrolling selections in display.

private void btnSearch_Click(object sender, EventArgs e)
{
  dataGridView1.ClearSelection();
  string strSearch = txtSearch.Text.ToUpper();
  int iIndex = -1;
  int iFirstFoundRow = -1;
  bool bFound = false;
  if (strSearch != "")
  {
    dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;

    /*  Select All Rows Starting With The Search string in row.cells[1] =
    second column. The search string can be 1 letter till a complete line
    If The dataGridView MultiSelect is set to true this will highlight 
    all found rows. If The dataGridView MultiSelect is set to false only 
    the last found row will be highlighted. Or if you jump out of the  
    foreach loop the first found row will be highlighted.*/

   foreach (DataGridViewRow row in dataGridView1.Rows)
   {
     if ((row.Cells[1].Value.ToString().ToUpper()).IndexOf(strSearch) == 0)
     {
       iIndex = row.Index;
       if(iFirstFoundRow == -1)  // First row index saved in iFirstFoundRow
       {
         iFirstFoundRow = iIndex;
       }
       dataGridView1.Rows[iIndex].Selected = true; // Found row is selected
       bFound = true; // This is needed to scroll de found rows in display
       // break; //uncomment this if you only want the first found row.
     }
   }
   if (bFound == false)
   {
     dataGridView1.ClearSelection(); // Nothing found clear all Highlights.
   }
   else
   {
     // Scroll found rows in display
     dataGridView1.FirstDisplayedScrollingRowIndex = iFirstFoundRow; 
   }
}

}