Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Search datagridview on user keypress

I'm trying to select the first row where the cell value starts with the same keychar the user pressed. That's the part that is giving me trouble.

Here's how I'm handling the event (updated with working solution):

private void dataGridView1_KeyPress(object sender, KeyPressEventArgs e)
{
    if (Char.IsLetter(e.KeyChar))
    {
        for (int i = 0; i < (dataGridView1.Rows.Count); i++)
        {
            if (dataGridView1.Rows[i].Cells["Name"].Value.ToString().StartsWith(e.KeyChar.ToString(), true, CultureInfo.InvariantCulture))
            {
                dataGridView1.Rows[i].Cells[0].Selected = true;
                return; // stop looping
            }
        }
    }
}

I'm sure it's something simple that I'm overlooking, but for the life of me can't figure out what it is.

EDIT

Updated the code with solution applied

like image 847
Johann J. Avatar asked Apr 28 '09 13:04

Johann J.


4 Answers

Might be a case issue, is the Value in Cells["Name"] start with a capital letter? Try using ToUpper or ToLower on both; or you could try StartsWith(e.KeyChar, true) to ignoreCase. If you are trying to select the row, you'll want to do dataGridView1.Rows[i].Selected = true

like image 197
SwDevMan81 Avatar answered Oct 03 '22 12:10

SwDevMan81


if (Char.IsLetterOrDigit(e.KeyChar))
{
    foreach (DataGridViewRow dgvRow in myDgv.Rows)
    {
        if (dgvRow.Cells["ColumnName"].FormattedValue
            .ToString().StartsWith(e.KeyChar.ToString(), true, CultureInfo.InvariantCulture))
        {
            dgvRow.Selected = true;
            break;
        }
    }
}

If the DGV is set up to allow Multi-Select then you'd obviously want to deselect any existing selection.

like image 35
xyz Avatar answered Oct 03 '22 11:10

xyz


The edited answer in the original question doesn't support jumping to the next letter if there are multiple instances of names starting with the same letter. Here is an edited answer which support this feature:

private void dataGridView1_KeyPress(object sender, KeyPressEventArgs e)
{
    if (Char.IsLetter(e.KeyChar))
    {
        int index = 0;
        // This works only if dataGridView1's SelectionMode property is set to FullRowSelect
        if (dataGridView1.SelectedRows.Count > 0 )
        {
            index = dataGridView1.SelectedRows[0].Index + 1
        }
        for (int i = index; i < (dataGridView1.Rows.Count + index); i++)
        {
            if (dataGridView1.Rows[i % dataGridView1.Rows.Count].Cells["Name"].Value.ToString().StartsWith(e.KeyChar.ToString(), true, CultureInfo.InvariantCulture))
            {
                foreach (var row in dataGridView1.Rows.Cast<DataGridViewRow>().Where(t => t.Selected))
                {
                    row.Selected = false;
                }
                dataGridView1.Rows[i % dataGridView1.Rows.Count].Cells[0].Selected = true;
                return; // stop looping
            }
        }
    }
}
like image 20
TBD Avatar answered Oct 03 '22 11:10

TBD


This is a VS2008 VB.NET DataGridView extension meant to do kind of what you are doing but using a TextBox for searching information (not designed with case in mind but could easily be added). This extension works so perhaps there is something that might be helpful. I did notice that your code selects a row using select where mine uses CurrentCell.

    <Runtime.CompilerServices.Extension()> _
Public Function PartSeek(ByVal GridView As DataGridView, ByVal ColumnName As String, ByVal Value As String, ByVal Part As Boolean) As Boolean
    Dim Located As Boolean = False

    If GridView.Columns.Contains(ColumnName) Then
        Dim SingleRow As DataGridViewRow
        If Part Then
            SingleRow = (From Rows In GridView.Rows.Cast(Of DataGridViewRow)() _
                         Where Rows.Cells(ColumnName).Value.ToString().Contains(Value)).FirstOrDefault
        Else
            SingleRow = (From Rows In GridView.Rows.Cast(Of DataGridViewRow)() _
                         Where Rows.Cells(ColumnName).Value.ToString() = Value).FirstOrDefault
        End If
        If Not IsNothing(SingleRow) Then
            If GridView.CurrentCell.RowIndex <> SingleRow.Index Then
                GridView.CurrentCell = GridView(0, SingleRow.Index)
            End If
            DirectCast(GridView.Parent, Form).ActiveControl = GridView
            Located = True
        End If
        Return Located
    Else
        Throw New Exception("Column '" & ColumnName & "' not contained in this DataGridView")
    End If

End Function
like image 33
user39074 Avatar answered Oct 03 '22 11:10

user39074