Filtro en un DataGridView

Iniciado por bybaal, 2 Abril 2017, 02:10 AM

0 Miembros y 1 Visitante están viendo este tema.

bybaal

Como puedo crear un filtro usando un textbox en este datagrid, para buscar por nombre, apellido o país.

Código (vbnet) [Seleccionar]

Public Class Form1

    Dim WithEvents dtgw As New DataGridView
    Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
        Me.Controls.Add(dtgw)
        Me.Width = 510
        With dtgw
            .Size = New Size(500, 200)
            .ColumnCount = 3
            .Columns.Item(0).Name = "Nombre"
            .Columns.Item(1).Name = "Apellido"
            .Columns.Item(2).Name = "País"
        End With

        dtgw.Rows.Add("Julio", "Hernández", "Puerto Rico")
        dtgw.Rows.Add("Alicia", "Casanova", "España")
        dtgw.Rows.Add("Manuel", "Pérez", "México")

    End Sub
End Class


okik

#1
no entendí muy bien lo que pides. Entiendo que es el típico buscar donde pones un texto, le das a un botón y te selecciona el contenido que buscas.

Código (vbnet) [Seleccionar]
Public Class Form1
   Dim WithEvents dtgw As New DataGridView
   Dim WithEvents bSearch As New Button
   Dim WithEvents txtBox As New TextBox
   Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

       With Me
           .Controls.AddRange({dtgw, bSearch, txtBox})
           .Width = 510

           With .dtgw
               .Size = New Size(500, 150)
               .ColumnCount = 3
               .Columns.Item(0).Name = "Nombre"
               .Columns.Item(1).Name = "Apellido"
               .Columns.Item(2).Name = "País"
           End With

           bSearch.Location = New Point(155, 160)
           bSearch.Text = "Buscar"
           txtBox.Location = New Point(50, 160)
           txtBox.Width = 100

           .dtgw.Rows.Add("Julio", "Hernández", "Puerto Rico")
           .dtgw.Rows.Add("Alicia", "Casanova", "España")
           .dtgw.Rows.Add("Manuel", "Pérez", "México")


       End With
   End Sub

   Private Sub bSearch_Click(sender As Object, e As EventArgs) Handles bSearch.Click
       dtgw.ClearSelection()
       For Each Column As DataGridViewColumn In dtgw.Columns
           For Each row As DataGridViewRow In dtgw.Rows
               Try
                   If txtBox.Text.ToString.ToLower.Equals(row.Cells(Column.Index).Value.ToString.ToLower) Then
                       row.Cells(Column.Index).Selected = True
                   End If
               Catch ex As Exception
               End Try
           Next
       Next
   End Sub
End Class


Si te fijas he usado el Try Catch ya que al haber filas vacías se produciría un error.

Si no quieres filas vacías al final del datagrid establece la propiedad AllowUserToAddRows = False al DataGridView para evitar que el usuario pueda crear nuevas filas  y no se creará una nueva fila vacía. En este caso ya no te hace falta el control de errores Try Catch


Código (vbnet) [Seleccionar]

With .dtgw
               .Size = New Size(500, 150)
                .AllowUserToAddRows = False  '<-------
               .ColumnCount = 3
               .Columns.Item(0).Name = "Nombre"
               .Columns.Item(1).Name = "Apellido"
               .Columns.Item(2).Name = "País"
           End With


.....

   Private Sub bSearch_Click(sender As Object, e As EventArgs) Handles bSearch.Click
       dtgw.ClearSelection()
       For Each Column As DataGridViewColumn In dtgw.Columns
           For Each row As DataGridViewRow In dtgw.Rows
               If txtBox.Text.ToString.ToLower.Equals(row.Cells(Column.Index).Value.ToString.ToLower) Then
                   row.Cells(Column.Index).Selected = True
               End If
           Next
       Next
   End Sub






bybaal

Realmente lo que necesitamos es que se oculten las filas que no coinciden con lo buscado y que la búsqueda sea al escribir en el TextBox.

Muchas Gracias

okik

Cita de: bybaal en  9 Abril 2017, 01:15 AM
Realmente lo que necesitamos es que se oculten las filas que no coinciden con lo buscado y que la búsqueda sea al escribir en el TextBox.

Muchas Gracias


