miércoles, diciembre 22, 2010

Buscar en Listas genericas

Bienvenidos, mi nombre es Milton Baltazar y con este blog pretendo dar un aporte a la comunidad de programadores en algunos códigos que he aprendido a lo largo de mi expericia con csharp y vb.net, aunque el tiempo es muy escaso me dare algunos momentos para publicar y responder las interrogantes que me planteen.

Luego de intentar publicar en wordpress y jimbo, blogger me pareceio la mejor opcion para publicar mis notas y artículos.

En este articulo aunque se llama buscar en listas genericas (el cual vendria a ser el resultado final), trato de unir varios temas como por ejemplo: buscar en listas genéricas, datagridview con origen de datos de listas genericas, uso de Using en vb.net, Clases personalizadas que heredan de listas genéricas y el uso de datareader para cargar las listas genéricas y mostrarlos en el datagridview.

Cabe mencionar que el ejemplo lo realizo con la base de datos Northwind y la tabla Employees.

Lo primero que hacemos es crear la clase Employees

Public Class Employees

Private lEmployeeID As System.Int32
Private lLastName As System.String = String.Empty
Private lFirstName As System.String = String.Empty
Private lTitle As System.String = String.Empty
Private lTitleOfCourtesy As System.String = String.Empty
Private lBirthDate As System.DateTime
Private lHireDate As System.DateTime
Private lAddress As System.String = String.Empty
Private lCity As System.String = String.Empty
Private lRegion As System.String = String.Empty
Private lPostalCode As System.String = String.Empty
Private lCountry As System.String = String.Empty
Private lHomePhone As System.String = String.Empty
Private lExtension As System.String = String.Empty
Private lPhoto As System.Byte()
Private lNotes As System.String = String.Empty
Private lReportsTo As System.Int32
Private lPhotoPath As System.String = String.Empty

Public Property EmployeeID As System.Int32
Get
Return lEmployeeID
End Get
Set(ByVal value As System.Int32)
lEmployeeID = value
End Set
End Property

Public Property LastName As System.String
Get
Return lLastName
End Get
Set(ByVal value As System.String)
lLastName = value
End Set
End Property

Public Property FirstName As System.String
Get
Return lFirstName
End Get
Set(ByVal value As System.String)
lFirstName = value
End Set
End Property

Public Property Title As System.String
Get
Return lTitle
End Get
Set(ByVal value As System.String)
lTitle = value
End Set
End Property

Public Property TitleOfCourtesy As System.String
Get
Return lTitleOfCourtesy
End Get
Set(ByVal value As System.String)
lTitleOfCourtesy = value
End Set
End Property

Public Property BirthDate As System.DateTime
Get
Return lBirthDate
End Get
Set(ByVal value As System.DateTime)
lBirthDate = value
End Set
End Property

Public Property HireDate As System.DateTime
Get
Return lHireDate
End Get
Set(ByVal value As System.DateTime)
lHireDate = value
End Set
End Property

Public Property Address As System.String
Get
Return lAddress
End Get
Set(ByVal value As System.String)
lAddress = value
End Set
End Property

Public Property City As System.String
Get
Return lCity
End Get
Set(ByVal value As System.String)
lCity = value
End Set
End Property

Public Property Region As System.String
Get
Return lRegion
End Get
Set(ByVal value As System.String)
lRegion = value
End Set
End Property

Public Property PostalCode As System.String
Get
Return lPostalCode
End Get
Set(ByVal value As System.String)
lPostalCode = value
End Set
End Property

Public Property Country As System.String
Get
Return lCountry
End Get
Set(ByVal value As System.String)
lCountry = value
End Set
End Property

Public Property HomePhone As System.String
Get
Return lHomePhone
End Get
Set(ByVal value As System.String)
lHomePhone = value
End Set
End Property

Public Property Extension As System.String
Get
Return lExtension
End Get
Set(ByVal value As System.String)
lExtension = value
End Set
End Property

Public Property Photo As System.Byte()
Get
Return lPhoto
End Get
Set(ByVal value As System.Byte())
lPhoto = value
End Set
End Property

Public Property Notes As System.String
Get
Return lNotes
End Get
Set(ByVal value As System.String)
lNotes = value
End Set
End Property

