Agenda telefónica 2 en Visual Basic .NET
Usando DataBinding (enlace de los datos a los controles del formulario) y una base de datos de Microsoft Access

Fecha: 12/Sep/2003 (14/Sep/2003)
Autor: Emilio Pérez Egido (Miliuco) - emi@miliuco.com

 
.

Recordando mi anterior ejercicio "Agenda telefónica en VBasic .NET", publicado en esta sección, se proponía una manera muy sencilla (posiblemente la que más) de conectar con una base de datos de Access, usando el Asistente para Formularios de Datos del propio IDE de Visual Studio. Esta manera de trabajar tiene ventajas evidentes para el principiante:

Pero, junto a esas ventajas, aparecen algunos inconvenientes, de los que, al menos 3, son para tener en cuenta: De todo lo anterior nace la idea del ejercicio actual, esta "Agenda telefónica 2", con 2 premisas fundamentales:

Introducción simple a ADO .NET y DataBinding

Acceso desconectado a datos: En la arquitectura tradicional de tipo cliente / servidor, cada cliente se conectaba a la base de datos, manteniendo la conexión el tiempo necesario para realizar operaciones directamente contra el servidor de base de datos al que está conectado. Obligaba a mantener conexiones de base de datos para todos y cada uno de los usuarios.
Al crecer el tamaño de las bases de datos y el número de clientes (usuarios) potenciales, sobre todo en relación con el fenómeno de Internet, se vio la necesidad de establecer conexiones lo más breves posibles, simplemente para las operaciones inicial (lectura o recuperación de datos) y final (escritura o actualización de datos) sobre el origen de los datos (la base de datos) y trabajar el resto del tiempo sobre una copia desconectada local del origen de los datos (DataSet).
En versiones anteriores de Visual Basic ya existía ADO (ActiveX Data Objects) que permite acceder a todo tipo de bases de datos desde Visual Basic y trabajar en modo desconectado. Visual Basic .NET puede usar ADO, pero ADO .NET es el método preferido por Visual Studio .NET para conectar a bases de datos.
ADO .NET usa clases específicas para efectuar operaciones en bases de datos. Una de las diferencias con respecto a ADO es el uso de comandos específicos de conexión con SQL Server: varias de las clases principales de ADO .NET tienen 2 versiones diferentes, una para conectar a una base de datos SQL Server y otra para proveedores OLE-DB. Como ejemplo, tenemos SQLCommand y OLEDBCommand, SQLConnection y OLEDBConnection, etc. ODBC está desaconsejado, es conveniente usar OLE-DB en su lugar.

DataBinding: es el mecanismo de la plataforma .NET que, en aplicaciones con interfaz WindowsForms, permite crear enlaces entre los objetos que contienen los datos y los controles del formulario. Como ejemplo, se puede enlazar la propiedad Text de un control TextBox con una columna de una tabla del DataSet (la base de datos desconectada), lo que simplifica enormemente las operaciones de navegación por los registros de la tabla.
Objetos importantes del DataBinding:

A continuación sigue código en Visual Basic:



'Agenda telefonica 2 --- Miliuco 07/09/2003
'Ejercicio de acceso a datos:
'- base de datos de Microsoft Access
'- usando DataBinding (enlace  de datos a controles del formulario)


Imports System.Data
Imports System.Data.OleDb

Public Class Inicio
    Inherits System.Windows.Forms.Form

    'Variables declaradas a nivel de clase para poder usarlas desde
    'cualquier procedimiento o función
    Private conn As OleDbConnection = New OleDbConnection 'conexión de tipo OleDb
    Private adaptador As OleDbDataAdapter 'DataAdapter: adaptador de datos
    Private datos As DataSet 'DataSet: conjunto de datos desconectados
    Private enlaceBase As BindingManagerBase 'administrador de los objetos de enlace a datos
    Private comando As OleDbCommandBuilder 'constructor de comandos para el DataAdapter
    Private ruta As String 'almacena la ruta a la base de datos
    Private abierto As Boolean = False 'para saber si ya está abierta la base de datos
    Private cambios As Boolean = False 'para saber si hay cambios pendientes de guardar


