1. Ejemplos. 1.1 Introducción. 1.2 Mantenimiento con

Anuncio
1. Ejemplos.
1.1 Introducción.
Vamos a visualizar dos tipos de programas de mantenimiento, uno con una tabla que esta enlazada a un
objeto de visualización como el DataGridView, y que necesita muy pocas líneas de código.
El otro ejemplo es el de un mantenimiento más clásico, y sin enlazar la tabla de datos.
Un ejemplo de un listado, sin uso del Crystal Report.
Y algunos procedimientos que pueden resultar útiles.
Los pasos que se van a considerar, con el fin de no alargar en exceso los ejemplos, son exclusivamente
los referentes a lo imprescindible, dejando de lado lo accesorio, dicho de otra forma, configuraciones previas,
mensajes de ayuda, cargas iniciales, etc..
1.2 Mantenimiento con tabla sin enlazar.
Comparado con el enlazado, es mucho más costoso, pero claro, los resultados no son iguales, y no
siempre un mantenimiento debe considerarse como un grid que visualice sus datos y dejar todo en manos del
usuario, por eso conviene elegir el más adecuado en cada ocasión.
Por lo tanto vamos a empezar con el punto de partida que es el control del campo de código de la tabla,
el ejemplo es de una tabla con una clave principal compuesta por dos campos.
1.2.1 Punto de partida.
Validación de los campos de código.
Private Sub Campo00_Validating( _
ByVal sender As Object, _
ByVal e As System.ComponentModel.CancelEventArgs) _
Handles Campo01.Validating, _
Campo02.Validating, _
.. / ..
Campo13.Validating, _
Campo14.Validating
Dim Cual As Integer
Dim Mensaje As String
Cual = CInt(Strings.Right(CType(sender, TextBox).Name, 2))
Validacion(Cual, CType(sender, TextBox), e.Cancel)
End Sub
Al abandonar los TextBox, se valida su contenido.
1.2.2 Validación.
En este procedimiento la primera parte de la clave se obtiene de un ComboBox,,
Tipo = CType(ComboBox01.SelectedItem, ItemLista)
Después el código se obtiene
Campo.Text = Format(CInt(Campo.Text), "0000")
Cuando ya disponemos de los dos datos, pasamos a realizar una lectura de comprobación:
LeerRegistro(Tipo.Codigo, Campo01.Text)
En este procedimiento obtendremos la situación de la clave introducida, existente o no.
El procedimiento de validación es el que sigue.
Private Sub Validacion(ByVal Cual As Integer, _
ByRef Campo As TextBox, ByRef Cancel As Boolean)
Dim Tipo As ItemLista
Cancel = False
Select Case Cual
Case 1
If Campo.Text <> "" Then
Campo.Text = Format(CInt(Campo.Text), "0000")
Select Case ComboBox01.SelectedIndex > -1
Case True
Tipo = CType(ComboBox01.SelectedItem, ItemLista)
LeerRegistro(Tipo.Codigo, Campo01.Text)
Case Else
Cancel = True
MsgBox("Debe indicar cual es el tipo de la publicación", _
MsgBoxStyle.Information, NomProgram)
End Select
Case 5
.. / ..
End Select
End Sub
1.2.3 Lectura de control.
Veamos el procedimiento de lectura.
El procedimiento realiza una lectura de un registro que exista en la tabla, si existe en la propiedad Tag
del objeto button, Comando01, que hay en el formulario asignamos una “A”, actualizar, y si no “N”, nuevo,
inserción.
Si existe aprovechamos para visualizar los datos, se podía haber enfocado de varias formas.
Los pasos son
Generamos la instrucción SQL.
CadenaSQL = "SELECT TipPub, Codigo, Titulo, ClasEdad, " & _
"ClasTema, Period, Editorial, ISBN, Autor, " & _
"PreCoste, PreVenta, EntAcu, SalAcu, EntDev, SalDev, " & _
"StockMax, StockMin, UltCompra, UltVenta " & _
"FROM Titulos " & _
"WHERE TipPub = '" & TipoPub & "' And " & _
"Codigo = '" & Codigo & "'"
Inicializamos los objetos de acceso a la base de datos, el objeto conexión se configura una vez al inicio
de la aplicación.
' Código SQL para la consulta
Comando.CommandText = CadenaSQL
' Tipo de comando a ejecutar
Comando.CommandType = CommandType.Text
' Conexión a utilizar, configurada previamente.
Comando.Connection = Conexion
Y después se ejecuta la acción.
' Uso del comando
Try
Lector = Comando.ExecuteReader
Después de la ejecución se comprueba si se encuentra o no un registro, y se asigna “A” o “N” según el
resultado, y visualizamos los datos.
Select Case Lector.HasRows
Case True
Lector.Read()
Campo01.Text = Lector.Item("Codigo").ToString
. / ..
Comando01.Tag = "A"
‘ Actualización
Case Else
Comando01.Tag = "N"
‘ Inserción
End Select
El código completo es el siguiente.
Private Sub LeerRegistro(ByVal TipoPub As String, ByVal Codigo As String)
Dim Comando As New System.Data.OleDb.OleDbCommand
Dim Lector As System.Data.OleDb.OleDbDataReader
Dim CadenaSQL As String
Conexion.Open()
CadenaSQL = "SELECT TipPub, Codigo, Titulo, ClasEdad, " & _
"ClasTema, Period, Editorial, ISBN, Autor, " & _
"PreCoste, PreVenta, EntAcu, SalAcu, EntDev, SalDev, " & _
"StockMax, StockMin, UltCompra, UltVenta " & _
"FROM Titulos " & _
"WHERE TipPub = '" & TipoPub & "' And " & _
"Codigo = '" & Codigo & "'"
' Código SQL para la consulta
Comando.CommandText = CadenaSQL
' Tipo de comando a ejecutar
Comando.CommandType = CommandType.Text
' Conexión a utilizar, configurada previamente.
Comando.Connection = Conexion
' Uso del comando
Try
Lector = Comando.ExecuteReader
Select Case Lector.HasRows
Case True
Lector.Read()
Campo01.Text = Lector.Item("Codigo").ToString
Campo02.Text = Lector.Item("Titulo").ToString
.. / ..
Campo14.Text = Lector.Item("UltVenta").ToString
Comando01.Tag = "A"
‘ Actualización
Case Else
Comando01.Tag = "N"
‘ Inserción
Campo01.Tag = Campo01.Text
InicializarCampos(Me)
Campo01.Text = Campo01.Tag.ToString
End Select
Catch ex As OleDb.OleDbException
MsgBox(ex.Message, MsgBoxStyle.Information)
End Try
' Liberar recursos
Comando.Dispose()
Comando = Nothing
Conexion.Close()
End Sub
El siguiente paso, después de la ejecución normal del programa, sería la acción a realizar por el usuario.
Borrado
Grabación.
1.2.4 Elección del usuario.
En el formulario se han previsto las siguientes posibilidades.
Grabar
Baja
Cancelar
Salida
Que son las cuatro posibilidades que contempla el evento.
Private Sub Comando01_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles Comando01.Click, _
Comando02.Click, _
Comando03.Click, _
Comando04.Click
Dim Cual As Integer = CInt(Strings.Right(CType(sender, Button).Name, 2))
TrataComando(Cual)
End Sub
Capturada la acción del usuario el siguiente paso es actuar.
Private Sub TrataComando(ByVal Cual As Integer)
Select Case Cual
Case 1 ' Aceptar
Grabar()
Case 2 ' Baja
Borrar()
Case 3 ' Cancelar
InicializarCampos(Me)
Case 4 ' Salir
Salida()
End Select
Campo01.Focus()
End Sub
1.2.5 Borrado.
El borrado queda como sigue.
Crear la cadena SQL
CadenaSQl = "Delete From Titulos " & _
"Where (Titulos.TipPub = '" & Tipo.Codigo.ToString & "') and " & _
"(Titulos.Codigo = '" & Campo01.Text & "');"
Inicializar los objetos de acceso a la base de datos.
Ejecución de la instrucción SQL
Cuantos = Comando.ExecuteNonQuery
En este caso como no hay datos de retorno, se usa ExecuteNonQuery.
Y el ejemplo completo a continuación.
Private Sub Borrar()
Dim Comando As New System.Data.OleDb.OleDbCommand
Dim Cuantos As Integer
Dim CadenaSQl As String
Dim Tipo As ItemLista
Tipo = CType(ComboBox01.SelectedItem, ItemLista)
CadenaSQl = "Delete From Titulos " & _
"Where (Titulos.TipPub = '" & Tipo.Codigo.ToString & "') and " & _
"(Titulos.Codigo = '" & Campo01.Text & "');"
Conexion.Open()
' Nombre de la consulta en la base de datos.
Comando.CommandText = CadenaSQl
' Tipo de comando a ejecutar
Comando.CommandType = CommandType.Text
' Conexión a utilizar, configurada previamente.
Comando.Connection = Conexion
Try
Cuantos = Comando.ExecuteNonQuery
Select Case Cuantos
Case Is <> 0
MsgBox("Datos borrados", MsgBoxStyle.Information, Me.Text)
Case Else
MsgBox("Incidencia en borrado", MsgBoxStyle.Information, Me.Text)
End Select
Catch ex As OleDb.OleDbException
MsgBox(ex.Message, MsgBoxStyle.Information, "Error en borrado")
End Try
Conexion.Close()
' Liberar recursos
Comando.Dispose()
Comando = Nothing
End Sub
1.2.6 Grabación.
La acción de grabación, oculta al usuario la acción de inserción o actualización, que ya se ha
seleccionado en el momento de validar a nivel de programa.
Por lo tanto el primer paso es seleccionar la acción a realizar.
Private Sub Grabar()
Select Case Comando01.Tag.ToString
Case "A"
Actualizar()
Case "N"
Insertar()
End Select
End Sub
Como se puede observar se utiliza la propiedad Tag, que se ha cargado previamente en validación.
Por lo tanto ahora o se inserta o se actualiza.
Veamos primero la actualización.
Primero como siempre creación de la instrucción SQL,
CadenaSQl = "Update Titulos Set " & _
"TipPub = '" & TipoPub.Codigo.ToString & "' , " & _
"Codigo = '" & Campo01.Text & "' , " & _
.. / ..
"UltVenta = '" & UltVent & "' " & _
"WHERE (Titulos.TipPub = '" & TipoPub.Codigo.ToString & "') And " & _
"(Titulos.Codigo = '" & Campo01.Text & "');"
Después como siempre la inicialización de los objetos de acceso a la base de datos, y la ejecución de la
instrucción SQL.
Cuantos = Comando.ExecuteNonQuery
Y el control del resultado de la actualización.
Select Case Cuantos
Case Is <> 0
MsgBox("Datos grabados", MsgBoxStyle.Information, Me.Text)
Case Else ' cuando hay error salta el Catch, y sino
MsgBox("Error en actualización", MsgBoxStyle.Information, Me.Text)
End Select
El procedimiento completo queda.
Private Sub Actualizar()
Dim Comando As New System.Data.OleDb.OleDbCommand
Dim Cuantos As Integer
Dim CadenaSQl As String
CadenaSQl = "Update Titulos Set " & _
"TipPub = '" & TipoPub.Codigo.ToString & "' , " & _
"Codigo = '" & Campo01.Text & "' , " & _
"Titulo = '" & Campo02.Text & "' , " & _
.. / ..
"UltVenta = '" & UltVent & "' " & _
"WHERE (Titulos.TipPub = '" & TipoPub.Codigo.ToString & "') And " & _
"(Titulos.Codigo = '" & Campo01.Text & "');"
Conexion.Open()
' Código SQL
Comando.CommandText = CadenaSQl
' Tipo de comando a ejecutar
Comando.CommandType = CommandType.Text
' Conexión a utilizar, configurada previamente.
Comando.Connection = Conexion
Try
Cuantos = Comando.ExecuteNonQuery
Select Case Cuantos
Case Is <> 0
MsgBox("Datos grabados", MsgBoxStyle.Information, Me.Text)
Case Else ' cuando hay error salta el Catch, y sino
MsgBox("Error en actualización", MsgBoxStyle.Information, Me.Text)
End Select
Catch ex As OleDb.OleDbException
MsgBox(ex.Message, MsgBoxStyle.Information, "Error en actualización")
End Try
Conexion.Close()
' Liberar recursos
Comando.Dispose()
Comando = Nothing
End Sub
El proceso de inserción es similar al anterior pero claro cambia la instrucción SQL, por lo que hay poco
que comentar.
Private
Dim
Dim
Dim
Sub Insertar()
Comando As New System.Data.OleDb.OleDbCommand
Cuantos As Integer
CadenaSQl As String
CadenaSQl = "INSERT INTO Titulos ( TipPub, Codigo, Titulo, ClasEdad, " & _
"ClasTema, Period, Editorial, ISBN, Autor, " & _
"PreCoste, PreVenta, EntAcu, SalAcu, " & _
"EntDev, SalDev, StockMax, StockMin, " & _
"UltCompra, UltVenta ) " & _
"Values ('" & TipoPub.Codigo.ToString & "', " & _
"'" & Campo01.Text & "', " & _
.. / ..
"'" & UltVent & "') "
Conexion.Open()
' Código SQL
Comando.CommandText = CadenaSQl
' Tipo de comando a ejecutar
Comando.CommandType = CommandType.Text
' Conexión a utilizar, configurada previamente.
Comando.Connection = Conexion
Try
' hay que borrarlo cuando está probado
Cuantos = Comando.ExecuteNonQuery
Select Case Cuantos
Case Is <> 0
MsgBox("Datos grabados", MsgBoxStyle.Information, Me.Text)
Case Else ' cuando hay error salta el Catch, y sino
MsgBox("Error en inserción", MsgBoxStyle.Information, Me.Text)
End Select
Catch ex As OleDb.OleDbException
MsgBox(ex.Message, MsgBoxStyle.Information, "Error en inserción")
End Try
Conexion.Close()
' Liberar recursos
Comando.Dispose()
Comando = Nothing
End Sub
En clase se les propone a los alumnos, que abrevien el código para realizar un único paso.
Visto el ejemplo comentar, que en caso de querer realizarlo con un DataSet, los cambios son mínimos,
pero pensamos que un Mantenimiento es más lógico hacerlo enlazando con la base de datos y dejando los
cambios plasmados en la misma, sin que se difieran los mismos en el tiempo.
Con un DataSet por otro lado se puede utilizar el método de búsqueda Find.
1.3 Mantenimiento con tabla enlazada.
La ventaja de este planteamiento, es los pocos recursos que se necesitan para dejar una tabla accesible
al usuario y permitir que realice tareas de mantenimiento.
El inconveniente, lo parco en recursos de validación, pero se puede alcanzar un buen nivel.
Por otro lado queda el tema del control de teclado, que hemos podido resolver creando una clase que
herede el objeto DataGridView y a la que le hemos mejorado el control del teclado, personalizándolo por
columnas.
No hemos incluido dicha clase, pues aunque funciona, aún es un embrión, y no nos gusta su aspecto.
Veamos el ejemplo.
1.3.1 Punto de partida.
En este caso el punto de partida tiene que ser el enlace de la tabla al DataGridView.
Private Sub CargaFormulario(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles Me.Load
ConfigConexion(Conexion)
Carga(Conexion, Adaptador, Enlace, ObjDataGrid, “Select * from provincia")
End Sub
Por lo tanto el mejor sitio para hacerlo es el evento Load del formulario, en el cual también configuramos
el objeto DataConnection.
Los objetos a utilizar son:
' Conexión a la base de datos
Dim Conexion As New System.Data.OleDb.OleDbConnection
' Acceso a la base de datos
Dim Adaptador As New System.Data.OleDb.OleDbDataAdapter
' Enlace a datos, no es imprescindible, solo por mostrarlo
Dim Enlace As New BindingSource
' Comando para la ejecución de SQL
Dim Comando As New System.Data.OleDb.OleDbCommand
Definidos a nivel de formulario.
En este procedimiento se realiza la carga de los datos, y el enlace del objeto.
Public Sub Carga(ByVal
ByRef
ByRef
ByRef
ByVal
Conexion As System.Data.OleDb.OleDbConnection, _
Adaptador As System.Data.OleDb.OleDbDataAdapter, _
EnlaceTabla As BindingSource, _
ObjDataGrid As DataGridView, _
CadenaSql As String)
Dim ComandoActualizar As OleDb.OleDbCommandBuilder
Try
Conexion.Open
' Crear un nuevo adaptador de datos
Adaptador = New OleDb.OleDbDataAdapter(CadenaSql, Conexion)
' Crear un 'commandbuilder' que genere el SQL Update/Insert/Delete
' no debe cambiarse de sitio
ComandoActualizar = New OleDb.OleDbCommandBuilder(Adaptador)
' Llenar la tabla con los datos
Dim Tabla As New DataTable
Adaptador.Fill(Tabla)
' Enlazarla al 'bindingsource'
ObjDataGrid.DataSource = EnlaceTabla
EnlaceTabla.DataSource = Tabla
Conexión.Close
Catch ex As OleDb.OleDbException
MsgBox(ex.Message, MsgBoxStyle.Information)
End Try
End Sub
El enlace también puede realizarse de forma directa sin usar el bindingsource.
ObjDataGrid.DataSource = Tabla
1.3.2 Elección del usuario.
Teniendo en cuenta que el DataGrid contiene todos los datos de la tabla, el usuario se supone que sabe
localizar lo que desea modificar, borrar o cuando debe insertar una fila nueva.
Salvada esta consideración, hay que tener presente que mientras no se ejecute el método Update los
cambios no se reflejan en la base de datos, por lo tanto es posible en la acción de cancelar, recargar el
DataGrid, y éste retomará la situación inicial, o desde la última actualización.
El borrado se realiza mediante el método Remove del DataGridView, sobre la fila actual.
En el formulario se han previsto las siguientes posibilidades.
Actualizar
Baja
Cancelar
Salida
Que son las cuatro posibilidades que contempla el evento, y el código que se acompaña.
Private Sub Comando01_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles Comando01.Click, _
Comando02.Click, _
Comando03.Click, _
Comando04.Click
Dim Cual As Integer
Cual = CInt(Strings.Right(CType(sender, Button).Name, 2))
Select Case Cual
Case 1
' Actualizar la base de datos con los cambios efectuados
Try
Adaptador.Update(CType(Enlace.DataSource, DataTable))
MsgBox("Datos actualizados", MsgBoxStyle.Information)
Catch ex As System.Data.OleDb.OleDbException
MsgBox("Errores " & vbCrLf & ex.Message, MsgBoxStyle.Critical)
End Try
Case 2
' Borrar
ObjDataGrid.Rows.Remove(ObjDataGrid.CurrentRow)
Case 3
' Cancelar, recargar sin actualizar los cambios
Carga(Conexion, _
Adaptador, _
Enlace, _
ObjDataGrid, _
Adaptador.SelectCommand.CommandText)
Case 4
' salida
Salida()
End Select
End Sub
Y no es necesario nada más, para que funcione.
Las columnas en el DataGridView, se generan de forma automática a partir de la estructura de la tabla
que estamos utilizando.
Mediante las propiedades de configuración de este objeto es posible el bloqueo de las acciones de
edición de forma personalizada.
Este sistema no siempre es posible plantearlo, acudir a la documentación de VB.Net.
El procedimiento Carga se puede utilizar también de esta otra forma, por otro lado más lógica, pues
dispone de la propiedad DataSource, y no precisa del objeto BindingSource de forma imprescindible.
Private Sub Carga(ByVal Conexion As System.Data.OleDb.OleDbConnection, _
ByRef Adaptador As System.Data.OleDb.OleDbDataAdapter, _
ByRef ObjDataGrid As DataGridView, _
ByRef Tabla As DataTable, _
ByVal CadenaSql As String)
Dim ComandoActualizar As OleDb.OleDbCommandBuilder
Try
' Crear un nuevo adaptador de datos
Adaptador = New OleDb.OleDbDataAdapter(CadenaSql, Conexion)
' Crear un 'commandbuilder' que genere el SQL Update/Insert/Delete
' no debe cambiarse de sitio
ComandoActualizar = New OleDb.OleDbCommandBuilder(Adaptador)
' Llenar la tabla con los datos
Tabla = New DataTable
Adaptador.Fill(Tabla)
' Enlazar tabla y DataGrid
ObjDataGrid.DataSource = Tabla
Catch ex As OleDb.OleDbException
MsgBox(ex.Message, MsgBoxStyle.Information)
End Try
End Sub
La diferencia está en que se enlaza la tabla al DataGrid, no se usa el BindingSource, que es más
adecuado.
Por lo tanto desaparece del procedimiento el objeto BindingSource y aparece la tabla.
Para esta versión, el procedimiento de evento del objeto Button, debe quedar así.
Private Sub Comando01_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles Comando01.Click, _
Comando02.Click, _
Comando03.Click, _
Comando04.Click
Dim Cual As Integer
Cual = CInt(Strings.Right(CType(sender, Button).Name, 2))
Select Case Cual
Case 1
' Actualizar la base de datos con los cambios efectuados
Try
Adaptador.Update(Tabla)
MsgBox("Datos actualizados", MsgBoxStyle.Information)
Catch ex As System.Data.OleDb.OleDbException
MsgBox("Errores " & vbCrLf & ex.Message, MsgBoxStyle.Critical)
End Try
Case 2
' Borrar
ObjDataGrid.Rows.Remove(ObjDataGrid.CurrentRow)
Case 3
' Cancelar, recargar sin actualizar los cambios
Carga(Conexion, _
Adaptador, _
ObjDataGrid, _
Tabla, _
Adaptador.SelectCommand.CommandText)
Case 4
' salida
Salida()
End Select
End Sub
Y como consecuencia de los cambios, en el evento Load también ha de cambiarse la llamada a Carga
Private Sub CargaFormulario(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles Me.Load
ConfigConexion(Conexion)
Carga(Conexion, Adaptador, ObjDataGrid, Tabla, ”Select * from provincia")
End Sub
Y debe aparecer el objeto tabla en la definición de objetos en el formulario.
Dim Tabla as DataTable
En función de cómo se quiera enriquecer el programa, son de setenta a cien líneas de código para el
mismo, lo cual es ridículo, comparado con uno más exhaustivo en su validación.
Conviene recordar las posibilidades de formato que incorpora éste objeto a la hora de visualizar
información y que permiten mejorar el aspecto de los datos visualizados incorporando distintas opciones de
fondos o colores en las celdas que se desee.
1.4 Listado.
Crystal Report, he mejorado en mucho desde sus inicios, malo sería que no fuera así, pero la ventaja de
controlar el uso de la impresión sin el asistente en cuestión, es la libertad que se tiene de poder abordar
cualquier tipo de proceso de impresión sin el corsé que podría suponer dicha utilidad, a la que evidentemente
siempre se puede recurrir.
Exponemos solo los dos procedimientos base, el bucle de impresión y la línea de detalle, el resto de
procedimientos no entrañan ningún problema.
La línea de detalle se utiliza partiendo de la existencia de un vector en el que hemos calculado la
ubicación de cada campo en el listado.
El procedimiento que realiza dichos cálculos es el que sigue.
Private Sub ConfigCabecera(ByRef Textocabecera() As CabecDetalle)
Dim Fuente As Font
Dim Lapiz As New System.Drawing.SolidBrush(System.Drawing.Color.Black)
Dim AnchoString As New SizeF
Dim Formato As New System.Drawing.StringFormat
Dim Cx As Long
Dim Grafico As Graphics = Me.CreateGraphics
Dim X As Integer
Fuente = Est_Lin_Det
' Campos del listado
Textocabecera(0).Texto = "Código "
Textocabecera(1).Texto = "Nombre
"
Textocabecera(2).Texto = "Apellido 1
"
Textocabecera(3).Texto = "Apellido 2
"
Textocabecera(4).Texto = "Domicilio
"
Textocabecera(5).Texto = ""
' Formato del texto
Formato.FormatFlags = StringFormatFlags.MeasureTrailingSpaces
' Margen lateral
Cx = CLng(Hoja.DefaultPageSettings.Margins.Left)
' Fuente a utiilizar
Fuente = Est_Lin_Det
' New Font("Arial", 12, FontStyle.Italic)
' Bucle de cálculo
While X < UBound(Textocabecera)
Textocabecera(X).Cx = Cx
' Ancho del texto
AnchoString
=
Grafico.MeasureString(StrDup(Len(Textocabecera(X).Texto),
“n"), Fuente)
Cx = CLng(Cx + AnchoString.Width)
X = X + 1
End While
End Sub
1.4.1 Punto de partida.
Load
Por lo tanto el punto de arranque debe ser la ejecución del procedimiento de configuración en el evento
Private Sub ListAlum_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
ConfigCabecera(TextoCabecera)
End Sub
El inicio del listado arrancará, después de haberse captado por uno u otro sistema los rangos del mismo,
en la pulsación del Button Aceptar o Listar, es lo mismo.
Suponemos que en pantalla el destino del listado.
Private Sub Comando01_Click(ByVal sender As Object, _
ByVal e As
System.EventArgs) _
Handles Comando01.Click
VistaPrevia = New PrintPreviewDialog
VistaPrevia.Document = Hoja
VistaPrevia.ShowDialog()
End Sub
Hay que tener presente que
VistaPrevia.Document = Hoja
Es donde se indica el destino del listado.
El objeto de impresión, PrintDocument se llama Hoja.
Este objeto es indistinto del destino del listado, podríamos decir que es un gestor que realiza la labor de
direccionamiento al destino de la impresión.
El destino en pantalla se obtiene con el objeto PrintPreviewDialog.
1.4.2 Los datos.
El primer paso será obtener los datos a listar a partir de las circunstancias del listado.
Ese paso se puede hacer desde el evento de inicio de listado del PrintDocument, BeginPrint
Private Sub Hoja_BeginPrint( _
ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintEventArgs) _
Handles Hoja.BeginPrint
CrearDataReader()
End Sub
En el ejemplo se cargan los datos de la cabecera de forma manual, pero podría ejecutarse un
procedimiento como éste para automatizar la tarea.
CargaCamposCabecera(TextoCabecera, Reader)
Cuyo contenido sería
Private Sub CargaCamposCabeceraDos(ByVal V() As CabecDetalle, _
ByVal RecordSet As OleDb.OleDbDataReader)
Dim Diseny As DataTable = RecordSet.GetSchemaTable()
Dim Fila As DataRow
Dim X As Integer
For Each Fila In Diseny.Rows
' elemento cero tiene el nombre del campo
V(X).Texto = Fila(0).ToString()
X = X + 1
Next
End Sub
El procedimiento para la obtención de los datos del listado sería
Private Sub CrearDataReader()
Dim CadenaSQL As String
Dim Condicion As String
Dim Clave As String
CreaRangos(Condicion, Clave)
CadenaSQL = "Select Exped , Ape1 , Ape2, Nombre, Domic From Alumnos " & _
"Where " & Condicion & _
" Order by " & Clave & " ;"
ContPag = 0
' Contador de páginas
Try
Conexion = New System.Data.OleDb.OleDbConnection
Comando = New System.Data.OleDb.OleDbCommand
' Abrir la base de datos.
ConfigConexion(Conexion)
Conexion.Open()
' Tipo de comando a ejecutar
Comando.CommandType = CommandType.Text
' Contenido del comando
Comando.CommandText = CadenaSQL
' Conexión a utilizar, configurada previamente.
Comando.Connection = Conexion
' Ejecución de SQL
Reader = Comando.ExecuteReader
Catch Ex As Exception
MsgBox(Ex.Message, MsgBoxStyle.Information, "Crear RecordSet")
End Try
End Sub
Obtenidos los datos ahora pasamos a la ejecución del bucle.
1.4.3 El bucle.
Ahora se trata de realizar la lectura de la estructura obtenida en el procedimiento anterior.
Se ha utilizado un DataReader, pero igual se podía haber utilizado un DataTable,
La lectura la realizaremos dentro del evento PrintPage del objeto PrintDocument.
Solo recordar, o indicar, que algunas variables usadas en el ejemplo no se declaran a nivel de
procedimiento por la idiosincrasia de funcionamiento de éste evento.
Veamos los pasos principales.
Dado que se entra y sale del evento por la acción de la propiedad
e.HasMorePages = True
las variables que siguen han de tener siempre este valor al entrar en el procedimiento.
Dim Cabec As Boolean = True
Dim Pie As Boolean = False
Si hay algo a listar la condición será cierta
If Reader.HasRows Then
Y después mientras algo haya que leer
While Reader.Read
' Línea de detalle
LineaDet(e, Cy, Reader, Fuente, TextoCabecera)
Iremos sacando líneas de detalle.
Cada vez que se llene la página haremos el pié de página, si procede, y sacaremos cabeceras.
' Control de fin de página
If Cy > e.MarginBounds.Height Then
PiePagina(Cy, e)
e.HasMorePages = True
Exit Sub
End If
El control se realiza con el valor de Cy comparado con la altura del objeto que se usa en la impresión,
hay que tener presente que se usa el valor de la zona imprimible, no de toda la altura del objeto.
If Cy > e.MarginBounds.Height Then
Sacar cabeceras es salir y entrar del seiscientos, que es un gran coche.
e.HasMorePages = True
Exit Sub
Por eso es necesario los valores iniciales de Cabec y Pie
Cuando se acabe el contenido del Reader, se realizará el fin de listado, y se dejará a falso la propiedad
FinImpresion(Cy, e)
e.HasMorePages = False
Y con eso acabaría el listado.
El fin de impresión también puede colocarse en el evento End_Print.
Veamos ahora el contenido del evento PrintPage completo.
Private Sub Hoja_PrintPage( _
ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintPageEventArgs) _
Handles Hoja.PrintPage
'
'
Ejemplo con un datareader
'
Dim Cy As Long
' Coordenada vertical
Dim Cabec As Boolean = True
Dim Pie As Boolean = False
Dim Fuente As Font
Fuente = Est_Lin_Det
' estilo línea de detalle
Try
If Reader.HasRows Then
If Cabec Then
If ContPag = 0 Then
LineaIden(Cy, ContPag, e)
' Línea de identificación
InicioImpresion(e)
e.HasMorePages = True
Exit Sub
End If
Cabeceras(Cy, e)
Cabec = False
End If
While Reader.Read
' Línea de detalle
LineaDet(e, Cy, Reader, Fuente, TextoCabecera)
' Control de fin de página
If Cy > e.MarginBounds.Height Then
PiePagina(Cy, e)
e.HasMorePages = True
Exit Sub
End If
End While
End If
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Information, "Evento Print Page")
End Try
FinImpresion(Cy, e)
e.HasMorePages = False
End Sub
1.4.4 La línea de detalle.
En el procedimiento de impresión se recibe la variable Cy, que nos indicará la situación en vertical de la
línea de detalle, en éste procedimiento se incrementa en el valor de la altura de la fuente utilizada.
De este forma el número de líneas de detalle depende de la altura, o tamaño de la fuente no del número
de líneas que se lleven impresas, que evidentemente también se puede usar.
En el ejemplo se usa un objeto Pincel, por lo de dibujar, al cual se le asigna el color negro, pero también
se puede hacer lo siguiente en la línea de impresión y no es necesario utilizar ningún objeto.
e.Graphics.DrawString(.Item(0).ToString, Fuente, Brushes.Black, V(0).Cx, Cy)
En el procedimiento se utiliza una línea para cada campo de impresión.
Y cada campo de impresión será uno de los campos de la Select utilizada en la carga del Reader, es
decir Reader.Item(0), Reader.Item(1).
Si que comentar, que mejor que Item(0), es utilizar Item(“Exped”), ya que de esa forma, aunque
cambiará el orden de los campos en la Select, no se alteraría el listado.
Por lo tanto la línea de impresión quedaría,
e.Graphics.DrawString(.Item(“Exped”).ToString, Fuente, Pincel, V(0).Cx, Cy)
e.Graphics.DrawString(.Item(“Ape1”).ToString, Fuente, Pincel, V(1).Cx, Cy)
e.Graphics.DrawString(.Item(“Ape2”).ToString, Fuente, Pincel, V(2).Cx, Cy)
e.Graphics.DrawString(.Item(“Nombre”).ToString, Fuente, Pincel, V(3).Cx, Cy)
e.Graphics.DrawString(.Item(“Domic”).ToString, Fuente, Pincel, V(4).Cx, Cy)
Y el procedimiento
Private Sub LineaDet(ByVal
ByRef
ByVal
ByVal
ByVal
e As System.Drawing.Printing.PrintPageEventArgs, _
Cy As Long, _
Reader As OleDb.OleDbDataReader, _
Fuente As Font, _
V() as CabecDetalle)
Dim Pincel As New System.Drawing.SolidBrush(System.Drawing.Color.Black)
With Reader
e.Graphics.DrawString(.Item(0).ToString, Fuente, Pincel, V(0).Cx, Cy)
e.Graphics.DrawString(.Item(1).ToString, Fuente, Pincel, V(1).Cx, Cy)
e.Graphics.DrawString(.Item(2).ToString, Fuente, Pincel, V(2).Cx, Cy)
e.Graphics.DrawString(.Item(3).ToString, Fuente, Pincel, V(3).Cx, Cy)
e.Graphics.DrawString(.Item(4).ToString, Fuente, Pincel, V(4).Cx, Cy)
End With
Cy = Cy + Fuente.Height
End Sub
1.4.5 El final del listado.
Private Sub Hoja_EndPrint(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintEventArgs) _
Handles Hoja.EndPrint
Conexion.Close()
Comando.Dispose()
Reader.Close()
End Sub
1.4.6 Impresora como destino.
Todo lo visto se usa igual, y hay que cambiar en el evento Clic del inicio del listado el objeto de destino
PrintPreviewDialog por el de PrintDialog, pasando de
VistaPrevia.Document = Hoja
A
PrinterDialogo.Document = Hoja
Ya que es de esta forma como se asigna el destino del listado.
1.4.7 Con un DataTable como objeto de datos.
Si usamos un DataTable como objeto para los datos, en el procedimiento de creación de los datos se ha
de sustituir lo del DataReader por
' Asignación del comando al objeto adapter.
Adaptador.SelectCommand = Comando
Adaptador.Fill(Tabla)
Por lo que ahora dispondremos de un DataTable y en el evento PrintPage quedaría como sigue.
Private Sub Hoja_PrintPage( _
ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintPageEventArgs) _
Handles Hoja.PrintPage
'
'
Ejemplo con un DataTable
'
Dim Cy As Long
' Coordenada vertical
Dim Cabec As Boolean = True
Dim Pie As Boolean = False
Dim Fuente As Font
Fuente = Est_Lin_Det
' Estilo línea de detalle
Try
If Posicion < Tabla.Rows.Count Then
If Cabec Then
If ContPag = 0 Then
LineaIden(Cy, ContPag, e)
' Línea de identificación
InicioImpresion(e)
e.HasMorePages = True
Exit Sub
End If
Cabeceras(Cy, e)
Cabec = False
End If
While Tabla.Rows.Count > Posicion
' Línea de detalle
LineaDet(e, Cy, Tabla, Fuente, Posicion)
' Incremento de posición en la Tabla
Posicion = Posicion + 1
' Control de fin de página
If Cy > e.MarginBounds.Height Then
PiePagina(Cy, e)
e.HasMorePages = True
Exit Sub
End If
End While
End If
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Information, "Evento Print Page")
End Try
FinImpresion(Cy, e)
e.HasMorePages = False
End Sub
La filosofía del procedimiento se mantiene igual, pero el origen es un DataTable.
El bucle While se usa con una variable integer y con Count, también se podría haber utilizado un bucle
For each, con un objeto DataRow.
1.5 Mantenimiento con Button de navegación.
La labor de navegación se obtiene con un objeto BindingSource, ya que este objeto dispone de los
métodos adecuados.
Los objetos a utilizar en el programa son:
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Conexion As New System.Data.OleDb.OleDbConnection
Adaptador As New System.Data.OleDb.OleDbDataAdapter
Tabla As New DataTable
EnlaceTabla As New BindingSource
Actualizador As New OleDb.OleDbCommandBuilder(Adaptador)
CadenaSql As String = "Select * From Provincia Order By CodProv"
Nuevo As Boolean = False
Actualizado As Boolean = True
Además utilizamos TextBox para la visualización y Button para las acciones de navegación y
mantenimiento.
La apariencia del formulario es la que vemos en la imagen.
Los campos los hemos enlazado
Private Sub Enlaces()
Campo00.DataBindings.Add("Text", EnlaceTabla, "CodProv")
Campo01.DataBindings.Add("Text", EnlaceTabla, "DenomCas")
Campo02.DataBindings.Add("Text", EnlaceTabla, "DenomVal")
End Sub
La carga de datos se realiza como sigue:
Private Sub CargaDatos()
If Conexion.State = ConnectionState.Closed Then Conexion.Open()
Adaptador = New OleDb.OleDbDataAdapter(CadenaSql, Conexion)
Adaptador.Fill(Tabla)
EnlaceTabla.DataSource = Tabla
Actualizador = New OleDb.OleDbCommandBuilder(Adaptador)
Conexion.Close()
End Sub
1.5.1 Punto de partida.
Arrancamos del evento Load, y en él realizamos las siguientes tareas.
Private Sub Mantenimiento_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles Me.Load
ConfigConexion(Conexion)
CargaDatos()
Enlaces()
End Sub
1.5.2 Los eventos
La captura de las acciones del usuario es como sigue:
Private Sub Comando00_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles Comando01.Click, _
Comando02.Click, _
Comando03.Click, _
Comando04.Click, _
Comando05.Click, _
Comando06.Click, _
Comando07.Click, _
Comando08.Click, _
Comando09.Click
Dim Cual As Integer
Cual = CInt(Strings.Right(CType(sender, Button).Name, 2))
Select Case Cual
Case 1 ' cancelar
EnlaceTabla.CancelEdit()
Case 2 ' borrar
EnlaceTabla.RemoveCurrent()
Case 3 ' salida
Salida()
Case 4 ' primero
EnlaceTabla.MoveFirst()
Case 5 ' anterior
EnlaceTabla.MovePrevious()
Case 6 ' siguiente
EnlaceTabla.MoveNext()
Case 7 ' último
EnlaceTabla.MoveLast()
Case 8 ' nuevo
EnlaceTabla.AddNew()
Case 9 ' actualizar
EnlaceTabla.EndEdit()
Actualizar()
End Select
End Sub
Como se puede observar toda la labor de navegación se realiza en la captura de evento de los Button
adecuados y con el uso de los métodos MoveXXXX.
Hacer hincapié en el uso del EndEdit para su correcto funcionamiento a la hora de actualizar.
EnlaceTabla.EndEdit()
Actualizar()
Y del uso de
Case 2 ' borrar
EnlaceTabla.RemoveCurrent()
Para el borrado del registro actual.
1.5.3 La actualización.
Ejecutar el método Update del DataAdapter y emitir el mensaje adecuado.
Private Sub Actualizar()
Conexion.Open()
Try
Adaptador.Update(CType(EnlaceTabla.DataSource, DataTable))
MsgBox("Datos actualizados.", MsgBoxStyle.Information, Me.Text)
Catch ex As OleDb.OleDbException
MsgBox("Datos existentes", MsgBoxStyle.Critical, Me.Text)
End Try
Conexion.Close()
Actualizado = True
End Sub
Tal como está generado el procedimiento, si al pulsar la opción de registro nuevo se coloca un código
existente, se genera la excepción que se captura en el procedimiento.
Si se coloca un código existente, no hay problema el procedimiento lo realiza correctamente.
El borrado se realiza con el RemoveCurrent del Button adecuado.
1.5.4 La salida.
Dada la condición de no grabar hasta que se pulse el botón de actualización en la salida se puede hacer
lo siguiente.
Private Sub Salida()
' Liberar recursos, en este orden, por el FormClosing
Select Case Actualizado
Case False
Select Case MsgBox("Hay datos sin guardar," & vbCrLf & _
"¿desea guardarlos ahora.? ", _
MsgBoxStyle.YesNoCancel, Me.Text)
Case MsgBoxResult.Yes
Actualizar()
Case MsgBoxResult.No
Case MsgBoxResult.Cancel
Exit Sub
End Select
End Select
Me.Close()
Me.Dispose()
Me.Finalize()
Actualizador.Dispose()
EnlaceTabla.Dispose()
Adaptador.Dispose()
Conexion.Dispose()
End Sub
De esa forma se puede advertir al usuario de la situación en ese momento y grabar o continuar.
Para ello es necesario que en el evento KeyPress figure:
Private Sub Campo00_KeyPress( _
ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyPressEventArgs) _
Handles Campo00.KeyPress, _
Campo01.KeyPress, _
Campo02.KeyPress
Actualizado = False
End Sub
1.6 Leer las tablas de una base de datos.
El ejemplo que sigue muestra como leer las tablas de una base de datos de Access, y dejarlas cargada
en un ListBox.
En el ListBox queda cargado el nombre de la tabla, con lo que en el momento de utilizarse se puede usar
para cargar los campos de la tabla seleccionada.
Se utiliza el procedimiento que sigue y la llamada a la función que figura a continuación.
El procedimiento recorre con el bucle For each, la tabla obtenida en la función y la visualiza en el
ListBox.
Public Sub CargarListaTablasBaseDatos( _
ByVal Conexion As System.Data.OleDb.OleDbConnection, _
ByVal Adaptador As System.Data.OleDb.OleDbDataAdapter, _
ByRef Lista As ListBox)
' El paso inicial es obtener la lista de tablas disponibles
' luego se visualiza de modo predeterminado la primera
' tabla de la lista y ordenada por su primera columna
Dim Tablas As DataTable
Tablas = ObtenerTablasBaseDatos(Conexion)
Lista.Items.Clear()
For Each Row As DataRow In Tablas.Rows
'la tercera columna tiene el nombre de la tabla
Lista.Items.Add(Row(2).ToString)
Next
End Sub
Esta función es la que obtiene las tablas de la base de datos, utilizando el objeto Connection.
Public Function ObtenerTablasBaseDatos( _
ByVal Conexion As System.Data.OleDb.OleDbConnection) _
As DataTable
Dim EsquemaTabla As DataTable
EsquemaTabla = _
Conexion.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, _
New Object() {Nothing, Nothing, Nothing, "TABLE"})
Return EsquemaTabla
End Function
1.7 Leer los campos de una tabla.
No tiene ningún misterio, solo se incorpora el contenido de la propiedad Text del ListBox a la cadena
SQL que se envía como parámetro al procedimiento de Carga, que es muy similar, igual, al visto anteriormente
en éste mismo tema, y se enlaza la tabla al DataGrid, incorporando las posibilidades de edición que se desee,
y que en el ejemplo se basa en la configuración del Objeto BindingSource.
Private Sub Lista_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles Lista.Click
Dim CadenaSql as String = "Select * From " & Lista01.Text
' Esta línea realiza el enlace entre el DataGrid y la tabla
ObjDataGrid.DataSource = Me.Enlace
CargaDataGrid(Conexion, Adaptador, Enlace, ObjDataGrid,CadenaSQL)
Edit.Checked = Enlace.AllowEdit
Borrar.Checked = Enlace.AllowRemove
Add.Checked = Enlace.AllowNew
End Sub
Con el contenido de estos dos apartados se puede confeccionar un programa que lea todas las tablas de
la base de datos, y permita su edición.
Para ello solo hace falta un DataGridView, para el contenido de la tabla seleccionada en cada momento
y un ListBox para cargar las tablas de la base de datos.
Después ya incorporar los Button y los objetos en función de la sofisticación que deseemos.
1.8 Las tablas provisionales.
Muchas veces necesitamos por uno u otro motivo del uso de una tabla provisional de trabajo.
El ejemplo que se expone sirve de apoyo a un DataGridView, para la visualización de los datos
seleccionados por el usuario, y es capaz de controlar la duplicidad de un dato introducido por error dos veces.
1.8.1 La configuración.
La tabla de trabajo la creamos a partir de una Select en la cual podemos o no cargar los datos que nos
sean precisos para nuestro programa.
CadenaSql = "Select Movimientos.TipTitulo as Tipo, " & _
"Movimientos.Titulo as Codigo, " & _
"Titulos.Titulo, " & _
"Titulos.PreVenta as Precio, " & _
"Movimientos.Cantidad " & _
"From Movimientos " & _
"Inner Join Titulos On " & _
"(Movimientos.TipTitulo = Titulos.TipPub) and “ & _
“(Movimientos.Titulo = Titulos.Codigo) " & _
"Where Movimientos.Numero = '" & Campo01.Text & "';"
Esta Select, es la que se utilizará para el llenado, o no, de la tabla.
' Crear un nuevo adaptador de datos
Adaptador = New OleDb.OleDbDataAdapter(CadenaSql, Conexion)
' Llenar la tabla con los datos y enlazarza con el 'bindingsource'
Adaptador.Fill(Tabla)
Para el correcto funcionamiento y evitar el duplicado de datos en el DataGridView es necesario crear
una clave principal.
' Se define la restricción
CrearRestriccion(Tabla)
Cuyo procedimiento es el que sigue:
Private Sub CrearRestriccion(ByVal Tabla As System.Data.DataTable)
Dim ColPri(1) As DataColumn
Dim Restriccion As UniqueConstraint
ColPri(0) = Tabla.Columns("Tipo")
ColPri(1) = Tabla.Columns("Codigo")
Restriccion = New UniqueConstraint("Principal", ColPri, True)
Tabla.Constraints.Add(Restriccion)
End Sub
Hay que enlazar la tabla y el DataGridView.
' Se enlaza el objeto
ObjDataGrid.DataSource = Tabla ' EnlaceTabla
'
EnlaceTabla.DataSource = Tabla
De las dos formas funciona, pero es más lógico
ObjDataGrid.DataSource = Tabla
Queda configurar el DataGrid y asignar el ancho de columnas y alineación de las columnas..
Y el procedimiento queda como sigue:
Private Sub CargaDataGrid()
Dim CadenaSql As String
' Se deshace de los datos anteriores
Tabla = New DataTable
CadenaSql = "Select Movimientos.TipTitulo as Tipo, " & _
"Movimientos.Titulo as Codigo, " & _
"Titulos.Titulo, " & _
"Titulos.PreVenta as Precio, " & _
"Movimientos.Cantidad " & _
"From Movimientos " & _
"Inner Join Titulos On " & _
"(Movimientos.TipTitulo = Titulos.TipPub) and “ & _
“(Movimientos.Titulo = Titulos.Codigo) " & _
"Where Movimientos.Numero = '" & Campo01.Text & "';"
Try
' Crear un nuevo adaptador de datos
Adaptador = New OleDb.OleDbDataAdapter(CadenaSql, Conexion)
' Llenar la tabla con los datos y enlazarla con el 'bindingsource'
Adaptador.Fill(Tabla)
' Se define la restricción
CrearRestriccion(Tabla)
' Se enlaza el objeto
ObjDataGrid.DataSource = Tabla ' EnlaceTabla
'
EnlaceTabla.DataSource = Tabla
ConfigDataGrid(Me, ObjDataGrid, False)
Catch ex As OleDb.OleDbException
MsgBox(ex.Message, MsgBoxStyle.Information)
End Try
End Sub
1.8.2 Llenado de la tabla.
Finalizada la parte de configuración ahora queda llenar la tabla.
Para ello se genera un objeto DataRow, el cual al utilizar el método NewRow, queda cargado con la
estructura de la tabla provisional, que sale de la Select, y solo queda cargarlo con datos.
Registro.Item("Tipo") = Titulo.Tipo.ToString
Para luego añadirlo a la tabla.
Tabla.Rows.Add(Registro)
Y si hubiera duplicidad se captura el error en la instrucción Try Catch.
Por lo que el procedimiento queda:
Private Sub AnyadirTitulos()
Dim Registro As DataRow = Tabla.NewRow
Dim Titulo As ItemLista = CType(Lista.SelectedItem, ItemLista)
Dim RegTit As System.Data.DataRow
Registro.Item("Tipo") = Titulo.Tipo.ToString
Registro.Item("Codigo") = Titulo.Codigo.ToString
Registro.Item("Titulo") = Titulo.ToString
Registro.Item("Cantidad") = "0"
Registro.Item("Precio") = Titulo.Precio
Try
Tabla.Rows.Add(Registro)
Catch ex As ConstraintException
MsgBox("Título existente", MsgBoxStyle.Critical, NomProgram)
End Try
End Sub
1.8.3 Lectura de la tabla.
Como el objeto Datagrid es un reflejo del contenido de la tabla, podemos tratar cualquiera de los dos
objetos mediante un bucle por el sistema que deseemos,
con un contador y usando Count,
While X < ObjDataGrid.RowCount And Not Error
Fila = ObjDataGrid.Rows.Item(X)
While X < ObjDataSet.Tables("TablaGrid").Rows.Count And Not Error
Registro = ObjDataSet.Tables("TablaGrid").Rows(X)
ActualizarStock(Registro)
GrabarMovim(Conexion, _
Comando, _
Fec, _
Clientes.Codigo.ToString, _
Clientes.Codig2.ToString, _
Fila.Cells.Item("Tipo").FormattedValue.ToString, _
Fila.Cells.Item("Codigo").FormattedValue.ToString, _
Fila.Cells.Item("Cantidad").FormattedValue.ToString, _
Format(CInt(Campo01.Text), "0000"), _
Error)
o con un objeto del tipo DataRow, o DataGridViewRow y el bucle del tipo For Each in “Objeto”.
Descargar