none
Buscar en un datagridview

    Question

  • Hola, tengo el datagridview que me muestra todos los campos q deseo, pero deseo introducir un textbox y un boton, para hacer una especie de busqueda, la tabla consta de varios campos, pero deseo hacer la busqueda pr nombre, osea introducir el nombre en el textbox y buiscarlo en el gridview al dar click en el boton pero no se com hacerlo.

    saludos
    Monday, November 23, 2009 2:37 AM

Answers

  • Hola:

    Si estás utilizando Visual Studio 2008, se puede hacer fácilmente mediante LINQ y añadiéndole un método Find al control DataGridView mediante métodos de extensión.

    Inicia un nuevo proyecto de Visual Basic, y en el formulario de inicio inserta un control BindingNavigator, un control DataGridView, un control TextBox y un control Button. Deja sus nombres por defecto.

    Crea un nuevo módulo en tu proyecto para pegar el método de extensión:

    Option Compare Text

    Imports System.Runtime.CompilerServices

    Public Module DataGridViewExtensions

        Private m_listRows As List(Of DataGridViewRow)

    #Region "Find"

        ''' <summary>
        ''' La función devolverá una lista de objetos DataGridViewRow
        ''' que satisfagan el criterio de búsqueda especificado.
        ''' </summary>
        ''' <param name="dgv">Control DataGridView.</param>
        ''' <param name="fieldName">Nombre de la columna por donde se desea buscar.</param>
        ''' <param name="criterio">Valor con el criterio de búsqueda deseado.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <Extension()> _
        Public Function Find(ByVal dgv As DataGridView, _
                             ByVal fieldName As String, _
                             ByVal criterio As String) As List(Of DataGridViewRow)

            ' Comprobamos los valores de los parámetros.
            '
            If (fieldName = String.Empty) OrElse _
               (criterio = String.Empty) Then Return Nothing

            ' Para que funcione adecuadamente el operador Like, hay que establecer
            ' Option Compare Text a nivel del módulo donde aparezca la función,
            ' o a nivel del proyecto.
            '
            Try
                Dim query As IEnumerable(Of DataGridViewRow) = _
                From item As DataGridViewRow In dgv.Rows.Cast(Of DataGridViewRow)() _
                Where ((item.Cells(fieldName).Value IsNot DBNull.Value) AndAlso _
                       (CStr(item.Cells(fieldName).Value) Like criterio)) _
                Select item

                ' Devolvemos la consulta LINQ ejecutada.
                m_listRows = query.ToList()

                Return m_listRows

            Catch ex As Exception
                Return Nothing

            End Try

        End Function

        ''' <summary>
        ''' Hace que el control DataGridView se desplace a la posición indicada
        ''' dentro del conjunto de filas que satisfacen el criterio de búsqueda
        ''' especificado en el método Find.
        ''' </summary>
        ''' <param name="dgv"></param>
        ''' <param name="position"></param>
        ''' <remarks></remarks>
        <Extension()> _
        Public Sub Find(ByVal dgv As DataGridView, ByVal position As Int32)

            If m_listRows Is Nothing Then _
                Throw New InvalidOperationException( _
                    "Operación no válida. Establezca primero los criterios de búsqueda mediante el método Find.")

            ' Seleccionamos el elemento correspondiente a la
            ' posición actual especificada.
            '
            Dim row As DataGridViewRow = m_listRows.ElementAtOrDefault(position)

            If row IsNot Nothing Then
                ' Establecemos la celda actual.
                dgv.CurrentCell = dgv.Rows(row.Index).Cells(0)
                dgv.FirstDisplayedCell = dgv.CurrentCell
            End If

        End Sub

    #End Region

    End Module

    Ahora en el formulario de inicio, pega el siguiente código y modifica la cadena de conexión y consulta SQL de selección para que se adapte a tus necesidades:

    Imports System.Data.SqlClient

    Public Class Form1

        Private m_bs As BindingSource

        Private Sub Form1_Load(ByVal sender As Object, _
                               ByVal e As EventArgs) Handles MyBase.Load

            Dim dt As DataTable

            Using cnn As New SqlConnection( _
                "Data Source=(local);" & _
                "Initial Catalog=Prueba;" & _
                "Integrated Security=SSPI")

                Dim sql As String = "SELECT * FROM Clientes"

                Dim da As New SqlDataAdapter(sql, cnn)

                dt = New DataTable("Clientes")

                da.Fill(dt)

                DataGridView1.DataSource = dt

            End Using

            ' Creamos una instancia del objeto BindingSource
            m_bs = New BindingSource

            ' Instalamos el controlador de evento PositionChanged
            AddHandler m_bs.PositionChanged, AddressOf PositionChanged

            ' Asociamos el control BindingNavigator
            'con el control BindingSource.
            '
            BindingNavigator1.BindingSource = m_bs

        End Sub

        Private Sub Button1_Click( _
            ByVal sender As Object, _
            ByVal e As EventArgs) Handles Button1.Click

            m_bs.DataSource = Nothing

            Dim fieldName As String = "NombreColumnaDataGridView"
            Dim criterio As String = TextBox1.Text

            ' Recuperamos las filas que cumplan con el criterio especificado.
            '
            Dim query As List(Of DataGridViewRow) = _
              DataGridView1.Find(fieldName, criterio)

            ' Asignamos el origen de datos del objeto BindingSource.
            '
            m_bs.DataSource = query

        End Sub

        Private Sub PositionChanged(ByVal sender As Object, ByVal e As EventArgs)

            DataGridView1.Find(m_bs.Position)

        End Sub

    End Class

    Cuando hagas clic en el control Button, se hará una búsqueda por el campo de la columna del control DataGridView que hayas indicado. Si la columna por la que deseas buscar se llama DataGridViewTextBoxColumn23, ese será el nombre que tendrás que especificar en la variable fieldName.

    Como criterio de búsqueda, puedes utilizar cualquier valor válido, pero si por ejemplo deseas buscar aquellos Clientes cuyo nombre comiencen por Jose, tienes que especificar el siguiente criterio de búsqueda en el control TextBox1 Jos*, es decir, el nombre tiene que acabar con el signo * para utilizarlo de comodín.

    Una vez que se encuentre registros coincidentes con el criterio de búsqueda especificado, puedes posicionarte en las filas encontradas pulsando los clásicos iconos existentes en el control BindingNavigator, que para ese motivo se ha insertado en el formulario.

    En fin, espero que te sea de utilidad el ejemplo que te he mandado, y si es así, no dudes en marcar ésta respuesta como satisfactoria.

    Un saludo


    Enrique Martínez [MS MVP - VB]
    Monday, November 23, 2009 2:02 PM
    Moderator

All replies

  • hola

    En realidad hay dos o tres tecnicas que podrias aplicar:


    - podrias recuperar el origen de datos que utilziaste para bindear el datagridview en principio y luego utilziar el metodo Filter del DataTable

    por ejemplo

    Dim dt As DataTable = CType(DataGridView1.DataSource, DataTable)

    Dim foundRows() As DataRow = dt.Select("Campo = filtro")

    DataGridView1.DataSource = foundRows


    DataTable.Select




    - otra tecnica podrias ser usando el BindingSource, y su propiedad Filter

    Nota, esta igual puede cambiar si es que has utilziado un BindingSource para asignar la primera vez los datos, ya que directamente podrias filtrar de este componente

    BindingSource. Filter




    - la otra seria ir directo contra la db y aplicar el filtro en una consulta sql por ahi usando los objetos de ado.net, o como estes conectandote a la db, recuperas un objeto, por ejemplo DataTable nuevo y lo bindeas a la grilla

    esto seria ahcer una consulta con filtro, pasandole parametros

    SELECT * FROM Tabla WHERE Campo1 = @filtro1 AND Campo2 = @filtro2

    si ejecutas este select y recupoeras los datoas en un datatable, al bindearlo a al grilla veras los datos filtrados

    esta desde mi punto de vista seria la que yo implementaria ya que me gusta tener control sobre el codigo, y saber bien como se filtra, por ahi requiera mas lecturas a la db, pero no creo que sean aplicacion de alta performace como para que esto afecte una lecturas de mas para recuperar un set de datos cuando se aplica el filtro


    saludos
    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Monday, November 23, 2009 3:04 AM
  • Hola:

    Si estás utilizando Visual Studio 2008, se puede hacer fácilmente mediante LINQ y añadiéndole un método Find al control DataGridView mediante métodos de extensión.

    Inicia un nuevo proyecto de Visual Basic, y en el formulario de inicio inserta un control BindingNavigator, un control DataGridView, un control TextBox y un control Button. Deja sus nombres por defecto.

    Crea un nuevo módulo en tu proyecto para pegar el método de extensión:

    Option Compare Text

    Imports System.Runtime.CompilerServices

    Public Module DataGridViewExtensions

        Private m_listRows As List(Of DataGridViewRow)

    #Region "Find"

        ''' <summary>
        ''' La función devolverá una lista de objetos DataGridViewRow
        ''' que satisfagan el criterio de búsqueda especificado.
        ''' </summary>
        ''' <param name="dgv">Control DataGridView.</param>
        ''' <param name="fieldName">Nombre de la columna por donde se desea buscar.</param>
        ''' <param name="criterio">Valor con el criterio de búsqueda deseado.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <Extension()> _
        Public Function Find(ByVal dgv As DataGridView, _
                             ByVal fieldName As String, _
                             ByVal criterio As String) As List(Of DataGridViewRow)

            ' Comprobamos los valores de los parámetros.
            '
            If (fieldName = String.Empty) OrElse _
               (criterio = String.Empty) Then Return Nothing

            ' Para que funcione adecuadamente el operador Like, hay que establecer
            ' Option Compare Text a nivel del módulo donde aparezca la función,
            ' o a nivel del proyecto.
            '
            Try
                Dim query As IEnumerable(Of DataGridViewRow) = _
                From item As DataGridViewRow In dgv.Rows.Cast(Of DataGridViewRow)() _
                Where ((item.Cells(fieldName).Value IsNot DBNull.Value) AndAlso _
                       (CStr(item.Cells(fieldName).Value) Like criterio)) _
                Select item

                ' Devolvemos la consulta LINQ ejecutada.
                m_listRows = query.ToList()

                Return m_listRows

            Catch ex As Exception
                Return Nothing

            End Try

        End Function

        ''' <summary>
        ''' Hace que el control DataGridView se desplace a la posición indicada
        ''' dentro del conjunto de filas que satisfacen el criterio de búsqueda
        ''' especificado en el método Find.
        ''' </summary>
        ''' <param name="dgv"></param>
        ''' <param name="position"></param>
        ''' <remarks></remarks>
        <Extension()> _
        Public Sub Find(ByVal dgv As DataGridView, ByVal position As Int32)

            If m_listRows Is Nothing Then _
                Throw New InvalidOperationException( _
                    "Operación no válida. Establezca primero los criterios de búsqueda mediante el método Find.")

            ' Seleccionamos el elemento correspondiente a la
            ' posición actual especificada.
            '
            Dim row As DataGridViewRow = m_listRows.ElementAtOrDefault(position)

            If row IsNot Nothing Then
                ' Establecemos la celda actual.
                dgv.CurrentCell = dgv.Rows(row.Index).Cells(0)
                dgv.FirstDisplayedCell = dgv.CurrentCell
            End If

        End Sub

    #End Region

    End Module

    Ahora en el formulario de inicio, pega el siguiente código y modifica la cadena de conexión y consulta SQL de selección para que se adapte a tus necesidades:

    Imports System.Data.SqlClient

    Public Class Form1

        Private m_bs As BindingSource

        Private Sub Form1_Load(ByVal sender As Object, _
                               ByVal e As EventArgs) Handles MyBase.Load

            Dim dt As DataTable

            Using cnn As New SqlConnection( _
                "Data Source=(local);" & _
                "Initial Catalog=Prueba;" & _
                "Integrated Security=SSPI")

                Dim sql As String = "SELECT * FROM Clientes"

                Dim da As New SqlDataAdapter(sql, cnn)

                dt = New DataTable("Clientes")

                da.Fill(dt)

                DataGridView1.DataSource = dt

            End Using

            ' Creamos una instancia del objeto BindingSource
            m_bs = New BindingSource

            ' Instalamos el controlador de evento PositionChanged
            AddHandler m_bs.PositionChanged, AddressOf PositionChanged

            ' Asociamos el control BindingNavigator
            'con el control BindingSource.
            '
            BindingNavigator1.BindingSource = m_bs

        End Sub

        Private Sub Button1_Click( _
            ByVal sender As Object, _
            ByVal e As EventArgs) Handles Button1.Click

            m_bs.DataSource = Nothing

            Dim fieldName As String = "NombreColumnaDataGridView"
            Dim criterio As String = TextBox1.Text

            ' Recuperamos las filas que cumplan con el criterio especificado.
            '
            Dim query As List(Of DataGridViewRow) = _
              DataGridView1.Find(fieldName, criterio)

            ' Asignamos el origen de datos del objeto BindingSource.
            '
            m_bs.DataSource = query

        End Sub

        Private Sub PositionChanged(ByVal sender As Object, ByVal e As EventArgs)

            DataGridView1.Find(m_bs.Position)

        End Sub

    End Class

    Cuando hagas clic en el control Button, se hará una búsqueda por el campo de la columna del control DataGridView que hayas indicado. Si la columna por la que deseas buscar se llama DataGridViewTextBoxColumn23, ese será el nombre que tendrás que especificar en la variable fieldName.

    Como criterio de búsqueda, puedes utilizar cualquier valor válido, pero si por ejemplo deseas buscar aquellos Clientes cuyo nombre comiencen por Jose, tienes que especificar el siguiente criterio de búsqueda en el control TextBox1 Jos*, es decir, el nombre tiene que acabar con el signo * para utilizarlo de comodín.

    Una vez que se encuentre registros coincidentes con el criterio de búsqueda especificado, puedes posicionarte en las filas encontradas pulsando los clásicos iconos existentes en el control BindingNavigator, que para ese motivo se ha insertado en el formulario.

    En fin, espero que te sea de utilidad el ejemplo que te he mandado, y si es así, no dudes en marcar ésta respuesta como satisfactoria.

    Un saludo


    Enrique Martínez [MS MVP - VB]
    Monday, November 23, 2009 2:02 PM
    Moderator
  • hola

    Enrique muy bueno el ejemplo, la verdad te pasaste.

    habai analziado sugerirle que use Linq para esta operacion pero me surgieron dudas en como re-bindearia el resultado obtenido de la consulta nuevamente a la grilla

    segun veo en el ejemplo que has armado en le metodo

    Public Function Find(ByVal dgv As DataGridView, _
                             ByVal fieldName As String, _
                             ByVal criterio As String) As List(Of DataGridViewRow)

    este devuelve una lista de DataGridViewRow, lo cual imagino podrias asignar al DataGridView, y mostrar el resultado del filtro.

    Pero que pasaria si quiere volver a filtrar o quitar el filtro, en este caso pierde los datos originales, y deveria detectar este caso y volver a consulta la db.

    Por eso me entraron dudas y no sugeri Linq, porque no se me ocurrio como cerrar el ejemplo.

    saludos
    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Monday, November 23, 2009 2:24 PM
  • hola

    por ahi sea algo avanzado, y lo que tiene de malo es que esta en c#, pero por ahi analizandolo puedes sacar algunas ideas

    DataGridView Filter Popup


    tambien podrias ayudarte de estas tool para convertir el codigo
    Convert C# to VB.NET
    Code Converter

     



    saludos
    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Monday, November 23, 2009 2:26 PM
  • "Leandro Tuttini" escribió:

    > segun veo en el ejemplo que has armado en le metodo
    > este devuelve una lista de DataGridViewRow, lo cual
    > imagino podrias asignar al DataGridView, y mostrar
    > el resultado del filtro.
    >

    ¡Hombre! Si el resultado del método se lo asignas al control DataGridView, entonces éste ya no estaría enlazado con el control DataTable, como así se hizo en un principio en el ejemplo que he publicado, aparte que no te gustaría el resultado cuando ejecutes

        DataGridView1.DataSource = query


    > Pero que pasaria si quiere volver a filtrar o quitar el filtro,
    > en este caso pierde los datos originales, y deveria detectar
    > este caso y volver a consulta la db.

    En primer lugar, el ejemplo no está filtrando; está buscando objetos DataGridViewRow mediante un criterio especificado.

    Si el resultado de la búsqueda no devuelve ningún objeto DataGridViewRow, pues no sucedería nada, ya que el valor de la consulta devolvería 0, por tanto, el valor de la propiedad Position del objeto BindingSource utilizado sería -1.

    De todas maneras, haz una prueba y busca primero registros que sabes que están ahí, y después especifica un criterio de búsqueda que sepas de antemano que no existen registros.

     


    Enrique Martínez [MS MVP - VB]
    Monday, November 23, 2009 4:13 PM
    Moderator