#Region " Código generado por el Diseñador de Windows Forms "
#End Region

    'Al cargar el formulario
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Crear tooltip de 2 líneas en el control Icono
        Me.ToolTip1.SetToolTip(Icono, "Emilio Pérez Egido  (Miliuco)" & ControlChars.CrLf _
        & Space(2) & "8 de Septiembre de 2003")
        'Texto inicial de las etiquetas
        lbPrimera.Text = "Pulsa en ""Cargar datos"" para conectarte a la base de datos." & _
                vbCrLf & "Elige la base de datos en el cuadro de diálogo."
        lbSegunda.Text = "Desconectado. Conjunto de datos vacío."
        'Altura inicial del separador Panel1
        Panel1.Height = 5
    End Sub

    Private Sub btCargar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btCargar.Click
        'Si la base de datos está abierta, simplemente informar
        If abierto = True Then
            Dim aviso As String = "La base de datos ya está cargada en el DataSet"
            lbPrimera.Text = aviso.ToUpper
        End If

        'Si la base de datos NO está abierta
        If abierto = False Then
            Try

                'Cuadro de diálogo para elegir la base de datos
                dlgFile = New OpenFileDialog
                dlgFile.Filter = "Base de datos Agenda (*.mdb)|*.mdb"
                dlgFile.Title = "Selecciona la base de datos Agenda"

                'Si el diálogo devuelve OK
                If dlgFile.ShowDialog() = DialogResult.OK Then
                    'Nombre del archivo elegido, con su ruta completa,
                    'equivale a la base de datos
                    ruta = dlgFile.FileName

                    'Cadena de conexión típica de base de datos de Microsoft Access
                    conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" _
                    & ruta & ";User Id=admin;Password=;"

                    'DataAdapter: objeto que hace de puente entre la base de datos
                    'y el DataSet o conjunto de datos
                    adaptador = New OleDbDataAdapter("SELECT * FROM Agenda ORDER BY Nombre", conn)
                    'DataAdapter puede contener sentencias SQL y objetos Command
                    comando = New OleDbCommandBuilder(adaptador)
                    'DataSet: contiene una copia de la base de datos, en esquema XML,
                    'independiente del proveedor, con sus elementos tablas y relaciones.
                    'Es el verdadero almacén de datos desconectados: actuamos sobre
                    'el DataSet desconectado y el DataAdapter se conecta para volcar
                    'los datos entre base de datos y DataSet, en ambos sentidos
                    datos = New DataSet

                    'Abrir la conexión, el DataAdapter llena el DataSet,
                    'cerrar la conexión
                    conn.Open()
                    adaptador.Fill(datos, "Agenda")
                    conn.Close()

                    'Para enlazar controles del formulario con el DataSet usamos
                    'DataBinding; al objeto Binding le pasamos la propiedad del
                    'control que se debe enlazar, el DataSet y la tabla-columna.
                    'Después, el objeto Binding se añade a la colección de enlaces
                    'de datos (DataBinding) del control elegido, con el método Add()
                    Dim enlace As Binding

                    enlace = New Binding("Text", datos, "Agenda.Nombre")
                    txNombre.DataBindings.Add(enlace)
                    enlace = Nothing

                    enlace = New Binding("Text", datos, "Agenda.Teléfono1")
                    txTel1.DataBindings.Add(enlace)
                    enlace = Nothing

                    enlace = New Binding("Text", datos, "Agenda.Teléfono2")
                    txTel2.DataBindings.Add(enlace)
                    enlace = Nothing

                    'Al objeto BindingManagerBase le pasamos el DataSet y la tabla,
                    'desde el contexto de enlace del formulario (BindingContext)
                    Me.enlaceBase = Me.BindingContext(datos, "Agenda")

                    lbPrimera.Text = "Base de datos cargada en el conjunto de datos," & _
                    vbCrLf & "usando DataBinding: Enlace de datos a controles." & _
                    vbCrLf & "Para insertar un registro nuevo, pulsa ""Limpiar campos""," & _
                    vbCrLf & "escribe los datos y pulsa ""Insertar"""
                    lbSegunda.Text = "Archivo de datos: " & ruta

                    'Procedimiento descrito más abajo
                    Call verCuenta()
                    'Para saber que la base de datos ya está cargada
                    abierto = True
                End If

            Catch pollo As Exception
                lbPrimera.Text = pollo.Message.ToUpper
            End Try
        End If

    End Sub

    'Mostrar el registro actual y el total de registros de la tabla del DataSet
    Private Sub verCuenta()
        lbRegistro.Text = "Registro " & Me.enlaceBase.Position + 1 & " de " _
        & Me.enlaceBase.Count
    End Sub

    'Gracias al enlace automático entre controles y datos (DataBinding)
    'es muy sencillo navegar entre los registros y se necesita muy poco
    'código para ello, el objeto enlaceBase (BindingManagerBase) se encarga
    'de actualizar de manera automática el control con los datos de la fila
    'de la tabla en que estamos posicionados
    Private Sub btAvanzar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btAvanzar.Click
        'Si la base de datos está abierta
        If abierto = True Then
            Try
                'Si ya estamos en el último registro
                If Me.enlaceBase.Position = Me.enlaceBase.Count - 1 Then
                    Dim aviso1 As String = "Ya estás en el último registro de la tabla"
                    lbPrimera.Text = aviso1.ToUpper
                Else
                    lbPrimera.Text = "Base de datos cargada en el conjunto de datos." & _
    vbCrLf & "Usando DataBinding: Enlace de datos a controles."
                    'avanzar un registro
                    Me.enlaceBase.Position += 1
                    verCuenta()
                End If
            Catch pollo As Exception
                lbPrimera.Text = pollo.Message.ToUpper
            End Try
            'Si la base de datos NO está abierta
        Else
            Dim aviso As String = "Primero has de cargar la base de datos"
            lbPrimera.Text = aviso.ToUpper
        End If

    End Sub

    Private Sub btRetroceder_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btRetroceder.Click
        'Si la base de datos está abierta
        If abierto = True Then
            Try
                'Si ya estamos en el primer registro
                If Me.enlaceBase.Position = 0 Then
                    Dim aviso2 As String = "Ya estás en el primer registro de la tabla"
                    lbPrimera.Text = aviso2.ToUpper
                Else
                    lbPrimera.Text = "Base de datos cargada en el conjunto de datos." & _
    vbCrLf & "Usando DataBinding: Enlace de datos a controles."
                    'retroceder un registro
                    Me.enlaceBase.Position -= 1
                    verCuenta()
                End If
            Catch pollo As Exception
                lbPrimera.Text = pollo.Message.ToUpper
            End Try
            'Si la base de datos NO está abierta
        Else
            Dim aviso As String = "Primero has de cargar la base de datos"
            lbPrimera.Text = aviso.ToUpper
        End If
    End Sub

    Private Sub btPrimero_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btPrimero.Click
        'Si la base de datos está abierta
        If abierto = True Then
            Try
                'Si ya estamos en el primer registro
                If Me.enlaceBase.Position = 0 Then
                    Dim aviso2 As String = "Ya estás en el primer registro de la tabla"
                    lbPrimera.Text = aviso2.ToUpper
                Else
                    lbPrimera.Text = "Base de datos cargada en el conjunto de datos." & _
        vbCrLf & "Usando DataBinding: Enlace de datos a controles."
                    'ir al primer registro
                    Me.enlaceBase.Position = 0
                    verCuenta()
                End If
            Catch pollo As Exception
                lbPrimera.Text = pollo.Message.ToUpper
            End Try
            'Si la base de datos NO está abierta
        Else
            Dim aviso As String = "Primero has de cargar la base de datos"
            lbPrimera.Text = aviso.ToUpper
        End If
    End Sub

    Private Sub btUltimo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btUltimo.Click
        'Si la base de datos está abierta
        If abierto = True Then
            Try
                'Si ya estamos en el último registro
                If Me.enlaceBase.Position = Me.enlaceBase.Count - 1 Then
                    Dim aviso1 As String = "Ya estás en el último registro de la tabla"
                    lbPrimera.Text = aviso1.ToUpper
                Else
                    : lbPrimera.Text = "Base de datos cargada en el conjunto de datos." & _
                       vbCrLf & "Usando DataBinding: Enlace de datos a controles."
                    'ir al último registro
                    Me.enlaceBase.Position = Me.enlaceBase.Count - 1
                    verCuenta()
                End If
            Catch pollo As Exception
                lbPrimera.Text = pollo.Message.ToUpper
            End Try
            'Si la base de datos NO está abierta
        Else
            Dim aviso As String = "Primero has de cargar la base de datos"
            lbPrimera.Text = aviso.ToUpper
        End If
    End Sub

    'Para borrar un registro
    Private Sub btBorrar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btBorrar.Click
        'Si la base de datos está abierta
        If abierto = True Then
            Try
                'Borrar el registro que se corresponde con la posición actual
                Me.enlaceBase.RemoveAt(Me.enlaceBase.Position)
                lbPrimera.Text = "Se ha eliminado un registro." & vbCrLf _
                & "Pulsa actualizar si deseas guardar los cambios."
                cambios = True
            Catch pollo As Exception
                lbPrimera.Text = pollo.Message.ToUpper
            End Try
            'Si la base de datos NO está abierta
        Else
            Dim aviso As String = "Primero has de cargar la base de datos"
            lbPrimera.Text = aviso.ToUpper
        End If
    End Sub

    'Para vaciar los campos de texto
    Private Sub btLimpiar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btLimpiar.Click
        'Si la base de datos está abierta
        If abierto = True Then
            txNombre.Text = ""
            txTel1.Text = ""
            txTel2.Text = ""
            txNombre.Focus()
            'Si la base de datos NO está abierta
        Else
            Dim aviso As String = "Primero has de cargar la base de datos"
            lbPrimera.Text = aviso.ToUpper
        End If
    End Sub

    'Para añadir un registro
    Private Sub btInsertar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btInsertar.Click
        'Si la base de datos está abierta
        If abierto = True Then
            ''crear una nueva fila en la tabla
            Dim fila As DataRow
            fila = Me.datos.Tables("Agenda").NewRow()
            Try
                'rellenar los campos de la fila nueva
                fila("Nombre") = txNombre.Text
                fila("Teléfono1") = txTel1.Text
                fila("Teléfono2") = txTel2.Text
                lbPrimera.Text = "Se ha insertado un registro nuevo." & vbCrLf _
                & "Pulsa actualizar si deseas guardar los cambios."
                'añadir la nueva fila a la tabla
                Me.datos.Tables("Agenda").Rows.Add(fila)
                cambios = True
            Catch pollo As Exception
                lbPrimera.Text = pollo.Message.ToUpper
            End Try
            'Si la base de datos NO está abierta
        Else
            Dim aviso As String = "Primero has de cargar la base de datos"
            lbPrimera.Text = aviso.ToUpper
        End If
    End Sub

    'Para actualizar el adaptador de datos (DataAdapter) con los cambios hechos en el DataSet
    Private Sub btActualizar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btActualizar.Click
        'Si la base de datos está abierta
        If abierto = True Then
            'Si ha habido cambios en el DataSet desde la última actualización
            If (cambios = True) Then
                Try
                    conn.Open()
                    'Actualizar DataAdapter, se pueden pasar parámetros:
                    ' - (datos as dataset, "tabla" as string)
                    ' - (datos.tables("tabla") as dataset) --> usado aquí
                    Me.adaptador.Update(Me.datos.Tables("Agenda"))
                    'Vaciar el DataSet: conserva los datos de tablas y registros y si no
                    'se limpia acumula las operaciones sucesivas de modificación de filas
                    Me.datos.Clear()
                    'Volver a llenar el DataSet desde el DataAdapter ya modificado
                    Me.adaptador.Fill(datos, "Agenda")
                    conn.Close()
                    'Actualizar la etiqueta lbRegistro
                    Call verCuenta()
                    'Indicador de cambios pendientes a false
                    cambios = False
                    Dim aviso As String = "Base de datos actualizada con los cambios realizados"
                    lbPrimera.Text = aviso.ToUpper
                Catch pollo As Exception
                    lbPrimera.Text = pollo.Message.ToUpper
                End Try
            Else
                '    'Si NO ha habido cambios en el DataSet desde la última actualización
                Dim aviso2 As String = "No hay cambios pendientes de actualizar"
                lbPrimera.Text = aviso2.ToUpper
            End If
            'Si la base de datos NO está abierta
        Else
            Dim aviso3 As String = "Primero has de cargar la base de datos"
            lbPrimera.Text = aviso3.ToUpper
        End If
    End Sub

    Private Sub btSalir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btSalir.Click
        'Si la base de datos NO está abierta
        If abierto = False Then
            'Cerrar el formulario
            Me.Close()
        End If
        If abierto = True Then
            'si NO ha habido cambios en el DataSet desde la última actualización
            If cambios = False Then
                'Cerrar el formulario
                Me.Close()
            End If
            'Si la base de datos está abierta y si además
            'ha habido cambios en el DataSet desde la última actualización 
            If cambios = True Then
                If MessageBox.Show("Hay cambios pendientes de guardar." & vbCrLf _
                & "Pulsa en ""Cancelar"" para volver al programa." & _
                vbCrLf & "Pulsa en ""Aceptar"" para salir sin guardar", _
                "Cambios sin guardar", MessageBoxButtons.OKCancel, _
                MessageBoxIcon.Exclamation) = DialogResult.OK Then
                    Me.Close()
                End If
            End If
        End If
    End Sub

End Class

Imagen del programa en funcionamiento


Agenda telefónica 2

 

Fichero con el código de ejemplo en Visual Studio .NET 2003 (miliuco_agenda2.zip - 90 KB)


ir al índice