Código (vbnet) [Seleccionar]
    Private Sub txtBox_TextChanged(sender As Object, e As EventArgs) Handles txtBox.TextChanged
        dtgw.ClearSelection()
        Dim IndexFilaEncontrada As Integer = Nothing
        For Indice As Integer = 0 To dtgw.Rows.Count - 1
            dtgw.Rows(Indice).Visible = True
        Next

        For Each Column As DataGridViewColumn In dtgw.Columns
            For Each row As DataGridViewRow In dtgw.Rows
                Try
                    If txtBox.Text.ToString.ToLower.Equals(row.Cells(Column.Index).Value.ToString.ToLower) Then
                        IndexFilaEncontrada = CInt(row.Index)
                        For Indice As Integer = 0 To dtgw.Rows.Count - 1
                            If Not Indice = IndexFilaEncontrada Then
                                dtgw.Rows(Indice).Visible = False
                            End If
                        Next
                    End If
                Catch ex As Exception
                End Try
            Next
        Next

    End Sub

Eleкtro

#4
Cita de: bybaal en  9 Abril 2017, 01:15 AMRealmente lo que necesitamos es que se oculten las filas que no coinciden con lo buscado y que la búsqueda sea al escribir en el TextBox.

Aquí abajo te muestro otra alternativa de hacerlo. En caso de que lo uses, adáptalo a tus necesidades.

Código (vbnet) [Seleccionar]
Public NotInheritable Class Form1 : Inherits Form

   Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged

       Me.TriggerFindText(DirectCast(sender, TextBox), Me.DataGridView1)

   End Sub

   Private Sub TriggerFindText(ByVal tb As TextBox, ByVal dgv As DataGridView)

       ' Cuando se dispara el evento TextBox.TextChanged, guardamos el texto actual en una variable,
       ' esperamos 300-500 ms approx. y verificamos si el texto sigue siendo el mismo o ha cambiado.
       ' De esta manera evitamos realizar búsquedas indeseadas (términos de búsqueda incompletos) mientras el usuario está escribiendo.
       ' Util también si tenemos miles de filas en el datagridview, para evitar bloqueos en el thread de la UI.

      ' Como es evidente, esta metodología está pensada para una búsqueda en "tiempo real";
      ' Si prefieres iniciar la búsqueda solamente cuando se presione la tecla "Enter" entonces esta metodología no tienes por que usarla...

       Dim t As New Task(
           Sub()
               Dim oldText As String = tb.Text
               Dim newText As String
               Thread.Sleep(400)

               newText = tb.Text
               If String.IsNullOrEmpty(newText) Then
                   ShowAllRowsInDataGridView(dgv)

               ElseIf (oldText = newText) Then
                   FindTextInDataGridView(dgv, tb.Text, StringComparison.OrdinalIgnoreCase)

               Else ' (oldText <> newText)
                   ' El texto ha cambiado, así que no hacemos nada.

               End If

           End Sub)

       t.Start()

   End Sub

   Friend Shared Sub ShowAllRowsInDataGridView(ByVal dgv As DataGridView)

       If (dgv.InvokeRequired) Then
           dgv.Invoke(New Action(Sub() ShowAllRowsInDataGridView(dgv)))
       End If

       dgv.SuspendLayout()
       For Each row As DataGridViewRow In dgv.Rows
           If Not (row.IsNewRow) Then
               row.Visible = True
           End If
       Next row
       dgv.ResumeLayout(performLayout:=True)

   End Sub

   Friend Shared Sub FindTextInDataGridView(ByVal dgv As DataGridView, ByVal str As String, ByVal stringComparison As StringComparison)

       If (dgv.InvokeRequired) Then
           dgv.Invoke(New Action(Sub() FindTextInDataGridView(dgv, str, stringComparison)))
       End If

       Dim cellContainsFunc As Func(Of DataGridViewCell, String, Boolean) =
           Function(ByVal cell As DataGridViewCell, s As String)
               If (cell.Value IsNot Nothing) Then
                   Return (cell.Value.ToString().IndexOf(s, stringComparison) <> -1)
               Else
                   Return False
               End If
           End Function

       Dim indices As IEnumerable(Of Integer) =
           (From row As DataGridViewRow In dgv.Rows
            Where row.Cells.Cast(Of DataGridViewCell).Any(Function(x As DataGridViewCell) cellContainsFunc(x, str))
            Select row.Index)

       dgv.SuspendLayout()
       dgv.ClearSelection()
       For Each row As DataGridViewRow In dgv.Rows
           If Not (row.IsNewRow) Then
               row.Visible = indices.Contains(row.Index)
           End If
       Next row
       dgv.ResumeLayout(performLayout:=True)

   End Sub

End Class


¡Saludos!








bybaal

Gracias Elektro y todos los que me ayudaron. Justamente es esto lo que estaba buscando.