Agenda telefónica en Visual Basic .NET Fecha: 23 de Agosto de 2003 (23/Ago/2003) |
. |
Explicación del ejercicio:
La base de este ejercicio está en crear una conexión entre una base de datos de Microsoft Access y un formulario de datos (DataForm) de Visual Basic .NET. De esta manera se consigue mostrar en el programa los registros almacenados en la base de datos de Access.
En este sitio web ya existe un tutorial en la sección de ADO.NET llamado "Ejemplo de acceso a datos con una base de Access" (autor: Guille) que propone realizar todo ésto mediante código escrito "a mano", pero exige un nivel de conocimientos avanzado, por ello propongo este otro ejercicio en el que es muy poco el código que debe escribir el usuario, aunque sí conviene entenderlo para poder retocarlo a nuestro gusto.
Los pasos que debemos seguir son:
- crear una base de datos de Microsoft Access que tenga al menos una tabla (no es imprescindible nada más en la base de datos) con los campos que nos interesen. En el ejercicio son ID, Nombre, Dirección, Teléfono 1 y Teléfono 2. Podemos dejar la tabla (aquí llamada tbAgenda) en blanco, sin registros, y agregarlos directamente desde la aplicación de Visual Basic, pero he comprobado que es más práctico rellenar desde Access unos pocos registros (bastan 3 o 4) para que, al probar la aplicación, sea más ilustrativo cómo se cargan los datos en el formulario de datos.
- comenzar un proyecto nuevo de Visual Basic .NET, del tipo Aplicación de Windows.
- nos olvidamos por ahora del formulario creado por defecto Form1.vb.
- agregar un elemento nuevo, eligiendo el "Asistente para formulario de datos", lo que inicia un asistente.
- elegir el conjunto de datos que deseas utilizar: creamos un nuevo conjunto de datos al que ponemos nombre.
- elegir una conexión de datos: desde el botón "Nueva conexión" abrimos las "Propiedades el vínculo de datos" con 4 pestañas:- proveedor: elegimos Microsoft Jet 4.0 OLEDB Provider.- elegir tablas de la base de datos: elegimos tbAgenda (o el nombre que le hayamos dado).
- conexión: buscamos la base de datos de Access para que aparezca en el cuadro "Seleccione el nombre de una base de datos". Mediante el botón "Probar conexión" sabremos si es factible realizarla.
- el resto de opciones las dejamos como están.
- elegir tablas y columnas para mostrar en el formulario: marcamos las deseadas.
- elegir el estilo de presentación: Registro único en controles individuales, y marcamos aquellos controles que deseamos que aparezcan como botones de comando en el formulario.
- finalizar, y podemos incluir la contraseña en el cuadro de diálogo que nos pregunta sobre ello (por el momento nos despreocupamos de las medidas de seguridad).
- ahora sólo queda modificar el diseño del formulario de datos a nuestro gusto, recordando que es imprescindible cambiar el objeto inicial del proyecto que, por defecto, estará configurado en Form1.vb y debe ser el formulario de datos (aquí DataForm1.vb). Incluso podemos eliminar el formulario Form1.vb después de ello.
NOTA acerca de ordenar los datos y los comandos SQL
Si deseamos que los registros aparezcan ordenados por algún campo, podemos modificar fácilmente la instrucción SQL que se encarga de seleccionar los datos de la tabla que son mostrados en el formulario.
En este ejercicio usamos la clase OleDb del espacio de nombres System.Data que permite el acceso a proveedores de datos que trabajan directamente contra los controladores basados en ActiveX de Microsoft. Si en vez de ello conectásemos con proveedores SQL Server usaríamos la clase SqlClient del mismo espacio de nombres System.Data. La clase OleDb tiene subclases específicas de cada proveedor de datos. De estas subclases, nos interesa la clase OleDbCommand, que representa un comando SQL enviado contra el gestor de datos. En el ejercicio, dentro de la región "Código generado por el Diseñador de Windows Forms", tenemos un objeto del tipo OleDbCommand llamado OleDbSelectCommand1 que se crea en 2 líneas no consecutivas:Friend WithEvents OleDbSelectCommand1 As System.Data.OleDb.OleDbCommand Me.OleDbSelectCommand1 = New System.Data.OleDb.OleDbCommandEste objeto OleDbSelectCommand1 tiene una propiedad de tipo String, CommandText, que contiene la cadena con la sentencia SQL de selección para cargar la tabla en el formulario. Por defecto el comando SQL es:
Me.OleDbSelectCommand1.CommandText = "SELECT Dirección, ID, Nombre, [Teléfono 1], [Teléfono 2] FROM tbAgenda"Esa instrucción SQL simplemente selecciona todos los registros de esos campos de la tabla tbAgenda y los muestra. Pero si queremos ordenarlos por algún criterio, podemos modificar la instrucción en esa línea de código. Por ejemplo, si queremos que los datos aparezcan ordenados por el campo Nombre en sentido ascendente, tendríamos que escribir:
Me.OleDbSelectCommand1.CommandText = "SELECT Dirección, ID, Nombre, [Teléfono 1], [Teléfono 2] FROM tbAgenda ORDER BY Nombre ASC"De esta manera comprobaremos cómo los registros mostrados en el formulario de datos están ordenados por el campo Nombre, lo que puede resultarnos más útil a la hora de desplazarnos por ellos.
A continuación sigue código en Visual Basic:
'Cargar la base de datos Private Sub btnLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoad.Click Try 'Intenta cargar el conjunto de datos. Me.LoadDataSet() 'Avisa de que se ha cargado la base de datos predeterminada MessageBox.Show("La base de datos se ha cargado en el DataSet", "Datos cargados", MessageBoxButtons.OK, MessageBoxIcon.Information) 'Informar en la barra de título del formulario Me.Text = "Agenda telefónica - DATOS CARGADOS" Catch eLoad As System.Exception 'Agregar aquí el código de control de errores. 'Mostrar mensaje de error, si hay alguno. System.Windows.Forms.MessageBox.Show(eLoad.Message) End Try Me.objemiData_PositionChanged() End Sub 'Añadir un registro Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAdd.Click Try 'Borrar las ediciones actuales Me.BindingContext(objemiData, "tbAgenda").EndCurrentEdit() Me.BindingContext(objemiData, "tbAgenda").AddNew() Catch eEndEdit As System.Exception System.Windows.Forms.MessageBox.Show(eEndEdit.Message) End Try Me.objemiData_PositionChanged() End Sub 'Borrar un registro Private Sub btnDelete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDelete.Click If (Me.BindingContext(objemiData, "tbAgenda").Count > 0) Then Me.BindingContext(objemiData, "tbAgenda").RemoveAt(Me.BindingContext(objemiData, "tbAgenda").Position) Me.objemiData_PositionChanged() End If End Sub Private Sub btnUpdate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUpdate.Click Try 'Intenta actualizar el origen de datos. Me.UpdateDataSet() Catch eUpdate As System.Exception 'Agregar aquí el código de control de errores. 'Mostrar mensaje de error, si hay alguno. System.Windows.Forms.MessageBox.Show(eUpdate.Message) End Try Me.objemiData_PositionChanged() End Sub 'Ir al primer registro Private Sub btnNavFirst_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNavFirst.Click Me.BindingContext(objemiData, "tbAgenda").Position = 0 Me.objemiData_PositionChanged() End Sub 'Ir al último registro Private Sub btnLast_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLast.Click Me.BindingContext(objemiData, "tbAgenda").Position = (Me.objemiData.Tables("tbAgenda").Rows.Count - 1) Me.objemiData_PositionChanged() End Sub 'Retroceder un registro Private Sub btnNavPrev_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNavPrev.Click Me.BindingContext(objemiData, "tbAgenda").Position = (Me.BindingContext(objemiData, "tbAgenda").Position - 1) Me.objemiData_PositionChanged() End Sub 'Avanzar un registro Private Sub btnNavNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNavNext.Click Me.BindingContext(objemiData, "tbAgenda").Position = (Me.BindingContext(objemiData, "tbAgenda").Position + 1) Me.objemiData_PositionChanged() End Sub 'Rellenar la etiqueta del panel de navegación Private Sub objemiData_PositionChanged() Me.lblNavLocation.Text = (((Me.BindingContext(objemiData, "tbAgenda").Position + 1).ToString + " de ") _ + Me.BindingContext(objemiData, "tbAgenda").Count.ToString) End Sub 'Actualizar el origen de datos Public Sub UpdateDataSet() 'Crear un conjunto de datos para alojar los cambios realizados en el conjunto de datos principal. Dim objDataSetChanges As Agenda_telefónica.emiData = New Agenda_telefónica.emiData 'Detener las ediciones actuales. Me.BindingContext(objemiData, "tbAgenda").EndCurrentEdit() 'Obtener los cambios realizados en el conjunto de datos principal. objDataSetChanges = CType(objemiData.GetChanges, Agenda_telefónica.emiData) 'Comprobar si se han realizado cambios. If (Not (objDataSetChanges) Is Nothing) Then Try 'Hay cambios que necesitan aplicarse, por tanto, intente actualizar el origen de datos 'llamando al método de actualización y pasando el conjunto de datos y los parámetros. Me.UpdateDataSource(objDataSetChanges) objemiData.Merge(objDataSetChanges) objemiData.AcceptChanges() Catch eUpdate As System.Exception 'Agregar aquí el código de control de errores. Throw eUpdate End Try 'Agregar código para comprobar en el conjunto de datos devuelto los errores que se puedan haber 'introducido en el error del objeto de fila. End If End Sub 'Cargar la base de datos Public Sub LoadDataSet() 'Crear un conjunto de datos para alojar los registros devueltos de la llamada a FillDataSet. 'Se utiliza un conjunto de datos temporal porque el relleno del conjunto de datos existente 'requeriría que se volvieran a enlazar los enlaces de datos. Dim objDataSetTemp As Agenda_telefónica.emiData objDataSetTemp = New Agenda_telefónica.emiData Try 'Intenta rellenar el conjunto de datos temporal. Me.FillDataSet(objDataSetTemp) Catch eFillDataSet As System.Exception 'Agregar aquí el código de control de errores. Throw eFillDataSet End Try Try 'Vaciar los registros obsoletos del conjunto de datos. objemiData.Clear() 'Combinar los registros en el conjunto de datos principal. objemiData.Merge(objDataSetTemp) Catch eLoadMerge As System.Exception 'Agregar aquí el código de control de errores. Throw eLoadMerge End Try End Sub 'Actualizar el origen de datos Public Sub UpdateDataSource(ByVal ChangedRows As Agenda_telefónica.emiData) Try 'Sólo es necesario actualizar el origen de datos si hay cambios pendientes. If (Not (ChangedRows) Is Nothing) Then 'Abra la conexión. Me.OleDbConnection1.Open() 'Intenta actualizar el origen de datos. OleDbDataAdapter1.Update(ChangedRows) End If Catch updateException As System.Exception 'Agregar aquí el código de control de errores. Throw updateException Finally 'Cerrar la conexión independientemente de si se inició una excepción o no. Me.OleDbConnection1.Close() End Try End Sub 'Rellenar el DataSet con los datos Public Sub FillDataSet(ByVal dataSet As Agenda_telefónica.emiData) 'Desactiva la comprobación de restricciones antes de rellenar el conjunto de datos. 'De esta forma los adaptadores pueden rellenar el conjunto de datos sin preocuparse 'de las dependencias entre las tablas. dataSet.EnforceConstraints = False Try 'Abrir la conexión. Me.OleDbConnection1.Open() 'Intenta rellenar el conjunto de datos a través de OleDbDataAdapter1. Me.OleDbDataAdapter1.Fill(dataSet) Catch fillException As System.Exception 'Agregar aquí el código de control de errores. Throw fillException Finally 'Volver a activar la comprobación de restricciones. dataSet.EnforceConstraints = True 'Cerrar la conexión independientemente de si se inició una excepción o no. Me.OleDbConnection1.Close() End Try End Sub Private Sub btSalir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btSalir.Click Me.Close() 'cerrar el formulario End Sub End ClassComentarios finales y propuestas de mejora
Como resumen, hemos visto que, mediante el asistente de formularios de datos, el propio entorno de Visual Studio .NET escribe gran cantidad de código útil por nosotros, lo que facilita la construcción de programas relativamente complejos sin tener conocimientos avanzados de programación.
El programa se mejoraría añadiendo funciones de filtrado o de búsqueda de registros concretos, impresión de informes con listados, etc. Por mi parte, por ahora se queda como está ;-)
Imagen del programa en funcionamiento
(El botón "Abrir datos" se conecta a la base de datos predeterminada)
Fichero con el código de ejemplo en Visual Studio .NET 2003 (miliuco_agenda.zip - 116 KB)