Public Property ReportsTo As System.Int32
Get
Return lReportsTo
End Get
Set(ByVal value As System.Int32)
lReportsTo = value
End Set
End Property

Public Property PhotoPath As System.String
Get
Return lPhotoPath
End Get
Set(ByVal value As System.String)
lPhotoPath = value
End Set
End Property

Function GetItem(ByVal PropertyName As String) As Object
If PropertyName = "EmployeeID" Then
Return EmployeeID
ElseIf PropertyName = "LastName" Then
Return LastName
ElseIf PropertyName = "FirstName" Then
Return FirstName
ElseIf PropertyName = "Title" Then
Return Title
ElseIf PropertyName = "TitleOfCourtesy" Then
Return TitleOfCourtesy
ElseIf PropertyName = "BirthDate" Then
Return BirthDate
ElseIf PropertyName = "HireDate" Then
Return HireDate
ElseIf PropertyName = "Address" Then
Return Address
ElseIf PropertyName = "City" Then
Return City
ElseIf PropertyName = "Region" Then
Return Region
ElseIf PropertyName = "PostalCode" Then
Return PostalCode
ElseIf PropertyName = "Country" Then
Return Country
ElseIf PropertyName = "HomePhone" Then
Return HomePhone
ElseIf PropertyName = "Extension" Then
Return Extension
ElseIf PropertyName = "Photo" Then
Return Photo
ElseIf PropertyName = "Notes" Then
Return Notes
ElseIf PropertyName = "ReportsTo" Then
Return ReportsTo
ElseIf PropertyName = "PhotoPath" Then
Return PhotoPath
Else
Return Nothing
End If
End Function

End Class




Lo novedoso es que voy a crear una clase ListEmployees el cual herada de una lista genérica de Employees.

Public Class ListEmployees
Inherits List(Of Employees)

Sub New()
End Sub

End Class


De esta manera cuando quiera crear una colección de employees
ya no tendre que declarar:

Dim value as List(Of Employees)

la declaración ahora se realizará de la siguiente manera

Dim value as ListEmployees

¿y porque lo hago asi?, la ventaje que encontre haciendolo de esta manera es que yo puedo heredar de otros tipos de colecciones o implementar interfaces dentro del archivo ListEmployees.vb, ademas
puedo manipular la lista generica para crear metodos y propiedades personalizadas en ListEmployees.vb sin la necesidad de cambiar mi declaración, por ejemplo yo podria crear un metodo que busque dentro de las colecciones o que me devuelva el item numero 3 de la lista, etc.

El diseño del formulario es como muestra la imagen.




En el solution explorer la distribución de los archivos queda como
muestra la siguiente imagen.




En el form1 ingresamos las siguientes variables que se usaran dentro del ambito del formulario.

Dim ListSoruce As ListEmployees
Dim lSelectColumn As String = String.Empty



Continuando en el form1 (formulario que realizará la busqueda) debo ingreso el siguiente código
para cargar el datagridview. Notese que se usa la clase employees
para guardar cada registro de la consulta en memoria y cada item se esta llenando en ListEmployees el cual será origen de datos del datagridview.

la función NullToNothing lo único que hace convertir cualquier valor nulo que me devuelva la conulta a nothing o a 0 si es un tipo de dato numérico.

Function NullToNothing(ByVal value As Object) As Object
If value Is DBNull.Value Then
If value.GetType.Name = "Int32" Then
Return 0
ElseIf value.GetType.Name = "Decimal" Then
Return 0
Else
Return Nothing
End If
Else
Return value
End If

End Function

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim List As New ListEmployees

