none
Filtrar coincidencias de texto de columna en datagridview

    Pregunta

  • Saludos.

    Tengo un datagridview1 y un textbox llamado txtbuscar, lo que necesito es que al escribir en el textbox  filtre el datagridview previamente llenado desde mysql. el datagridview se llena con las siguientes columnas: idproducto, codinterno, codproducto, nombre, ubicacion, pcosto, pventa, stock.

    quiero filtrar la columna nombre pero no el texto en orden, ejemplo: si se llama juan perez castro miranda, si escribo en el txtbuscar miranda juan que me aparezcan las coincidencias, si escribo miranda castro igual.

    mi codigo en vb.net es:

     Function filtro(ByVal busqueda As String) As DataTable
            Dim dt As New DataTable
            Dim da As New MySqlDataAdapter("SELECT idproducto,codinterno,codproducto,nombre,ubicacion,marca,rubro,pcosto,pventa,stock FROM productos", conector)
            da.Fill(dt)
            Dim temp As New BindingSource
            temp.DataSource = dt
            DataGridView1.DataSource = temp
            Dim descript As String()
            descript = Split(txtbuscar.Text)
            If txtbuscar.Text <> "" Then
                For Each busqueda In descript
                    If txtbuscar.Text <> "" Or txtbuscar.Text = "" Then
                        Dim filter As String = "nombre LIKE '%" & busqueda & "%'" & _
                        "or marca LIKE '%" & busqueda & "%'" & _
                        "or rubro LIKE '%" & busqueda & "%'" & _
                       "or codinterno LIKE '%" & busqueda & "%'" & _
                        "or codproducto LIKE '%" & busqueda & "%'"
                        DataGridView1.Columns("marca").Visible = False
                        DataGridView1.Columns("rubro").Visible = False
                        DataGridView1.Columns("codinterno").Width = 80
                        DataGridView1.Columns("codproducto").Width = 80
                        DataGridView1.Columns("stock").Width = 60
                        DataGridView1.Columns("idproducto").Width = 40
                        DataGridView1.Columns("nombre").Width = 580
                        temp.Filter = filter
                    End If
                Next
            End If
    
            Return dt
        End Function

     Private Sub txtbuscar_TextChanged(sender As Object, e As EventArgs) Handles txtbuscar.TextChanged
            conector.Close()
            If filtro(txtbuscar.Text).Rows.Count > 0 Then
                DataGridView1.DataSource = filtro(txtbuscar.Text.Trim)
            End If
        End Sub

    sábado, 24 de diciembre de 2016 16:12

Respuestas

  • zabino,

    No es para nada óptimo -a menos que sea necesario- que teniendo los datos vinculado a un origen filtres contra la base de datos cuando podrías hacerlo sobre los datos en memoria, filtras por cada palabra e incluso llamas dos veces a la función filtro(), no suena bien, ¿verdad?

    Respecto a buscar palabras sin importar el orden en que se encuentran dentro de la cadena, debes definir una expresión de filtro por cada palabra combinando cada condición con el operador lógico AND (operador inclusivo), lo mismo podrías hacer para todas las columnas, veamos un ejemplo:

    Vamos a implementar un procedimiento Function que retorne un tipo DataTable conteniendo los datos (todas las filas) que serán vinculados contra la grilla de datos a través de la propiedad DataSource, la carga inicial la podrías invocar en el evento Load del formulario o donde mejor veas conveniente:

    Private Function ObtenerProductos() As DataTable
    
    	Try
    		Using cn As New MySqlConnection("Cadena de conexión")
    			Dim ConsultaSQL As String = "SELECT idproducto, codinterno, codproducto, nombre, 
    				ubicacion, marca, rubro, pcosto, pventa, stock FROM productos"
    
    			Dim da As New MySqlDataAdapter(ConsultaSQL, cn)
    			Dim dt As New DataTable
    
    			da.Fill(dt)
    
    			Return dt
    		End Using
    	Catch ex As Exception
    		MessageBox.Show(ex.Message)
    
    		Return Nothing
    	End Try
    
    End Function
    
    
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    	
    	'Vincular datos a la grilla (todas las filas) al cargar el formulario
    	DataGridView1.DataSource = ObtenerProductos()
    	
    End Sub

    Ahora vamos a implementar un procedimiento Sub que permita realizar el filtro contra el origen de datos:

    Private Sub FiltrarDatos(Texto As String)
    
    	Dim dt = DirectCast(DataGridView1.DataSource, DataTable)
    	Dim Filtro As String = String.Empty
    
    	For Each Palabra As String In Texto.Split(New Char() {" "c},
    							StringSplitOptions.RemoveEmptyEntries)
    		Filtro += String.Format("nombre LIKE '%{0}%' AND ", Palabra)
    	Next
    
    	Filtro = String.Format("({0})", IIf(String.IsNullOrEmpty(Filtro),
    						"nombre LIKE '%%'",
    						Filtro.TrimEnd(New Char() {"A", "N", "D", " "})))
    
    	Filtro += String.Format(" OR marca LIKE '%{0}%'", Texto.Trim())
    	Filtro += String.Format(" OR rubro LIKE '%{0}%'", Texto.Trim())
    	Filtro += String.Format(" OR codinterno LIKE '%{0}%'", Texto.Trim())
    	Filtro += String.Format(" OR codproducto LIKE '%{0}%'", Texto.Trim())
    
    	dt.DefaultView.RowFilter = Filtro
    
    End Sub

    Finalmente invocamos el procedimiento FiltrarDatos():

    Private Sub txtBuscar_TextChanged(sender As Object, e As EventArgs) Handles txtBuscar.TextChanged
    
    	Dim txt As TextBox = DirectCast(sender, TextBox)
    
    	FiltrarDatos(txt.Text)
    
    End Sub


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    • Propuesto como respuesta Joyce_ACModerator lunes, 26 de diciembre de 2016 16:21
    • Marcado como respuesta zabino martes, 27 de diciembre de 2016 14:59
    domingo, 25 de diciembre de 2016 18:53