Using cn As New SqlClient.SqlConnection
cn.ConnectionString = "Data Source=pc01;Initial Catalog=Northwind;User ID=sa;Password=xxxxxx"
Using cmd As New SqlClient.SqlCommand
cmd.Connection = cn
cmd.CommandType = CommandType.Text
cmd.CommandText = "select * from dbo.Employees"
cn.Open()
cmd.ExecuteNonQuery()
Using dr As SqlClient.SqlDataReader = cmd.ExecuteReader
If dr.HasRows = True Then
Dim Col01 As Integer = dr.GetOrdinal("EmployeeID")
Dim Col02 As Integer = dr.GetOrdinal("LastName")
Dim Col03 As Integer = dr.GetOrdinal("FirstName")
Dim Col04 As Integer = dr.GetOrdinal("Title")
Dim Col05 As Integer = dr.GetOrdinal("TitleOfCourtesy")
Dim Col06 As Integer = dr.GetOrdinal("BirthDate")
Dim Col07 As Integer = dr.GetOrdinal("HireDate")
Dim Col08 As Integer = dr.GetOrdinal("Address")
Dim Col09 As Integer = dr.GetOrdinal("City")
Dim Col10 As Integer = dr.GetOrdinal("Region")
Dim Col11 As Integer = dr.GetOrdinal("PostalCode")
Dim Col12 As Integer = dr.GetOrdinal("Country")
Dim Col13 As Integer = dr.GetOrdinal("HomePhone")
Dim Col14 As Integer = dr.GetOrdinal("Extension")
Dim Col15 As Integer = dr.GetOrdinal("Photo")
Dim Col16 As Integer = dr.GetOrdinal("Notes")
Dim Col17 As Integer = dr.GetOrdinal("ReportsTo")
Dim Col18 As Integer = dr.GetOrdinal("PhotoPath")
Dim Count As Integer = dr.FieldCount - 1
Dim Values(Count) As Object
Dim lInfo As Employees
While dr.Read
dr.GetValues(Values)
lInfo = New Employees
lInfo.EmployeeID = NullToNothing(Values(Col01))
lInfo.LastName = NullToNothing(Values(Col02))
lInfo.FirstName = NullToNothing(Values(Col03))
lInfo.Title = NullToNothing(Values(Col04))
lInfo.TitleOfCourtesy = NullToNothing(Values(Col05))
lInfo.BirthDate = NullToNothing(Values(Col06))
lInfo.HireDate = NullToNothing(Values(Col07))
lInfo.Address = NullToNothing(Values(Col08))
lInfo.City = NullToNothing(Values(Col09))
lInfo.Region = NullToNothing(Values(Col10))
lInfo.PostalCode = NullToNothing(Values(Col11))
lInfo.Country = NullToNothing(Values(Col12))
lInfo.HomePhone = NullToNothing(Values(Col13))
lInfo.Extension = NullToNothing(Values(Col14))
lInfo.Photo = NullToNothing(Values(Col15))
lInfo.Notes = NullToNothing(Values(Col16))
lInfo.ReportsTo = NullToNothing(Values(Col17))
lInfo.PhotoPath = NullToNothing(Values(Col18))
List.Add(lInfo)
End While
DataGridView1.DataSource = List
End If
End Using
End Using
cn.Close()
End Using
End Sub



en el evento ColumnHeaderMouseClick del datagridview colocamos el siguiente código:

Private Sub DataGridView1_ColumnHeaderMouseClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellMouseEventArgs) Handles DataGridView1.ColumnHeaderMouseClick
'colocamos en una variable el nombre de la columna clickeada
lSelectColumn = DataGridView1.Columns(e.ColumnIndex).Name
'mostramos en un label el nombre de la columna clickeada
Label1.Text = lSelectColumn
'otorgamos el foco a la caja de texto donde se realizará la busqueda
txtBuscar.Focus()
End Sub


en el evento TextChanged de la caja de texto txtBuscar colocamos el siguiente código.

Private Sub txtBuscar_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtBuscar.TextChanged
'para buscar en una lista generica con el operador like es necesario colocar los signos de * al
'comienzo y al final de la palabra que deamos buscar
Dim Filter As String = "*" & txtBuscar.Text & "*"
'El resultdo de la busqueda lo guardo en una interfaz IList
Dim Itemns As IList = ListSoruce.FindAll(Function(c As Employees) CStr(c.GetItem(lSelectColumn)).ToLower Like Filter.ToLower)
'Muestro el resultado de la busqueda en el datagridview
DataGridView1.DataSource = Itemns
End Sub


El resultado queda como muestra la siguiente imagen.




Para realizar la busqueda debemos dar click el encabezado de la columna en el cual queremos filtrar, por ejemplo damos click en el LastName y luego escribimos el texto que deseamos filtrar vemos que automaticamente van quedando los registros que contengan la letra o palabra ingresada.




Espero que haya sido de utilidad, me despido hasta la próxima.