Todas las respuestas

  • zabino,

    No es para nada óptimo -a menos que sea necesario- que teniendo los datos vinculado a un origen filtres contra la base de datos cuando podrías hacerlo sobre los datos en memoria, filtras por cada palabra e incluso llamas dos veces a la función filtro(), no suena bien, ¿verdad?

    Respecto a buscar palabras sin importar el orden en que se encuentran dentro de la cadena, debes definir una expresión de filtro por cada palabra combinando cada condición con el operador lógico AND (operador inclusivo), lo mismo podrías hacer para todas las columnas, veamos un ejemplo:

    Vamos a implementar un procedimiento Function que retorne un tipo DataTable conteniendo los datos (todas las filas) que serán vinculados contra la grilla de datos a través de la propiedad DataSource, la carga inicial la podrías invocar en el evento Load del formulario o donde mejor veas conveniente:

    Private Function ObtenerProductos() As DataTable
    
    	Try
    		Using cn As New MySqlConnection("Cadena de conexión")
    			Dim ConsultaSQL As String = "SELECT idproducto, codinterno, codproducto, nombre, 
    				ubicacion, marca, rubro, pcosto, pventa, stock FROM productos"
    
    			Dim da As New MySqlDataAdapter(ConsultaSQL, cn)
    			Dim dt As New DataTable
    
    			da.Fill(dt)
    
    			Return dt
    		End Using
    	Catch ex As Exception
    		MessageBox.Show(ex.Message)
    
    		Return Nothing
    	End Try
    
    End Function
    
    
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    	
    	'Vincular datos a la grilla (todas las filas) al cargar el formulario
    	DataGridView1.DataSource = ObtenerProductos()
    	
    End Sub

    Ahora vamos a implementar un procedimiento Sub que permita realizar el filtro contra el origen de datos:

    Private Sub FiltrarDatos(Texto As String)
    
    	Dim dt = DirectCast(DataGridView1.DataSource, DataTable)
    	Dim Filtro As String = String.Empty
    
    	For Each Palabra As String In Texto.Split(New Char() {" "c},
    							StringSplitOptions.RemoveEmptyEntries)
    		Filtro += String.Format("nombre LIKE '%{0}%' AND ", Palabra)
    	Next
    
    	Filtro = String.Format("({0})", IIf(String.IsNullOrEmpty(Filtro),
    						"nombre LIKE '%%'",
    						Filtro.TrimEnd(New Char() {"A", "N", "D", " "})))
    
    	Filtro += String.Format(" OR marca LIKE '%{0}%'", Texto.Trim())
    	Filtro += String.Format(" OR rubro LIKE '%{0}%'", Texto.Trim())
    	Filtro += String.Format(" OR codinterno LIKE '%{0}%'", Texto.Trim())
    	Filtro += String.Format(" OR codproducto LIKE '%{0}%'", Texto.Trim())
    
    	dt.DefaultView.RowFilter = Filtro
    
    End Sub

    Finalmente invocamos el procedimiento FiltrarDatos():

    Private Sub txtBuscar_TextChanged(sender As Object, e As EventArgs) Handles txtBuscar.TextChanged
    
    	Dim txt As TextBox = DirectCast(sender, TextBox)
    
    	FiltrarDatos(txt.Text)
    
    End Sub


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    • Propuesto como respuesta Joyce_ACModerator lunes, 26 de diciembre de 2016 16:21
    • Marcado como respuesta zabino martes, 27 de diciembre de 2016 14:59
    domingo, 25 de diciembre de 2016 18:53
  • Gracias estimado, funciona perfecto... tal cual como lo necesitaba.... muchas gracias!

    tengo una pequeña duda:

     - luego de buscar, ¿se puede resaltar en el datagridview cada palabra que valla encontrando?

    de antemano muchas gracias.

    martes, 27 de diciembre de 2016 15:02