Manual VBNet
Manual VBNet
Net 2003
1
Programación con Visual Basic .NET
El objetivo del curso es proveer a los desarrolladores de software los
conocimientos necesarios para crear aplicaciones en Web y Windows, usando la
plataforma .Net.
Al terminar el curso, el participante estará capacitado para:
o Listar los elementos del Framework y describir los elementos de la nueva
versión de Visual Basic.
o Describir y usar las nuevas estructuras y características del lenguaje Visual
Basic .Net.
o Explicar y usar los conceptos de programación orientada a objetos en
Visual Basic .Net
o Crear aplicaciones usando Microsoft Windows Forms.
o Crear aplicaciones que usen Web Forms.
o Crear aplicaciones usando ADO.Net.
o Crear aplicaciones Multitarea.
o Utilización de reportes con CrystalReport para aplicaciones Windows y
Web.
o ASP .Net.
Contenido
Modulo 1: Introducción a la Plataforma de Microsoft .Net
Objetivos de la infraestructura .Net
El Common Language RunTime o CLR
Lenguaje Intermedio de Microsoft MSIL
Ensamblados
Dominios de aplicación
Recolector de basura
Tipos de Proyectos Disponibles
Analizando la Estructura de Proyectos
El nuevo entorno Integrado
Que son los Ensamblados?
Activando Referencias al Proyecto
Los Espacios de Nombres (Name Spaces)
Activando las Propiedades del Proyecto
Usando el Explorador de Soluciones
Usando el Examinador de Objetos
Usando la Lista de Tareas
Ayuda Dinámica
Depurando Aplicaciones
2
Módulo 2: Adiciones en la Sintaxis y el Lenguaje
Tipos de Dato como Estructuras de Clase
Estructura Común de Tipos
Cambios a los Tipos de Dato Existentes
Conversiones Estrictas
Conversiones de Enlace Tardío
Declarando e Inicializando Variables y Arreglos
Alcance de Variables
Procedimiento o Función
Operadores de Asignación
Llamada a Funciones y Procedimientos
Utilización de Errores y Excepciones
3
Módulo 5: ADO .NET
Por que Ado .Net
Las Clases de ADO .NET
Proveedores de Objetos Conectados
Usando el Objeto Command
Usando el Objeto DataReader
Ejecución de Múltiples Consultas
Proveedores de Objetos Desconectados
Múltiples Consultas Bajo un DataSet
Usando Relaciones dentro de DataSet
Acceder Datos Relacionados
Usando Restricciones(Constraints)
Afectando Datos en un DataSet
Actualizando la Información del Dataset al Origen de Datos
Enlace de Datos
4
Modulo 1: Vistazo a la Plataforma de Microsoft .Net
5
Common Language RunTime o CLR
Todos los lenguajes de .NET utilizan un único Runtime para su ejecución.
Adicionalmente, se centralizan todas las funciones de forma común para los
lenguajes. Por ejemplo, abrir un archivo desde visual se efectúa en forma similar
que desde otros lenguajes de la plataforma .NET (por supuesto dependiendo de
su sintaxis).
A esta característica se le denomina CLR, y es la responsable del cambio de
sintaxis de Visual Basic y demás integrantes del Visual Studio .NET.
CLR asegura también que todos los lenguajes tendrán soporte para orientación a
objetos, como también que no necesitarán preocuparse por el manejo de
memoria, ya que ahora se cuenta con un colector de desechos o basura, el cual
se encarga de esta tarea por nosotros. Ya no importa si olvidó asignar la palabra
nothing , o no se hizo en forma correcta, ya que esta característica se encargará
de liberar la referencia cuando no esté siendo utilizada.
Por otra parte, CLR emplea un nuevo tipo de bibliotecas y ejecutables llamados
Ensamblados, que resuelven los problemas de los DLL.
Esta integración aseguran también un sistema común de tipos de dato, por lo que
utilizar un componente realizado en otro lenguaje es realmente sencillo, ya que las
estructuras son siempre las mismas.
6
directamente las mismas, aunque se muestren dentro de éste como un conjunto
de instrucciones estándares. Por otra parte, el sistema común de tipos también se
sitúa dentro de la misma, al igual que todos aquellos enumerados o constantes
factibles de ser empleadas, lo que hace fácil el compartir conocimiento entre
programadores.
Ensamblados
Todo ensamblado es una biblioteca DLL o EXE que contiene MSIL, y que requiere
las características de CLR para ser ejecutadas.
Los ensamblados son la nueva unidad de módulo ejecutable de .Net, la cual hace
posible resolver los problemas de instalación y coexistencia entre varias versiones
de bibliotecas. A simple vista, no existen diferencias entre componente del
modelo COM y un ensamblado, y , de hecho, ambos terminan ejecutándose de
forma similar desde el punto de vista del usuario. Sin embargo, estos últimos
almacenan dentro de sí mismos la descripción de tipos (métodos, propiedades,
etc.) y demás datos, lo cual elimina totalmente la necesidad de emplear el archivo
de registro como repositorio de información. Decimos entonces que los
ensamblados son unidades auto descriptivas o auto contenidas ejecutables, que
no dependen del archivo de registro, ni necesitan de éste para su correcta
ejecución.
Los ensamblados contienen a grandes rasgos dos secciones, una con la
implementación y otra con la información que contiene el mismo. A esta ultima
se le llama manifiesto, e incluye entre otras el nombre programático del
ensamblado, versión, otros ensamblados de los cuales éste depende, sus
métodos y propiedades, información de seguridad, etc.
Manifiesto
Meta-datos
(Funciones y
ti )
MSIL
Lenguaje
Intermedio
Microsoft
Biblioteca1.dll
Ensamblado1
7
Los ensamblados ofrecen tres características esenciales, las cuales no están
disponibles en código no administrado (el que se construía en versiones
anteriores):
1. Facilidad de Instalación.
2. Componentes privados.
3. Nuevo modelo para componentes compartidos.
Dominios de Aplicación
Cuando un ensamblado EXE o DLL es ejecutado en la plataforma .NET, el mismo
es cargado por CLR dentro de un espacio llamado dominio. Este es similar a un
proceso, ya que de hecho brinda la misma seguridad, pero con un costo de
recursos infinitamente menor. En realidad CLR utiliza un único proceso para todas
las aplicaciones (tanto sean EXE como DLL) y se encarga también de realizar el
aislamiento entre ellos, ver la siguiente figura:
CLR
Aplicación Proceso1 Aplicación Proceso 2
Proceso
EXE
EXE DLL Ensamblado Ensamblado
DLL DLL
DLL
Aplicación Proceso3
Ensamblado
DLL
DLL
EXE
Recolector de Basura
El recolector de basura o desechos es un servicio de la plataforma .NET, y ,más
específicamente provisto por CLR para código administrado. El mismo se encarga
8
de liberar la memoria en forma automática de aquellos objetos que no están
siendo utilizados, sin que el desarrollador tenga que ocuparse de esta tarea.
En las versiones anteriores de Visual Basic, usted podía indicar y conocer el
momento exacto en el cual se deseaba que un objeto fuese liberado, simplemente
asignando nothing a la variable. Esto llevaba a que si el contador de referencias
alcanzaba el valor 0, la memoria ocupada por el mismo era recobrada por el
sistema operativo. A esta función se le denomina finalización determinada, ya que
el desarrollador adquiere control total sobre la misma.
9
Tipos de Proyectos Disponibles
Biblioteca de Clases
Este es el reemplazo (pero no la migración automática) para todos los proyectos
de tipo EXE Activex o DLL Activex construidos en la versión anterior. El mismo
contiene un conjunto de clases, las cuales serán ofrecidas por intermedio de un
ensamblado. El resultado final de este tipo de proyecto es siempre un archivo
(Ensamblado) con extensión DLL, ya que en .NET no se cuenta con biblioteca de
clase con extensión EXE.
10
como contenedor para implementar un control para ser dibujado sobre un
formulario de Windows.
Aplicación Web ASP.NET
Este tipo de aplicación permite trabajar con el modelo de páginas de servidor
activo ASP.NET. Las mismas se componen de formularios web, los cuales son
gestionados por el entorno de desarrollo en forma similar a los formularios
estándar de Windows, pero con la diferencia de que ellos serán posteriormente
transformados a ASP.NET, y finalmente a HTML o DHTML. Debido a ello, el
resultado final es siempre accesible desde cualquier explorador. Este tipo de
proyecto elimina la necesidad de la herramienta Visual Interdev, o los lenguajes de
código script del lado servidor.
Aplicación de Consola
Los proyectos de este tipo permiten crear aplicaciones que no requieran de
interfaz gráfica, y que se puedan valer simplemente de texto. El resultado de la
misma puede ser exhibido a través de una ventana de consola, en forma similar a
lo que hacían las aplicaciones del sistema operativo DOS. Existen también formas
de interactuar con la consola, a los efectos de escribir o leer una cadena de texto
del teclado o de la pantalla.
Servicio Windows
Ahora es posible crear un servicio Windows, cosa que era bastante complicada de
implementar en versiones anteriores, ya que se debía apelar a un críptico conjunto
de API del sistema operativo.
11
Analizando la Estructura de Proyectos
Cada proyecto contiene una variedad de archivos de solución para cada tipo de
proyecto. Para simplificar el manejo, los archivos del proyecto son almacenados
en el directorio del proyecto.
12
El nuevo entorno Integrado
A) Barra de
Herramienta E) Proyectos
s y Menús abiertos
propiedades,
ayuda, etc.
B) Cuadro de
Herra-
mientas y
explorador
servidores
D) Área de
diseño y
edición
C) Opciones
referentes a
compilación,
o lista de
tareas
pendientes
1. Ventanas acoplables.
2. Pestañas.
3. Ocultamiento automático.
La idea principal de las ventanas acoplables, es que se peguen unas con otras,
con el fin de reducir la cantidad de espacio utilizado (sector E).
También es posible emplear pestañas, con el fin de que sólo una de ellas este
visible a la vez (sector D).
13
Que son los Ensamblados?
<Assembly: AssemblyTitle("")>
<Assembly: AssemblyDescription("")>
<Assembly: AssemblyCompany("")>
<Assembly: AssemblyProduct("")>
<Assembly: AssemblyCopyright("")>
<Assembly: AssemblyTrademark("")>
Basta con escribir la información deseada dentro de las comillas, para que la
misma sea contenida posteriormente por el compilado y exhibida cuando se haga
botón derecho y luego propiedades sobre el ensamblado EXE o DLL desde el
explorador de Windows.
Se incluye también una carpeta de referencias, la cual almacena todos los
nombres de los ensamblados que puede requerir la aplicación para se ejecutada.
Esta característica se constituye como una ventaja sustancial con respecto a
versiones anteriores, ya que ahora basta con expandir la misma para conocer sus
dependencias (ensamblados DLL).
Los ensamblados son creados automáticamente cuando se compilan los archivos
fuente de Visual Studio .NET.
14
Activando Referencias al Proyecto
15
Los Espacios de Nombres (Name Spaces)
Los espacios de nombres son paquetes que pueden contener clases, interfaces y
módulos dentro de una estructura fácil de entender. Se encuentran organizadas en
forma jerárquica y no plana, similar a lo que seria una estructura de carpetas del
sistema de archivos.
Sintaxis
Imports [alias=] <Espacios de nombre separados por punto>
Imports System.IO
Este ejemplo muestra cómo indicar que se utilizarán las clases del subes
pació IO, del espacio principal System, las cuales se encargan de la manipulación
de entrada y salida a archivos, memoria, etc. Una vez realizada la misma, es
posible hacer uso en el lenguaje de las clases allí existentes, por ejemplo de la
siguiente forma:
Cada espacio de nombres puede contener otros, y cada uno de ellos puede incluir
a su vez una o varias clases. El paquete raíz más importante de la jerarquía se
llama System, y es aquel que almacena la mayor parte de los espacios de
nombres y clases.
Mediante la palabra Imports se le advierte a Visual Basic de que deberá
proporcionar un acceso rápido para todas las clases existentes en el espacio de
nombres. Basta entonces con realizar la importación correspondiente, para que
sea posible emplear las clases sin necesidad de tener que adjuntar la ruta a la
misma.
Las sentencias de importaciones deben de ir al comienzo de cada módulo, y tiene
alcance del mismo. De esta forma, cada una de ellas estará asociada con cada
uno de éstos . A su vez, muchos de los módulos en Visual Basic agregan en forma
automática importaciones, las cuales son utilizadas directamente por el lenguaje,
con el fin de facilitar el acceso a las diferentes funcionalidades.
16
Creando Namespaces
NameSpace AccesoADatos
Public Class Cliente
‘ Implementación
End Class
End NameSpace
17
Namespace AccesoADatos
Public Class Cliente
‘Implementación
End Class
End NameSpace
Namespace Impuesto
Public Class ClacTasa
‘ Implementación
End Class
End Namespace
Para utilizar alguna de las clases se debe nombrar siempre el espacio respectivo,
aun que es posible también hacer uso de la palabra Imports, la cual permite
establecer un acceso rápido a la misma.
Imports AccesoADatos
Imports Impuesto
Sub Ejemplo()
Dim MisClientes as New Cliente()
Dim MiTasa as New CalcTasa()
End Sub
End Class
Por otra parte, los espacios de nombres pueden ser anidados, lo que facilita la
organización jerárquica de las estructuras.
Namespace AccesoADatos
Namespace Oracle
Public Class Cliente
‘Implementación
End Class
End Namespace
18
Namespace SQLServer
Public Class Socio
‘Implementación
End Class
End Namespace
End Namespace
Para acceder a las mismas se deberá mencionar cada uno de los espacios
referidos y por ultimo el nombre de la clase.
19
Importando Namespaces
Namespace AccesoADatos
Namespace Lectura
Namespace SeccAtenCliente
Namespace SQLServer
‘ Implementación de clases
End Namespace
Namespace SQLServer
‘ Implementación de Clases
End Namespace
End Namespace
End Namespace
End Namespace
Evidentemente, cada vez que desee definir una variable del tipo de la clase, se
deberá referir a cada uno de los espacios involucrados. Si bien puede resultar muy
mnemónico y estructurado, normalmente no deseara escribir esto en más de una
ocasión.
Afortunadamente, se cuenta con una solución y lo suficientemente flexible para
adecuarse a la mayoría de las casos, la cual consiste en hacer uso de la
instrucción imports, que debe ser incluida en la zona de declaraciones del módulo,
con el fin de crear un acceso rápido a las clases contenidas por el mismo.
Imports AccesoADatos.Lectura.SeccAtenCliente
Dim X as AccesoBD.SQLServer.MiClase
20
Activando las Propiedades del Proyecto
Cuando se está implementando un nuevo proyecto en Visual Basic .NET (ya sea
para Windows o para la Web), existen varias opciones que pueden condicionar la
forma en que el mismo será tratado posteriormente por el diseñador de
formularios, compilador o depurador. Haciendo clic derecho sobre el proyecto y
seleccionando propiedades, o marcando la opción de Propiedades en el menú de
Proyecto, es posible acceder y modificar las mismas.
La ventana de propiedades involucra más elementos que los que tenía la versión
anterior y, a su vez, dispuestos de diferente forma. La expansión de las mismas se
debe principalmente a dos factores, el primero es la integración del producto con
la infraestructura .NET, mientras que el segundo es debido a los nuevos tipos de
plantillas de proyecto con que ahora se cuenta. Las opciones se almacenan
debajo de las siguientes carpetas:
21
Propiedades Comunes Descripción
General Permite especificar el nombre del ensamblado EXE o DLL, el tipo
de aplicación, el objeto de inicio y el espacio de nombres al cual
pertenecerá el mismo.
Generar Hace posible establecer los valores por defecto a utilizar durante el
proceso de compilación, así como también el icono de la aplicación.
Las opciones de Option Explicit y Option Compare son ya
habituales para un desarrollador Visual Basic.
Importaciones Permite indicar los espacios de nombres que deberán ser
importados para el proyecto.
Ruta de acceso de referencia Indica las carpetas en donde estarán situados los ensamblados
adicionados al proyecto mediante la ventana de referencias.
Valores predeterminados del Contiene varias características que afectan únicamente a las
diseñador aplicaciones para el web (ASP.NET). las opciones superiores
indican las pautas a seguir por el diseñador de formularios, mientras
que la inferior especifica el lenguaje que será utilizado por el Código
Script para ser ejecutado del cliente.
22
Usando el Explorador de Soluciones
23
Usando el Explorador de Servidores
Las aplicaciones creadas con Visual Studio pueden consistir en uno o varios
componentes, los cuales pueden estar situados en diferentes equipos
comunicados a través de una red. La ventana de Explorador de Servidores
permite centralizar el monitorizado y gestión de las distintas características de los
mismos, sin necesidad de salir del entorno de desarrollo.
Dicha ventana esta localizada encima del cuadro de herramientas como elemento
ocultable automáticamente. Cada nodo representa los diferentes servidores, y los
elementos hijos a sus características. Veamos entonces qué funcionalidades son
provistas por las mismas:
o Colas de mensajes.
o Contadores de rendimiento.
o Servicios.
o Servicios de Crystal.
o Lista de procesos (es posible iniciar o detener cualquiera de ellos).
o Registro de eventos. Esto incluye: Aplicación, Seguridad Y sistema
(similar a los ofrecidos por NT)
o Bases de datos SQL Server.
24
Usando el Examinador de Objetos
Libreria
25
Usando Lista de Tareas
Usted puede usar esta característica para mantener una lista de tareas con las
que trabajara, o les dará seguimiento, podrá eliminar las tareas al ser
completadas. Las tareas son conservadas dentro del archivo del proyecto .suo,
para que estas no se pierdan cuando cierra su sesión de Visual Studio .Net.
Cualquier tarea cargada será disponible para todos los desarrolladores que usen
el mismo archivo del proyecto .suo.
Para abrir la ventana Lista de Tareas, selecciónela en la opción de Otras
Ventanas en el menú de Ver.
26
Ayuda Dinámica
Dim x as Integer
Usted puede usar la caja de dialogo Options, que se encuentra dentro del menú
Tools, para configurar los elementos que la ventana de ayuda desplegará. La
siguiente ventana muestra la caja de dialogo de Options:
27
Depurando Aplicaciones
28
La siguiente ventana muestra un punto de interrupción condicionado, cuando el
valor de la caja de textos valor.text sea igual a 100.
Como beneficio adicional, estos son guardados en forma conjunta con el proyecto,
por lo que la próxima vez que abra el mismo, encontrará las marcas previamente
configuradas.
La Ventana de Comandos
La ventana de comandos permite evaluar expresiones principalmente durante el
proceso de depuración. Tiene cierto parecido con lo que se conocía como ventana
de Inmediato en versiones anteriores. Sin embargo, brinda algunas opciones más
avanzadas, las cuales describiremos a continuación.
Para acceder a la misma basta con ir al menú Ver, luego Otras Ventanas, y por
último Ventana de Comandos, o presionar CTRL-ALT-A (aunque en tiempo de
ejecución es mostrada por defecto).
Si desea evaluar una variable, propiedad o expresión, durante la depuración,
basta con escribir >Debug.Print x o >? x.
espacio
Si desea blanquear el contenido de la ventana de comandos debe escribir la
instrucción cls.
29
Esta ventana también permite ejecutar elementos del menú en forma de
comandos de texto. Por ejemplo, la siguiente línea busca debajo de la carpeta y
subcarpetas del proyecto aquellos archivos que contengan el texto AlexLora, y
posteriormente muestra los resultados.
>Edit.FindInFiles “AlexLora”
La Ventana de Inspección
La ventana de inspección es normalmente exhibida en la parte inferior derecha de
la pantalla, y hace posible observar el contenido de una variable, (véase la
siguiente figura). Basta con escribir dentro de ella el nombre de la misma para
conocer su valor y tipo.
La misma permite también modificar el contenido del elemento que está siendo
evaluado, simplemente haciendo clic sobre la columna que contiene su valor y
escribiendo uno nuevo.
Esta ventana solo la puede ver y abrir estando en ejecución el proyecto. Para
abrirla basta seleccionar Inspección en la opción de Ventanas en el menú
Depurar.
30
La ventana de Automático
La ventana de automático ofrece funcionamiento similar a la de inspección, pero
incluye por defecto todas las variables empleadas dentro del procedimiento, con
sus respectivos valores y tipos.
Podemos acceder a ella en el menú Depurar en la opción Ventanas y Ventana
de Automático.
La ventana de Locales
La ventana de locales es similar a la inspección y automático, pero incluye todas
las variables y propiedades de componentes, que son visibles por el procedimiento
en el cual se localiza el punto de ejecución.
Podemos acceder a ella en el menú Depurar en la opción Ventanas y Ventana
de Locales.
31
Módulo 2: Adiciones en la Sintaxis y el Lenguaje
Los tipos de dato definidos en Visual Basic tales como enteros, enteros largos,
cadenas de texto, etc., correspondían en versiones anteriores a elementos
estándares definidos en el Runtime del lenguaje, pero en esta nueva versión todos
los tipos de dato han sido convertidos en estructuras de clase. Por ejemplo en la
versión anterior:
Debido a que todos los tipos de dato son clases, los mismos pueden incluir
funcionalidades asociadas a ellos en forma de métodos y propiedades (ver la
siguiente figura). Por otra parte, las conversiones que requerían el empleo de
funciones independientes son ahora realizadas mediante métodos asociados al
tipo de dato.
32
Al existir un único repositorio común con la definición de los mismos, se facilita la
utilización de ensamblados implementados en otros lenguajes de la plataforma
.NET, ya que un tipo de una precisión determinada será el mismo tipo para todos
los integrantes que hagan uso de la infraestructura. Sin embargo, este cambio
afecta a la forma en que los mismos deberán ser utilizados.
La asignación de versiones anteriores entre tipos y objetos no estaba permitida,
pero ahora es posible debido a que todas las variables son de este tipo. A su vez,
se utilizaba la palabra Set para asignar una variable de objeto, la cual ha sido
eliminada totalmente del lenguaje, por lo que la siguiente línea:
iContador = iVal
Este ejemplo muestra cómo se copia una variable de objeto a otra, pero no debe
confundirse esto último con que ambos apunten a la misma instancia de memoria.
El siguiente ejemplo muestra cómo transformar una variable de tipo entero largo a
cadena de texto, empleando uno de sus métodos intrínsecos.
Telefono = 7825845
Lada = “(461)”
33
debido a que el recolector de basura detecta cuándo el mismo no está siendo
utilizado y libera la memoria ocupada por éste. Sin embargo, gran parte de las
clases ofrecen un método llamado dispose, el cual obliga al colector a liberar la
misma tan pronto como éste sea invocado. Sin embargo, esto puede redundar en
una caída momentánea del rendimiento de la aplicación.
Todos los tipos de dato ahora se corresponden con estructuras de clase definidas
en la infraestructura .NET (en la clase System.Object), por lo que el lenguaje se
remite estrictamente a emplear éstos. En realidad, los tipos de dato originales
tienen nombres <<extraños>> para Visual Basic, por lo que este último le brinda
un seudónimo más acorde y amigable, con el fin de lograr una apariencia similar a
la que se tenía en versiones anteriores. A continuación se muestra la estructura
tipos definidos dentro del espacio de nombres System.Object:
34
Cambios a los Tipos de Dato Existentes
Currency
Un Cambio Importante a tener en cuenta radica en que el tipo de dato Currency no
está soportado, por lo que en su lugar se debe hacer uso de Decimal. El mismo
cuenta con características similares, ya que provee soporte para valores muy
grandes.
Integer
Hay cambios en la capacidad de los tipos de dato entero y entero largo. Donde en
versiones anteriores se utilizaba un entero (Integer) ahora se debe emplear el tipo
de dato Short. De forma similar, lo que representaba un entero largo (Long), ahora
se debe definir como un entero (Integer).
String
Un tipo de datos String en la plataforma .NET es inmutable, y esto quiere decir
que una vez asignado un valor, el contenido del mismo no será modificado. De
esta forma cualquier intento de modificación de un elemento de la cadena o todos
derivará en un nuevo objeto de tipo String, mientras que el objeto original será
destruido. Por supuesto que este proceso es trasparente para el desarrollador,
pero puede influir seriamente en el rendimiento final de la aplicación.
Imagine una aplicación que realice 52 modificaciones sobre una cadena de 400
KB. Cada vez que ésta sea modificada, será creada una nueva instancia del
objeto conteniendo la nueva cadena. Lo mismo pasa si se concatenan dos de
ellas, lo que derivará en una nueva cadena conteniendo el resultado, como
muestra la siguiente figura:
160Kb 140Kb
300Kb
Basta con que la aplicación tenga que realizar esta tarea en reiteradas ocasiones
para que se obtenga como consecuencia un consumo excesivo de tiempos y
recursos.
Con el fin de gestionar este tipo de situaciones, la biblioteca de clases, BCL,
ofrece una alternativa que permite la modificación de los elementos, sin que ello
derive en la creación de una nueva instancia del objeto, y para dicho fin se cuenta
con una clase llamada StringBuilder. La misma representa un espacio de memoria
(Buffer), y contiene métodos para gestionar su contenido, sin que ello derive en la
creación de una nueva instancia de objeto.
35
Dim NombreAlumno as New System.Text.StringBuilder
Imports System.Text
.
.
Dim NombreAlumno as New StringBuilder
En este caso, el tamaño inicial del texto será de 60 caracteres, aunque si la misma
es sobrepasada, ésta será expandida automáticamente. Una vez creado el objeto,
el mismo quedará apto para ser utilizado.
La manipulación de la información que debe ser guardada se logra mediante el
conjunto de métodos asociados a la clase.
NombreAlumno.Append(“Hola Abraham”)
Cadena = NombreAlumno.ToString
El método Append permite que una cadena de texto sea copiada dentro del objeto
StringBuilder. Para asignar el contenido de un objeto StringBuilder a uno String, el
mismo debe ser siempre convertido.
Por otra parte, la inserción, eliminación y reemplazo se logra mediante los
métodos Insert, Remove y Replace, respectivamente.
NombreAlumno.Append(“Hola Abraham”)
NombreAlumno.Replace(“Abraham”,”Juan Pablo”)
NombreAlumno.Insert(NombreAlumno.Length, “!!”)
Msgbox(NombreAlumno.ToString)
36
Sin duda, la clase StringBuilder ofrece una característica importante a la hora de
obtener un rendimiento más optimo en lo que a manejo de cadenas de refiere.
For i = 1 To 5000
Cadena = Cadena & "Prueba de Concatenación"
Next i
TiempoString.Text = Now.Subtract(Inicio).TotalSeconds & "Segundos"
End Sub
37
A continuación agregue el siguiente código al botón de PruebaStringBuilder
Date
Algunos desarrolladores utilizaban en versiones anteriores el tipo de dato doble
para almacenar fechas. En efecto, las fechas eran en realidad información de tipo
doble bajo el tipo Date. Visual Basic no ponía ninguna restricción, y de hecho
ambos podían ser intercambiados en cualquier momento sin ningún efecto
secundario.
En esta versión se utiliza un formato propio de fecha y fecha/hora, el cual no
guarda relación con el doble.
Fecha = now
-ToA2Date
-FromOADate
38
Los mismos permiten convertir una fecha y hora a double o viceversa. La
utilización es sencilla, ya que simplemente se debe invocar a uno u otro método
sin necesidad de pasos previos, o información adicional.
FechaHora = Now
39
Conversiones Estrictas
Option Strict On
Dim Texto as String
Dim Numero as long
Texto = “52”
‘Esta Línea produce error
Numero = Texto
MsgBox(Numero)
Texto = Cstr(Numero)
Texto = Numero.ToString
Visual Basic cuenta además con varias palabras Option que pueden especificar
controles adicionales a realizar por el compilador:
40
Conversiones de Tipos de Dato con Enlace Tardío
Para utilizar enlace tardío con la opción estricta, se debe apelar a la función Ctype,
la cual permite convertir un tipo en otro en forma explícita, corriendo por parte del
desarrollador el riesgo de que en tiempo de ejecución el tipo sea el que se indica.
Sintaxis:
41
Declarando e Inicializando Variables y Arreglos
La inicialización puede también incluir una constante, así como llevarse a cabo de
la forma habitual:
Numero = 20
Una técnica similar de inicialización puede emplearse para las matrices, pero
dicha técnica es utilizada para precargar en tiempo de diseño los diferentes
valores de la misma.
El ejemplo anterior declara una matriz de 5 elementos con sus respectivos valores,
utilizando a su comienzo y final llaves. También es posible cargar valores para una
matriz bidimensional, pero se debe agregar una coma en medio de los paréntesis:
Los cambios en las matrices vienen dados por las funcionalidades que éstas
adquieren en esta nueva versión.
En muchas aplicaciones es común agrupar un conjunto de variables sin hacer uso
de una clase. Para dicho fin se cuenta con los tipos de dato definidos por el
usuario (UDT User Defined Type), los que permiten ofrecer un conjunto de
elementos bajo una misma entidad. En versiones anteriores de Visual Basic, una
estructura definida por el usuario se veía de la siguiente forma:
42
En Visual Basic .NET la sintaxis sufre un pequeño cambio, que además ofrece la
posibilidad de modificar la visibilidad de cada uno de sus miembros.
Otra característica muy comúnmente empleada eran las variables de texto con
longitud fija. Para ello se debía incluir en la declaración el número de caracteres
antecedido por un asterisco.
Visual Basic generaba un texto con longitud especifica, rellenando las posiciones
sobrantes con el caracter ASCII 0. en esta versión dicha característica no existe
en forma directa.
Esto puede ser de utilidad cuando se espera una variable de dicho contenido, pero
si se asigna un nuevo valor, ésta adquirirá automáticamente el nuevo largo.
En Visual Basic 6 usted podía declarar en una sola línea múltiples variables, pero
usted podría obtener resultados inesperados. Considere el siguiente ejemplo:
En Visual Basic .NET las tres variables son creadas de tipo entero. Esto es
consistente con la mayoría de los lenguajes de programación y más intuitivo.
43
Alcance de Variables
Módulo
Cuando una variable se define en la zona de declaraciones de un módulo, ésta se
hace visible a todos los integrantes de la aplicación. Para agregar un módulo,
basta con hacer botón derecho sobre el proyecto en el Explorador de Soluciones y
luego Agregar y posteriormente Agregar Módulo.
Module Module1
End Module
Por la nueva sintaxis que se le agrego a los módulos, ahora se podría definir más
de un módulo dentro de un solo archivo.
Module Module1
Public Var1 As Long
End Module
End Sub
Clase o Formulario
El segundo tipo de de visibilidad es aquella que involucra los módulos de clases o
formularios. Puede accederse a toda variable definida como pública en la zona de
declaraciones de los mismos, desde los demás integrantes del proyecto, pero
éstos deberán incluir el nombre del objeto donde ella reside.
44
Public Class Negocio
Public Interes as Long
Sub CalcularMontoInteres()
End Sub
End Class
Para acceder a la misma, basta con definir un objeto de este tipo y asignar o leer
el valor de igual forma que si se tratara de una propiedad.
Negocio.Interes = 10
Procedimiento o Función
El tercer tipo de variable corresponde a la definición en un procedimiento o
funciones. Toda variable declarada dentro del mismo procedimiento será visible
exclusivamente por éste (debe usar la palabra DIM en vez de Public o Private
cuando se defina una Variable de Procedimiento o función).
Sub Proc1
Dim Var1 as Long
Var1 = 10
End Sub
Bloque
Existe un cuarto tipo de visibilidad, el cual viene dado por la utilización de
subbloques dentro de un procedimiento o función. Todas las variables definidas
45
dentro de ellos serán visibles exclusivamente por el mismo, y su vida estará
condicionada a la finalización de éste.
Dim i as Integer
For i = 1 to 10
Dim Y as Boolean = False
Y = Not Y
MsgBox(Y)
Next I
Y = True
De esta forma Y será visible solamente por el bloque For, y cualquier intento de
acceder desde fuera del mismo producirá un error de compilación.
Cuando el punto de ejecución llega al bloque, las variables allí definidas serán
creadas, y destruidas una vez que finalizo el mismo. La visibilidad de este tipo de
variables se hace extensible también para aquellos bloques anidados.
Como excepción, no pueden existir dos variables con igual nombre dentro del
procedimiento, aunque pertenezcan a diferentes bloques.
46
Operadores de Asignación
En Visual Basic .NET se incluyen nuevos operadores, los cuales ponen el lenguaje
a la altura de los demás.
Sintaxis
Variable &= expresión
Ejemplo:
Dim Cadena as String
Cadena = “Hola ”
Cadena &= “Abraham”
MsgBox(Cadena)
Ejemplo:
Num1 = 10
Num2 = 100
Num1 *= Num2
Resultado
Num1 = 1000
Num2 = 100
47
Llamada a Funciones y Procedimientos
Usted debe usar paréntesis para encerrar a los parámetros en cualquier función o
subrutina. Si usted llama a un procedimiento que no tiene parámetros, usted debe
incluir los paréntesis vacíos.
Parámetros Opcionales
Ahora en esta nueva versión los parámetros opcionales deberán incluir su valor
por default. El siguiente ejemplo muestra la declaración de los parámetros
opcionales:
Visual Basic .Net ofrece facilidades para retornar valores desde una función.
Usted puede usar el nombre de la función para retornar el valor de una función.
48
Usted puede usar sentencia Return para regresar el valor de una función. Esto
evita ligar el regreso con el nombre de la función. Permitiendo facilitar el regreso
de la función
49
Utilización de Errores y Excepciones
En este caso el Catch capturará todos los errores producidos dentro de Try, pero
no discriminará de qué tipo se trata. A su vez, los bloques Try pueden ser
anidados, por lo que un bloque de captura de excepción puede a su vez contener
otro.
Si se produce un error dentro del bloque Try, automáticamente CLR dará paso al
código incluido por el bloque Catch. Después de discriminar la excepción y
ejecutar el código alternativo, se llevará adelante la ejecución del contenido de la
sección Finally.
En el caso de que no se produzca una excepción, la sección de Finally será
ejecutada una vez finalizado con el contenido Try.
50
Dim i1, i2, iResult As Decimal
i1 = 22
i2 = 0
Try
iResult = i1 / i2
MsgBox(iResult)
Catch eexception As DivideByZeroException
MsgBox(eexception.Message)
Finally
Beep()
End Try
Nombre Descripción
DivideByZeroException Se inicia al intentar una división por cero
InvalidCastException Se inicia cuando un tipo de dato no puede ser
convertido.
IOException Se inicia cuando existe algún error al intentar
acceder a un archivo.
IndexoutOfRangeException Se inicia cuando se intenta acceder a un
elemento de una matriz, empleando un índice
fuera de los límites.
También es posible capturar una excepción sin importar el tipo involucrado. Para
ello basta hacer uso de la clase base, la cual se denomina Exception.
En el siguiente ejemplo el catch atrapa el error de división por cero, haciendo uso
de la clase base.
51
La Clase System.Exception
Propiedades
Nombre Tipo Descripción
HelpLink Lectura / Escritura Hipervínculo relacionado a la misma.
InnerException Lectura Referencia a una excepción interna.
Message Lectura Descripción del error.
StackTrace Lectura Información de la pila de llamados.
Source Lectura / Escritura Nombre de la aplicación, o el objeto
que causó el error.
TargetSite Lectura Referencia al método que genero la
excepción.
Métodos
Nombre Tipo Descripción
GetBaseException Lectura Obtiene la excepción inicial en la
cadena de excepciones.
ToString Lectura Convierte el contenido de la excepción
en un texto (nombre de la excepción,
mensaje de error, nombre de las
excepciones contenidas, valor de la
pila, etc.)
52
Las excepciones cuentan también con una propiedad llamada StackTrace, la cual
hace posible obtener toda la información respectiva a los métodos, archivos y
líneas relacionados a la misma.
53
Excepciones Anidadas
Las estructuras de manejo de error, al igual que las de excepción, hacen posible
que las mismas puedan ser iniciadas y posteriormente capturadas, ya sea por el
procedimiento que genero la misma como por cualquiera de los involucrados en la
pila. Debido a ello, varios procedimientos podrían estar envueltos en la captura y
posterior gestión de la misma.
Sub Principal()
Try
Call RealizaOperación()
Catch eExceptionPrincipal As Exception
Dim Excepción As Exception
Do
Excepción = eExceptionPrincipal.InnerException
MsgBox(Excepción.Message)
Loop Until Excepción Is eExceptionPrincipal.GetBaseException
End Try
End Sub
54
En este caso se generará una excepción empleando el texto especificado, pero
adjuntando a ésta la original, la cual a su vez podría contener otras excepciones.
Esto produce que se envíe un conjunto de excepciones anidadas en vez de un
único elemento. Para extraer las excepciones contenidas se cuenta con un
método llamado InnerException, el cual retorna la referencia a la misma.
Excepción = eExceptionPrincipal.InnerException
eExceptionPrincipal.GetBaseException
Cada iteración del ciclo obtendrá una excepción anidada y la exhibirá. El mismo
finalizará cuando el valor sea igual a la excepción base.
55
Módulo 3: Programación Orientado a Objetos para Visual Basic .Net
Introducción
La programación orientada a objetos es un paradigma increíblemente poderoso y
natural para crear programas que sobrevivan a los cambios inevitables que
acompañan al crecimiento y mantenimiento de cualquier aplicación. Debido a que
cada clase es auto contenida y mantiene interfaces (métodos y propiedades) para
su acceso, es posible llevar a cabo sistemas que consten de cientos de ellas
interactuando entre sí con mucha facilidad.
La orientación a objetos u OOP(Object Oriented Programming) es un conjunto de
características adicionales que un lenguaje puede ofrecer, y más concretamente
relacionadas a las estructuras de clase. A continuación se resumen algunas estas
características:
Abstracción
Esta característica permite concentrarse en lo que hace, pero no en como lo hace.
Mediante esta, es posible usar un objeto conociendo solamente las características
que nos interesan del mismo, y manteniendo oculta la forma en la cual lo hace.
Lógicamente, esto nos brinda el gran beneficio de la facilidad.
Encapsulación
Brinda la posibilidad de esconder la implementación, y proveer el acceso a través
de una apariencia estándar llamada interfaz. Una interfaz es una colección de
métodos y propiedades, aunque en algunos lenguajes se incluye también la
definición de eventos de la misma. De esta forma, la clase puede ofrecer una o
varias de éstas para interactuar con sus funcionalidades, sin necesidad de
exponer directamente su implementación. Esta característica mejora la
integración entre aplicaciones, ya que se emplea una forma estándar de
utilización.
Agregación
Hace posible que una propiedad de una clase puede contener otras clases. En
general las capacidades de encapsulación y agregación trabajan en conjunto, ya
que varias clases podrían estar incluidas dentro de una misma estructura.
Herencia
Una clase puede heredar las funcionalidades de otra ya existente, con el fin de
ganar sus cualidades, y posteriormente adicionar, eliminar y hasta sobrescribir los
miembros originales. En algunos lenguajes se permite que una clase pueda
heredar las características de varias de ellas, y a esto se le domina herencia
múltiple.
Polimorfismo
El termino significa <<un objeto y muchas formas>>, y hace posible que un
método de una clase (función o procedimiento) pueda tener diferentes
comportamientos teniendo en cuenta el o los tipos de dato utilizados en su
invocación. Una clase llamada Operaciones que contenga un método Suma y que
56
acepte dos argumentos podría ejecutar implementaciones diferentes si es
invocada con tipos de datos distintos.
Módulos de Clase
En Visual Basic .NET la mayoría de los módulos que se utilizan son de clase y, de
hecho, cada uno de ellos incluye explícitamente el tipo de archivo al cual
corresponde, en vez de efectuarse la vinculación por su extensión.
End Class
End Class
Module Cliente
End Module
Así mismo, es posible incluir dentro de un mismo módulo (archivo físico) varias
clases, simplemente encerrando la implementación de cada una de ellas dentro de
los identificadores de comienzo y fin de bloque vistos anteriormente.
A su vez, una clase puede estar partida a través de varios archivos físicos, aunque
se vea posteriormente desde el punto de vista programático como una única
entidad. Esto último simplifica la manipulación de código cuando varios
desarrolladores requieren trabajar con la misma estructura al mismo tiempo.
Mediante esta facilidad, cada módulo podría contener un conjunto de métodos de
la clase, factibles de ser fusionados posteriormente en el momento de la
compilación.
Public Class Cliente
End Class
Cliente
Public Class Cliente
End Class
57
Una vez incluidas las clases al proyecto, es necesario crear una instancia de ella a
los efectos de acceder a sus miembros:
58
Definiendo Propiedades
Los miembros de una clase (métodos y propiedades) son la forma en la cual la
misma exhibe sus funcionalidades a los demás integrantes. Visual Basic .NET
amplía y modifica la sintaxis utilizada en versiones anteriores, con el fin de
simplificar la codificación y emplear una aproximación más consistente.
59
Usted no puede usar el bloque Set cuando define una propiedad de solo lectura
porque la propiedad no puede ser actualizable. El compilador genera un error si
usted coloca esta.
Usted no puede usar el bloque Get cuando define una propiedad de solo escritura,
por que la propiedad no puede ser leída. El compilador genera un error si se
incluye esta.
End Class
60
Especificando la Visibilidad a Variables y Procedimientos
Palabra Definición
Public Accesible desde cualquier lugar.
Private Accesible solo dentro de ella misma.
Friend Accesible para los demás integrantes del proyecto, pero no
fuera del mismo.
Protected Asegura que los miembros pertenecientes a la misma podrán
ser visibles solamente por todas aquellas que deriven de
ésta, pero no por los demás integrantes.
Protected Friend Es la unión de Protected y Friend. Esto indica que la
visibilidad será exclusivamente para todos los elementos que
la hereden, así como también para los integrantes del
proyecto.
Por ejemplo:
A su vez, las mismas pueden ser marcadas a nivel de toda la clase, lográndose
así un resultado más modular.
End Class
61
Polimorfismo en Propiedades
End Class
62
Implementación de Métodos
End Sub
End Function
End Class
Las funciones pueden emplear la palabra Return para retornar un valor, de forma
similar a lo que se hacía en las propiedades.
Las características de visibilidad analizadas anteriormente también pueden ser
aplicadas a un método, logrando así similares resultados.
63
Métodos Compartidos
Los métodos compartidos de una clase también pueden ser indicados como
compartidos (Shared), a los efectos de que los mismos puedan ser invocados sin
la necesidad de crear una variable objeto. Para ello basta con adicionar la palabra
Shared después de la definición de visibilidad del procedimiento o función.
MsgBox(Conectate.UsrConectado)
En una misma clase pueden existir algunos métodos que estén marcados como
compartidos y otros no. Adicionalmente, los mismos pueden utilizar similares
reglas que aquellos estándares, lo cual simplifica su entendimiento.
Ejemplo:
Hacer un procedimiento de tipo compartido que incremente una variable privada
de la clase cada vez que el mismo sea invocado.
Public Class Cuenta
Private Shared Cuenta As Long
End Class
64
Polimorfismo en Métodos
Una vez conocidos los mismos, se deberían implementar las funciones necesarias
atendiendo a cada una de las situaciones:
End Function
End Function
End Class
Así como se especifico en este ejemplo, es más que suficiente para realizar la
invocación de uno u otro método dependiendo de los parámetros utilizados. Existe
la opción OverLoads, la cual no es obligatoria y hace posible marcar aquellos
procedimientos que ofrecerán diferentes opciones de invocación.
End Function
Public Overloads Function Buscar(ByVal Arg As String, ByVal Arg2 As
Integer) As String
End Function
End Class
MsgBox(oCuenta.Buscar(“1”,1))
65
Usando Constructores
End Class
Constructores Sobrecargados
Los constructores sobrecargados permiten que una clase pueda ofrecer distintas
formas de inicialización, involucrando diferentes parámetros para realizar dicho
proceso. Para ello se emplean las características de sobrecarga de funciones
(Polimorfismo) que vimos anteriormente, con el fin de brindar diferentes
alternativas a la hora de crear un objeto.
End Class
66
Para emplear el constructor sobrecargado o parametrizado: instancia e inicializa
un objeto
Usando Destructores
Así como se cuenta con un procedimiento Constructor que se ejecuta tan pronto
como un objeto es creado, también se ofrece un tipo especial de procedimiento
denominado Destructor. El mismo se ejecuta tan pronto como el recolector de
basura libera la memoria ocupada por el objeto y, a diferencia del primero, no es
posible sobrecargar el mismo.
Colección Garbage
Gc.Collect()
67
Herencia
Dentro de Visual Basic .NET, usted puede usar herencia para obtener una clase
derivada de una clase base. La clase derivada puede heredar todas las
propiedades, métodos miembros de datos, eventos de la clase base con la
finalidad de reutilizar el código de la clase base a través de una aplicación.
A medida que las aplicaciones han crecido en tamaño y complejidad, la tarea de
reutilizar sus partes se hace cada vez más difícil. Indudablemente, la reutilización
de código implica que las funcionalidades empleadas por una aplicación puedan
ser utilizadas por otra en forma sencilla. El primer punto radica siempre en
identificar aquellos módulos o características a ser compartidas, a los efectos de
aislarlas, y así definir quién o quiénes formarán parte de la infraestructura común.
Sin duda la orientación objetos brinda parte de la solución mediante el manejo de
clases, ya que varias implementaciones podrían ser agrupadas y posteriormente
tratadas como entidad. Sin embargo, es importante poder contar con alguna
característica que permita ganar cualidades de las clases ya existentes, con el fin
de modificar o mejorar las mismas, y así ofrecer un nuevo conjunto de
características basadas en la primera.
Para ello el paradigma de orientación a objetos ofrece una funcionalidad
denominada herencia, la cual permite que una clase pueda adquirir las cualidades
de otra ya existente, pudiendo –posteriormente- agregar nuevas implementaciones
bajo la misma apariencia, o lo que es igual, extenderla.
Clase Base
Una clase base es aquella que se utiliza como plantilla para definir otras, o dicho
de otra forma, aquella de la que derivan otras clases ganando así sus cualidades.
En Visual Basic .NET se basa en la utilización de la palabra Inherits (heredada),
la cual se debe situar en la zona de declaraciones, y debe incluir el nombre de la
clase de quien se desean ganar las características.
Inherits Caja
La palabra Inherits permite que una clase derivada solamente incluya aquellos
nuevos miembros, o aquellos cuya reimplementación se desea.
‘ Clase Caja
Option Explicit On
Public Class Caja
Public Function volumen() As Long
'Implementación
End Function
Public Function Peso() As Long
'Implementación
End Function
End Class
68
‘Clase Caja de Chocolate
Option Explicit On
Public Class CajaDeChocolates
Inherits Caja
Public Sub Color()
'Implementación
End Sub
End Class
o Clase base.
o Superclase.
o Clase padre.
A su vez, todas las clases que heredan o ganan las características de una base
pueden ser encontradas de las siguientes formas:
o Clase derivada.
o Subclase.
o Clase Hija.
69
Palabra NotInheritable
Por defecto todas las clases en Visual Basic .NET son factibles de ser heredadas.
Sin embargo, en algunas ocasiones puede ser necesario evitar que se realice este
proceso. Para ello se cuenta con la palabra NotInHeritable, la cual evita que una
clase pueda ganar las características de la misma.
Option Explicit On
Public NotInheritable Class ClasePrueba
‘Implementación
End Class
Cuando intente hacer uso de la herencia con una clase que indique esta palabra,
Visual Basic generará un error en tiempo de compilación tal como lo demuestra el
ejemplo anterior.
Palabra MustInherit
Es posible construir una variable de objeto basada en casi todas las clases de la
infraestructura .NET. Sin embargo, en algunos casos puede requerirse el restringir
esta funcionalidad, a los efectos de que solamente sea utilizada si se hace a
través de una clase derivada. Para ello se ofrece la palabra MustInherit, la cual
obliga a que la misma deba ser heredada por otra para que pueda hacerse uso de
sus miembros.
Option Explicit On
Public MustInherit Class Caja
Public Function volumen() As Long
'Implementación
End Function
Public Function Peso() As Long
'Implementación
End Function
End Class
70
Visibilidad en la Herencia
Las clases pueden heredar las propiedades o métodos de otra dependiendo de la
visibilidad que los miembros ofrezcan. Existen cinco tipos de visibilidad diferentes,
dos de los cuales son aplicables exclusivamente a la herencia:
Protected
ProtectedFriend
Private
Public
Friend
Protected
Tiene utilidad cuando se hace uso de la herencia. La misma permite que un
miembro se haga visible para aquellas clases derivadas que ganen sus
características, pero no puedan ser invocadas directamente por otros.
H
E X
R
E
N
C Y Z
I
A
Si intenta llamar a un método que utiliza este tipo de visibilidad, obtendrá un error
al momento de la compilación.
Friend
En algunas ocasiones es necesario que un conjunto de características sean
ofrecidas para otros miembros del proyecto, pero no así para elementos externos
al mismo. Esto es muy útil cuando se busca que una estructura contenida en un
ensamblado sea brindada al mismo, pero no así a aquellas entidades externas.
Para ello se debe hacer uso de esta operación de visibilidad.
71
Protected Friend
Esta forma ofrece menores restricciones, ya que justamente conjuga las
características de Protected y Friend. El mismo permite que un miembro pueda ser
visible por todas las clases que integran al proyecto, pero también por las que la
hereden.
Option Explicit
Public Class Caja
Function Volumen() as Long
‘Implementación
End Function
Function Peso() as Long
‘Implementación
End Function
End Class
72
Sobrescribir y Sobrecargado
Sobrescribiendo
Cuando una clase derivada es heredada de una clase base, esta hereda todos las
funciones, subrutinas, y propiedades de la clase base, incluyendo cualquier
implementación dentro de los métodos. Ocasionalmente usted puede implementar
código para su clase derivada en vez de usar el método heredado.
Overridable
Para crear una implementación especial en la clase derivada, especifique la
palabra Overridable en la definición del método de la clase base, como se muestra
en el siguiente ejemplo:
MustOverride
Para crear un método en una clase base que se deba sobrescribir dentro de todas
las clases derivadas, define el método con la palabra MustOverride. Solo el
prototipo del método puede ser creado dentro de la clase base, pero no el código
de su implementación. Usted solo puede usar esta palabra en la clase base que
esta marcada como MustInherit. El siguiente ejemplo muestra como definir esto:
Overrides
Para especificar que la clase derivada va a sobrescribir la implementación de un
método de la clase base, use la palabra Overrides. Para que esto se pueda hacer
la clase base deberá tener definido dicho método como Overridable. El siguiente
ejemplo muestra como se debe definir el método en la clase derivada:
73
Ejemplo:
Option Explicit On
Public MustInherit Class ClaseBase
Public Overridable Sub metodoSobreEscri()
MsgBox("Método Base de Sobrescritura")
End Sub
Public Sub Otro()
MsgBox("Otro Método de la Clase Base de No Sobrescritura")
End Sub
End Class
NotOverridable
En algunos casos puede ser necesario que un elemento que rescribe otro anule la
posibilidad a futuros miembros de que implementen una nueva versión del mismo.
Para ello debe utilizar la palabra NotOverridable en conjunto con Overrides.
Option Explicit On
Public MustInherit Class ClaseBase
Public MustOverride Sub ProCalcula()
74
Código para invocar a los métodos de la clase derivada:
75
Shadowing
Class aEjemploShadow
Inherits aBase
Public Shadows Sub M1(ByVal i As Integer)
' Solo se puede ver este método
End Sub
End Class
Invocación:
76
Usando la palabra MyBase
End Class
77
Usando la Palabra MyClass
o Esta permite acceder a todos los miembros de la clase derivada que sean:
Public, Protected, o Friend.
o Esta no es un objeto real, usted no podrá asignar MyClass a una variable.
Option Explicit On
Public Class ClaseBase
End Class
Invocación:
78
Implementando Interfaces
El siguiente ejemplo muestra como se define una interfase que incluye tres
métodos, dos de los cuales están sobrecargados.
Interface iMiInterfase
Function Metodo1(ByRef s As String) As Boolean
Sub Metodo2()
Sub Metodo2(ByVal I As Integer)
End Interface
Una vez realizada la declaración, la interfaz quedará disponible para ser empleada
por otras clases. Para hacer uso de la misma, basta con definir en la primera línea
de la clase la palabra Implements, seguida del nombre de la interfaz.
Posteriormente, cada miembro de ésta deberá implementar necesariamente cada
procedimiento, función o evento definido en la primera.
A su vez, cada elemento debe adicionar al final de su declaración el miembro con
el cual mantiene vinculación a través de la palabra Implements. En el caso de que
no se implemente uno de los mismos, Visual Basic generará un error en el
momento de la compilación. Otra opción es que la interfaz incluya declaraciones
de propiedades y eventos, así como las diferentes opciones de métodos:
79
Interface IPerson
Property UltimoNombre() As String
Sub Despliega()
End Interface
End Class
80
Implementación de Eventos
Un evento es la forma que utiliza un objeto para comunicarse con quien lo está
manipulando. Una clase puede iniciar tantos eventos como desee, pero antes
debe definirlos. La definición de los mismos se realiza en la zona general de una
clase, y tiene cierta similitud con la declaración de un procedimiento, salvo que la
misma no incluye la finalización del bloque ni su implementación.
Sintaxis
<visibilidad> MustInHerit Class <Nombre>
<visibilidad> Event <Nombre>(Args,...) as <Tipo>
En Visual Basic existen dos formas mediante las cuales es posible capturar los
eventos generados por una clase desde el exterior:
81
Cuando se utiliza la palabra WithEvents en la declaración de una variable, Visual
Basic inspecciona la clase en el momento de la definición para ver si contiene
eventos, y en caso afirmativo los incluye en la ventana de código en forma similar
a otros objetos. Esto hace que pueda hacer uso de las características estándares
para realizar la captura del mismo, pudiéndose en forma sencilla escribir código
para el evento.
Como un evento debe ser visible desde los miembros del módulo, la variable debe
ser definida a nivel modular, no pudiéndose utilizar este operador con elementos
locales.
Esta última hace posible a Visual Basic obtener una referencia al mismo. Cuando
el evento es enlazado, automáticamente se ejecutará las implementaciones
asociadas. Veamos como quedaría:
82
En resumen los pasos a seguir deben ser los siguientes:
1. Definir e instanciar una variable de objeto de la clase.
2. Asociar el evento del objeto a un procedimiento mediante la palabra
AddHandler.
Recuerde que los argumentos del procedimiento asociado deben ser iguales a los
del evento declarado en la clase. Por otra parte, es posible asociar varios
procedimientos a un evento con tan solo agregar más de una línea AddHandler
83
Módulo 4: Uso de Windows Forms
Tab Order
84
ello, después de dibujar los controles sobre el formulario basta con activar la
opción Orden de Tabulación (Tab Order) del menú Ver, el cual permite hacer
esta tarea en forma grafica.
DialogResult
MiSegundaForma.ShowDialog()
Me.DialogResult = DialogResult.Yes
Me.Close()
Font
85
Opacity
Me.Opacity = 0.5
Me.TransparencyKey = Color.Black
MaximumSize y MinimumSize
Estas dos propiedades permiten que usted defina el tamaño máximo y el tamaño
mínimo de la forma en tiempo de ejecución. Los tipos de datos de tamaño, son
la propiedad Height y la propiedad Width para definir el tamaño total de la forma.
MaximoTamano.Height = 500
MaximoTamano.Width = 500
MinimoTamano.Height = 200
MinimoTamano.Width = 200
Me.MaximumSize = MaximoTamano
Me.MinimumSize = MinimoTamano
86
TopMost
Los formularios flotantes son de mucha utilidad cuando se desea que una ventana
prevalezca sobre cualquier otra, o incluso sobre otras aplicaciones. A este tipo de
formularios se les denomina Flotantes. Una aplicación puede tener más de una
ventana flotante. Para indicar que un formulario debe ser de este tipo se debe
hacer uso de la propiedad TopMost. La misma puede ser modificada tanto en
tiempo de diseño como en tiempo de ejecución.
AcceptButton y CancelButton
Me.AcceptButton = Button1
Me.CancelButton = Button2
Show y ShowDialog
Usted puede usar estos métodos para desplegar una forma sobre la pantalla. El
método Show despliega la forma activando la propiedad Visible en true. El
método ShowDialog muestra la forma como caja de dialogo modal.
87
El siguiente ejemplo muestra como desplegar una caja de dialogo en forma modal
y como usar la propiedad DialogResult para determinar la acción que debe tomar:
Activated y Deactivate
El evento Activated es invocado cuando la forma es activada por el código o por la
interacción del usuario, y el evento Deactivate es invocado cuando la forma pierde
el foco.
El siguiente ejemplo muestra como usar el evento Activated, seleccionando el
contenido de un textBox:
Closing
Este evento es similar al evento unload de Visual Basic 6, este evento se dispara
cuando la forma empieza a cerrarse y permite que usted cancele el cerrado a
través del argumento CancelEventArgs.
88
Closed
El evento Closed ocurre después del evento Closing, pero antes del método
Dispose de la forma. Usted puede usarlo para preguntar si la información de la
forma desea salvarla.
El siguiente ejemplo muestra como usar el evento Closed para cargar información
en una variable global:
MenuStart y MenuComplete
Estos dos eventos son invocados cuando el menú recibe y pierde el foco. Usted
puede usar este evento para activar las propiedades de los elementos del menú,
por ejemplo la propiedad Checked o Enabled.
Una ventana MDI es aquella capaz de contener otras. Las ventanas hijas son
aquellas albergadas y manipuladas obligatoriamente dentro del espacio grafico de
la ventana principal. Adicionalmente, cualquier acción sobre la ventana principal
puede afectar a las contenidas o hijas.
IsMdiContainer() as Boolean
Usted puede usar la propiedad IsMDIContainer de la forma para crear una forma
MDI padre. Esta propiedad acepta un valor booleano. Ella puede ser configurada
en tiempo de diseño o en tiempo de ejecución.
89
El siguiente ejemplo muestra como especificar que una forma será de tipo MDI y
maximice su tamaño para facilitar su uso.
Es común el usos de menús en una forma MDI padre, para manipular partes de
una forma MDI Child. Para hacer esto usted necesita determinar que forma hija es
la que se encuentra activa en un instante determinado. La propiedad
ActiveMDIchild de la forma padre identifica esto.
El siguiente código muestra como cerrar una ventana hija desde la Forma MDI
padre:
90
Arreglo de las Formas Child
Usted puede usar el método LayOutMdi de la forma padre para cambiar el arreglo
de las formas hijas dentro de la ventana principal. Este método toma un parámetro
como se puede ver en el siguiente código:
Me.LayoutMdi(MdiLayout.ArrangeIcons)
Me.LayoutMdi(MdiLayout.Cascade)
Me.LayoutMdi(MdiLayout.TileHorizontal)
Me.LayoutMdi(MdiLayout.TileVertical)
Msgbox
La tradicional función MsgBox usada por los desarrolladores, se encuentra
incluida dentro de .NET FrameWork. Usted puede usar la misma sintaxis que
usaba en versiones anteriores, excepto que usted define el estilo de la caja,
usando la enumeración MsgBoxStyle y el resultado de la decisión con la
enumeración MsgBoxResult. El siguiente ejemplo muestra como usar la función
MsgBox:
If MsgBox("¿Continuamos?", _
MsgBoxStyle.YesNo + MsgBoxStyle.Question, _
"Pregunta") = MsgBoxResult.Yes Then
' Implementación
End If
Clase MessageBox
91
dialogo. Usted puede comparar el resultado de una decisión del usuario usando la
enumeración System.Windows.Forms.DialogResult, como a continuación se
muestra:
If MessageBox.Show("¿Continuamos?", "Pregunta", _
MessageBoxButtons.YesNo, _
MessageBoxIcon.Question) = DialogResult.Yes Then
' Implementación
End If
InputBox
92
Creación de Menús
MainMenu
Use la clase MainMenu para crear una barra de menú estándar para Windows, en
la parte superior de la forma.
ContextMenu
Use la clase ContextMenu para definir un menú Pop-Up asociado con un control
particular.
MenuItem
Use la clase MenuItem para definir los elementos del menú para un MainMenu o
para un ContextMenu
93
En forma automática, el control de menú asocia cada elemento a un
procedimiento clic, el cual será ejecutado al seleccionar el mismo. Para acceder al
procedimiento en tiempo de diseño, basta con hacer doble clic sobre el elemento
deseado y escribir el código.
End Sub
Propiedad Descripción
Checked Indica si el elemento estará marcado con un tick.
DefaultItem Cuando se indica que un elemento es el por defecto, el texto del
menú será marcado en negrita, y cuando el usuario haga doble
clic sobre un submenú que contenga elementos, el mismo será
ejecutado por defecto.
Enabled Indica si el elemento estará habilitado o deshabilitado.
MDIList Esta propiedad es sólo aplicable cuando se utiliza el modelo de
interfaces de documento múltiple (MDI), e indica que se deberán
listar los nombres de las ventanas abiertas.
MergeOrder Indica el orden con que los elementos fusionados serán
mostrados.
MergeType Cuando un menú es fusionado con otro, esta propiedad
establece cómo debe ser tratado el primero.
RadioCheck Esta propiedad se utiliza en conjunto con Checked, e indica si en
vez de utilizar un tick se utilizará un círculo.
ShowShortCut Indica si se deberán mostrar las teclas de acceso rápido.
ShortCut Especifica la combinación a utilizar de acceso rápido (por
ejemplo F3, Ctrl.+G).
Text Contiene el caption del menú.
Visible Indica si el elemento estará visible o no visible.
Ahora los formularios hijos también pueden contener sus propios menús, e
integrarse en forma automática al de la ventana principal en el elemento en que el
usuario abra la primera. De esta forma, el formulario MDI puede ganar elementos
del menú hijo mientras dicha ventana esté activa.
94
Creación de un Menú a Tiempo de Ejecución
Usted puede adicionar o editar menús a tiempo de ejecución asiendo uso de las
clases MainMenu, ContextMenu y MenuItem. Cada una de estas clases
contiene la colección MenuItem que cuenta con los métodos Add y Remove. El
siguiente ejemplo muestra como crear menús en forma dinámica:
mnuItem1.Text = "Catalogos"
mnuMain.MenuItems.Add(mnuItem1)
Menu = mnuMain
El nombre del mismo puede ser cualquiera, pero los argumentos de entrada deben
ser del tipo que aquí se exhibe. A continuación se debe escribir el código
necesario para enlazar el evento clic del elemento con el procedimiento
previamente escrito.
95
Menús de Contexto
mnuItemC1.Text = "Salvar"
mnuMainC.MenuItems.Add(mnuItemC1)
mnuItemC2.Text = "Cerrar"
mnuMainC.MenuItems.Add(mnuItemC2)
AddHandler mnuItemC2.Click, AddressOf Cerrar
Me.ContextMenu = mnuMainC
96
Herencia de Ventanas
Por supuesto que para demostrar esta característica vamos a crear un nuevo
proyecto de Biblioteca de clases, al cual llamaremos LibClases, y posteriormente
agregaremos un formulario con los siguientes controles, en forma similar a la
siguiente figura:
Debido a que no haremos uso de la clase creada por defecto por la plantilla, la
eliminaremos del proyecto, haciendo clic derecho sobre ésta y seleccionando
Excluir del proyecto. Ahora vamos a agregar código al botón Cancelar, el cual
simplemente cerrará la ventana.
97
A continuación, haremos clic en Aceptar. Lo que desplegará la ventana Selector
de herencia, como muestra la siguiente figura:
98
Aceptar, lo que dará como resultado un nuevo formulario que contiene los
controles del original dentro de ese proyecto.
Inherits ClassLibrary1.Form1
Una vez hecho esto, haremos clic derecho sobre la ventana de aplicación para
Windows y seleccionaremos Establecer como proyecto de inicio, a los efectos de
que se inicie la misma en vez del ensamblado creado inicialmente.
99
Por último, ejecutaremos la aplicación, lo que dará como resultado nuevamente la
ventana de control de acceso. Sin embargo, si intenta escribir código para los
diferentes eventos, notará que ello no es posible.
Ello es debido a que los objetos dentro del código generado por el diseñador de
formularios de Windows en la clase base han sido definidos utilizando el operador
de visibilidad Friend, lo que restringe la posibilidad de implementar sus diferentes
eventos.
100
Módulo 5: ADO .NET
♦ Acciones Unidireccionales
♦ Acciones Bidireccionales
El primer paso involucra aquellas acciones que no retornan filas, como una
actualización, modificación o eliminación de uno o varios registros. Para este caso
la solución en forma desconectada es relativamente sencilla, ya que en el
momento de requerir la acción, el mismo podrá establecer una conexión con el
origen, enviar la sentencia SQL y posteriormente desconectarse del mismo.
101
Adicionalmente, toda la información gestionada por ADO .NET puede ser
almacenada en formato de documentos XML, ya sean cursores, reglas, y hasta los
tipos de dato de cada columna (campos). Esto beneficia al modelo, ya que este
tipo de documento es aceptado ampliamente para transferencia de datos a través
de diferentes redes. A su vez, el mismo es intensamente utilizado para
intercomunicar información entre aplicaciones o sistemas operativos, dado que el
mismo está conformado exclusivamente por caracteres ASCII. Gracias a esto, los
documentos pueden ser enviados a través del Web sin los inconvenientes que
provocan los formatos binarios como los que ofrecía el modelo COM.
ADO .NET incluye varias clases para la manipulación de datos, las cuales están
incluidas en varios espacios de nombres:
System
Data
OleDb
SqlClient
(Proveedor especifico)
Imports System.Data
Imports System.Data.OleDb
Imports System.Data.SqlClient
Las clases en ADO .NET se separan en dos grandes grupos, teniendo en cuenta
la tarea que las mismas desempeñan:
1. Consumidores de Datos.
2. Gestores de Información.
Dentro del primer grupo se encuentran las clases que se encargan exclusivamente
de realizar una conexión y obtener los datos. Como ejemplo de estas tenemos,
las localizadas dentro de OleDb y SQLClient.
Dentro del segundo grupo se hallan aquellas que gestionan la información una vez
obtenida. Esto permite a ADO .NET emplear las mismas clases para gestionar los
datos, sin importar si éstos fueron obtenidos a través de un proveedor específico
(SQLClient) o genérico (OleDb). De acuerdo con ello, quienes obtienen la
102
información podrán estar relacionados con un motor de datos especifico, pero
quienes lo gestionen posteriormente serán comunes a todas ellas.
103
Objetos Conectados
Si desea emplear el proveedor específico de SQL Server provisto por ADO .NET,
se debe hacer uso de la estructura localizada dentro del espacio SQLClient:
Dado que sólo se podrá emplear con este tipo de motor de datos, no se hace
necesario la especificación del manejador (driver) a utilizar.
Para cerrar la conexión en forma inmediata o retornarla al pool de conexiones,
basta con que se invoque el método Close como se muestra a continuación:
Cn.Close
104
Usando el Objeto Command
Sintaxis
ExecuteReader
Use este método cuando espere que un query regrese un conjunto de registros.
Este método regresa los registros dentro de un objeto SQLDataReader o un
OleDbDataReader.
ExecuteScalar
Use este método cuando el query regrese un solo valor. Por ejemplo el resultado
de un select que solo contenga una función de agregado en sus columnas.
Select Max(PrecioUni) From Producto
ExecuteNonQuery
Use este método cuando el query no regrese resultado, por ejemplo un Insert,
Update, Delete o Procedimiento almacenado.
ExecuteXML
Use este método solo cuando el query incluya la cláusula de validación FOR
XML. Este método solo es valido cuando usa el objeto SQLCommand.
105
commSQL.CommandText = "Select Count(*) From Cliente"
MessageBox.Show(commSQL.ExecuteScalar().ToString)
106
Código Visual Basic para ejecutar el procedimiento almacenado
107
Usando el Objeto DataReader
datRead = commSQL.ExecuteReader
Dado que la variable de tipo DataReader puede leer un solo registro por vez, se
brinda el método Read para realizar esta acción. Cada invocación al mismo
incrementará el puntero al próximo registro, y es posible conocer si se encuentra
al final, si el método regresa el valor de falso:
While datRead.Read
MessageBox.Show(datRead(0).ToString)
End While
MessageBox.Show(datRead.Item("ClientePk").ToString)
MessageBox.Show(datRead.Item(0).ToString)
108
Si quisiéramos validar que una columna del dataReader contenga un valor nulo:
If datRead.IsDBNull(0) Then
MessageBox.Show("Valor Nulo")
Else
MessageBox.Show(datRead.Item(0).ToString)
End If
Para obtener el nombre de una de las columnas de la tabla que trae cargada el
DataReader:
MessageBox.Show(datRead.GetName(0))
datRead = commSQL.ExecuteReader
Do
While datRead.Read()
MessageBox.Show(datRead.Item(3).ToString)
End While
Loop While datRead.NextResult
datRead.Close()
109
El siguiente ejemplo modifica el campo NomCliente de la tabla Cliente de la base
de datos Ferreteria (conectada al ejemplo en el punto anterior):
Dim commSQL As OleDb.OleDbCommand
Dim strCommand As String
strCommand = "Update Cliente set NomCliente = 'Alex Lora' Where
ClientePk = 52"
110
Proveedores de Objetos Desconectados
DataSet
OleDbDataAdapter o DataAdapter
SQLDataAdapter
Origen
de
Datos
111
Otro punto importante a tener en cuenta es el relacionado con las estructuras y
restricciones vinculadas a cada tabla. Como vimos anteriormente, cuando un
conjunto de datos obtenido de un origen de datos, el mismo es gestionado por un
objeto de tipo DataSet en modalidad local y desconectado. Las columnas de una
tabla generalmente definen relaciones con otras, así como también contienen
reglas y restricciones que aseguran la consistencia de la información almacenada.
La única forma de cerciorarse sobre la integridad de los datos locales es
asegurándose de que las mismas reglas estén también disponibles en la copia
privada. Para dicho fin, el DataSet cuenta con una clase llamada DataRelation , la
cual permite especificar relaciones y restricciones a mantener entre las tablas pero
en forma local, con el fin de emular los comportamientos ofrecidos por el origen de
datos (o similar a la modalidad conectada).
De esta forma es posible asegurar que la copia local no generará conflictos en el
momento de la sincronización, ya que las pautas con las cuales será tratada la
información local serán similares a las ofrecidas por el origen de datos.
El dataset también beneficia en forma directa a las aplicaciones Web, las cuales
son desconectadas por naturaleza. En general, no se hace necesario el conocer
dónde está localizado el origen de datos hasta el momento en que la información
debe ser sincronizada. En muchas ocasiones, el proceso involucra solamente
lectura de datos o acciones que nunca serán enviadas al motor, por lo que muy
comúnmente el DataSet será utilizado simplemente como estructura de
intercambio entre aplicaciones.
112
Declaración del DataSet en la sección de Declaraciones a nivel forma:
Botón para cargar el ListBox con la información del DataSet (este se carga como
si fuera una colección):
El siguiente ejemplo muestra como cargar las filas de la tabla Cliente, Clasif y
Producto. Las mismas podrán ser cargadas posteriormente en único DataSet.
Para ello es necesario invocar al método Fill de cada adaptador:
113
Dim Ds As New System.Data.DataSet
Dim Registro As DataRow
Dim DataAdapEmp, DataAdapTie, DataAdapAut As
OleDb.OleDbDataAdapter
El siguiente ejemplo muestra como crear una relación entre dos DataTable dentro
de un DataSet. El mismo DataAdapter será usado para cargar el DataTable, y
entonces crear el DataRelation entre estas dos:
Dim adaptSQl As OleDb.OleDbDataAdapter
Dim Ds As New System.Data.DataSet
114
Acceder Datos Relacionados
Como se puede observar el Listbox se llena con la información del las Fechas de
las facturas que se corresponden con el segundo registro de Cliente. Si
convirtiéramos este código a un Query quedaría de la siguiente manera:
select FecFactura
From Cliente A Inner Join Factura B On (A.clientePk = B.clientepk)
Where A.ClientePk = 2
115
Usando Restricciones (Constraints)
Usted puede crear restricciones sobre un DataSet, puede copiar las existentes de
un origen de datos.
Valor Descripción
Cascade Borra o Actualiza cualquier registro hijo que este basado en el
registro padre.
SetNull Coloca los valores relacionados a DBNull.
SetDefault Coloca los valores relacionados a su Default.
None No Afecta los registros relacionados.
El siguiente ejemplo muestra como aplicar una restricción de tipo foreign key sobre
dos tablas existentes en un DataSet. Si el registro en la tabla padre es borrado, los
valores relacionado en la tabla hija serán colocados en DbNull. Si un registro de la
tabla padre es modificado, los valores relacionados en la tabla hija serán
igualmente modificados:
colPadre = Ds.Tables("Clasif").Columns("ClasifPk")
colHija = Ds.Tables("Producto").Columns("ClasifPk")
Ds.Tables("Producto").Constraints.Add(RestForeign)
Ds.EnforceConstraints = True
Restricción UniqueConstraint
Esta restricción puede ser agregada a una columna o un arreglo de columnas. Y
se asegura que todos los valores dentro de una columna sean únicos. Cuando
esta restricción es adicionada, ADO .NET verifica que los valores existentes no
violen la restricción y mantiene esta para todos los cambios efectuados sobre
DataTable.
116
El siguiente ejemplo muestra como adicionar un UniqueConstraint a una columna:
117
Afectando Datos en un DataSet
Una vez que se creo el DataSet, usted puede adicionar, modificar y borrar datos.
Cualquier cambio que se efectué en los datos, primero es cargado en memoria y
posteriormente se aplican los cambios en el origen de datos.
Editar un Registro
Use los siguientes pasos para editar un registro existente:
Borrar Datos
Use uno de los siguientes métodos para borrar un registro:
♦ Método Remove
Llame al método Remove de la colección DataRows. Este remueve el
registro del DataSet permanentemente.
♦ Método Delete
Llame al método Delete del objeto DataRow. Este solo marca en registro a
borrar en el DataSet, y si quiere deshacer el borrado llame al método
RejectChanges.
118
El siguiente ejemplo muestra como borrar un registro existente en el
DataSet:
Valor Descripción
UnChanged No hay cambios que aplicar.
Added Los registros que deben ser agregados a la tabla.
Modified Los registros que fueron modificados.
Deleted Los registros que fueron borrados con deleted.
Detached Los registros que fueron borrados, o el registro que fue
creado pero no fue llamando al método Add.
119
Actualizando la Información del Dataset al Origen de Datos
Para realizar la sincronización del DataAdapter con la base de datos, se hace uso
de la clase CommandBuilder esta clase facilita la tarea de especificar las
instrucciones SQL para los diferentes comandos del DataAdapter. La idea
principal es que solamente se establezca la cadena de selección, y que
posteriormente ADO .NET deduzca las demás.
Para dicho fin se provee una clase llamada OleDbCommandBuilder para el
proveedor genérico o SqlCommandBuilder para el específico de SQL Server.
120
Dim Ds As New System.Data.DataSet
Dim Adaptador As New OleDb.OleDbDataAdapter("Select * From Clasif",
Cn)
Private Sub Form5_Load(ByVal sender As System.Object, …
Adaptador.Fill(Ds, "Clasif")
End Sub
121
Puede hacer uso de este objeto cuando se utilizan sentencias SQL simples
(Select, Insert, etc.) sobre una única tabla, pero no en el caso de que se requiera
de comandos asociados a procedimientos almacenados. Los mismos deberán ser
introducidos en forma explicita.
Una vez realizada la tarea, el adaptador podrá ser sincronizado con el origen, y las
modificaciones, eliminaciones o nuevas filas serán enviadas al mismo.
Imports System.Data
Imports System.Data.OleDb
122
Como ultimo paso, agregaremos en el evento click del botón el código necesario
para la sincronización del DataSet con la base de datos.
El método AcceptChanges del DataSet modifica el estado de todas las filas a sin-
cambios. Este método debe ser invocado siempre después de llamar al método
Update del DataAdapter, ya que sise realiza antes de la sincronización, se
eliminará la información del estado de aquellas filas modificadas, agregadas o
eliminadas.
De igual manera puede utilizar la propiedad HasChanges para conocer si hubo
algún cambio en alguna de las tablas contenidas por el DataSet, y así se deberá
proceder a la sincronización.
123
Enlace de Datos
Con el fin de demostrar dicha funcionalidad, crearemos una nueva aplicación para
Windows, y crearemos una ventana de altas bajas cambios, usando la tabla Clasif
de acuerdo a la siguiente ventana:
124
Ahora nos centraremos en la programación de los botones que realizarán el
desplazamiento a través de las diferentes filas de la tabla. Los controles que
utilizan Binding apuntan siempre a un único registro o registró activo. De acuerdo
con esto, cualquier acción tomada sobre el mismo afectará a todos los elementos
vinculados. Para dicho fin, los formularios de Windows cuentan con una propiedad
llamada BindingContext, que hace posible desplazarse a través de las diferentes
filas, simplemente asignando a la misma el ordinal de registro activo, así como
también el DataSet y tabla.
125
Si efectuamos algún cambio en la información de las cajas de texto y queremos
reflejarlo en la base de datos:
Private Sub Salvar_Click(ByVal sender As System.Object, …
Dim Cb As New OleDb.OleDbCommandBuilder(AD)
AD.Update(Ds, "Clasif")
Ds.AcceptChanges()
Ds.Tables("Clasif").AcceptChanges()
End Sub
126
Módulo 6. Utilización de Reportes en Visual Basic
127
más adelante que es igual de sencillo crear uno de estos para una aplicación
Windows que para una aplicación Web.
Antes de comenzar a explicar sobre cómo crear un informe para una aplicación
para Windows, es importante que conozca que Visual Basic instala una carpeta
llamada Samples debajo del directorio Crystal, la cual contiene varios ejemplos
sobre este tema. Bien, ahora vamos a crear un nuevo proyecto de aplicación para
Windows, y será el encargado de obtener todos los productos por clasificación y
agruparlos por dicho criterio.
128
Inmediatamente después de que un módulo de informe es adicionado al proyecto,
la ventana de diálogo denominada Galería de Crystal Reports será exhibida, a los
efectos de que sea posible especificar en forma sencilla el tipo de documento a
elaborar. El mismo ofrece las siguientes opciones:
129
La siguiente ventana –similar a la siguiente figura - nos solicitará información
sobre cómo deberá ser establecida la conexión. Existen dos posibles opciones de
autenticación, la primera es utilizando los usuarios definidos en Windows
(Seguridad Integrada), mientras que la segunda es empleando aquellos definidos
en SQL Server (o Windows). Esta última es de gran utilidad cuando se desea
conectar al motor de datos desde ambientes no-Windows, lo cual no es el caso
que nos ocupa en este momento. Debido a ello, haremos clic en Seguridad
Integrada, a los efectos de que se empleen los privilegios del usuario actual. Por
supuesto que es necesario que el mismo cuente con derechos para poder acceder
a la base de Ferreteria. Por último, debemos especificar el nombre del equipo, o
(local) si el servidor se encuentra en forma local, y luego indicar Ferreteria en la
lista de Bases de datos.
Este bastará para que la conexión a la base pueda ser establecida, por lo que
vamos a hacer clic en Finalizar para agregar la conexión a la lista de factibles de
utilizar por un informe.
130
por ella. Algo realmente interesante es que un informe podría basarse en datos de
diferentes orígenes, sin que esto influyera en la complejidad de los procesos
posteriores. Vamos entonces a expandir Ferreteria, luego dbo, y por último
Tablas, a los efectos de acceder a las tablas de la conexión.
131
Cuando se establece una conexión, el generador de informes no solamente
obtiene la información de campos y tipos, sino también las diferentes relaciones y
restricciones de las mismas. Esta información es posteriormente utilizada por el
generador de informes para –por ejemplo- indicar un vínculo de tipo
principal/detalle. Sin embargo, con algunos orígenes no es posible obtener dicha
información, por lo que se brinda la posibilidad de indicar ésta en forma manual.
Esto es de gran utilidad en dos situaciones, la primera es cuando se desean
establecer vínculos diferentes a los originales, y la segunda cuando se tienen
tablas que pertenecen a distintos orígenes de datos, y se desea conformar una
relación. Haremos clic en Próximo, a los efectos de obtener una ventana similar al
de la siguiente figura:
132
La misma nos permitirá seleccionar los campos que integrarán el informe. Si
recuerda, la idea original era la de exhibir los datos de Clasificaciones y Productos,
por lo que agregaremos los campos de ambas tablas (Clasif y Producto). Una vez
hecho esto, haremos clic en Siguiente. La siguiente ventana solicita los campos
necesarios para ordenar y agrupar las diferentes filas obtenidas del origen.
Debido a que deseamos que los diferentes Productos sean agrupados por su
respectiva clasificación, bastará con que indiquemos el campo NomClasif de la
tabla de Clasif como elemento agrupador, en forma similar y como exhibe la
Figura:
133
Las próximas ventanas brindan la posibilidad de agregar subtotales gráficos, etc.,
y no haremos uso de éstos en el ejemplo, por lo que haremos clic en Terminar, lo
cual dará como resultado que un nuevo módulo de informe será agregado al
proyecto, conteniendo características similares a las de la siguiente figura:
C D
B
A
134
A continuación se describen las cuatro secciones de la figura:
A. Explorador de campos.
Permite agregar, modificar o eliminar campos del informe, así como también
fórmulas. Es posible mostrar u ocultar esta ventana haciendo clic en el menú de la
barra principal Ver, luego Otras Ventanas, y por último Esquema del Documento o
CTRL.+ALT+T.
Exhibe el informe con sus campos y demás integrantes. Éste incluye las siguientes
secciones:
2. Encabezado de página.
Aloja aquellos elementos que deberán ser incluidos en las diferentes
páginas que integrarán al informe. Generalmente se incluyen en ésta
los títulos de los diferentes campos, logotipo de la empresa, número de
página, etc.
3. Encabezados de grupo.
4. Detalles.
Las secciones de este tipo contienen las diferentes filas (y campos) que
integran el informe.
6. Pie de página.
135
C. Barra principal de herramientas del informe
Incluye las herramientas necesarias para ordenar, ver las propiedades del objeto
seleccionado, etc.
Incluye las herramientas necesarias para insertar nuevos objetos al informe, así
como también agregar nuevos grupos, etc.
Las diferentes pautas sobre cómo tendrá que ser obtenida la información y los
distintos procesos a realizar sobre ésta han sido guardados en el documento
Productos.rpt. Sin embargo, el mismo no mantiene ninguna relación sobre cómo
deberá ser exhibido el resultado, ya que éste se remite exclusivamente a
almacenar los procesos especificados mediante el asistente. Esto es así con el fin
de que un mismo informe pueda ser utilizados para generar su salida a una
aplicación para Windows o para Web, sin que se requiera modificaciones, o la
creación de informes similares. Antes de pasar a la siguiente sección del libro –en
la cual nos encargaremos de exhibir el resultado del informe- haremos una pausa
para poder interactuar con los diferentes elementos de la ventana del informe.
Exhibiendo el informe
Si bien los informes contienen los datos sobre el origen, campos y procesos a
realizar, no están asociados con ningún tipo de presentación en especial, y ello
tiene como cometido que el mismo pueda ser utilizado en diferentes tipos de
proyecto. En el caso de aplicaciones para Windows, se ofrece un control de
Windows llamado CrystalReportViewer (Visor de Crystal Report), el cual debe ser
dibujado sobre un formulario, a los efectos de poder exhibir el resultado del
informe previamente creado. Vamos entonces a agregar uno de éstos al
formulario creado por defecto por la plantilla, en forma similar a como muestra la
siguiente figura:
136
La forma más fácil de enlazar un informe al control de vista de informe es utilizar la
ventana de propiedades. Para ello, el miembro ReportSource juega un rol
fundamental, ya que basta con especificar la ruta y nombre del documento que
contiene el informe para que el mismo se haga funcional. El resultado en
ejecución que se obtendrá después de esto será similar al de la siguiente figura:
137
Como es posible apreciar, el crear y configurar las diferentes propiedades de un
informe es una tarea realmente sencilla, pero no obstante, cuenta con dos grandes
desventajas: la primera radica en que el mismo debe situarse siempre debajo de la
misma ruta, y la segunda es que el origen de datos debe estar accesible de igual
forma. Estas son cosas que raramente pasan entre el ambiente de desarrollo y el
orden del usuario, por lo que aprenderemos a continuación cómo es posible
gestionar este tipo de problemas mediante código.
Sintaxis:
ReportSource() As Object
Esta es la forma empleada por defecto, pero no nos es de gran utilidad cuando
deseamos especificar un nuevo origen y proveedor en tiempo de ejecución,
diferente al que fue establecido originalmente en el informe.
Para resolver este problema, los mismos proveen un modelo llamado Push
(Introducir), el cual brinda una solución a este problema.
138
El modelo Push se basa en que el desarrollador debe escribir el código necesario
para conectarse al origen, y posteriormente obtener un conjunto de filas, las
cuales serán luego utilizadas para confeccionar el informe. Esta técnica permite
que no solamente se pueda establecer un nuevo origen, sino también realizar
algún tipo de proceso intermedio, como filtros, u otros pasos imperiosamente
necesarios para la conexión ver la siguiente figura.
Base de Crystal
Datos ADO Dataset Report
.Net
Para ello, existe una característica brindada por el entorno de desarrollo, la cual
hace posible obtener la estructura de un conjunto de tablas (campos, llave
primaria, etc.), y posteriormente almacenarlas en un documento en formato de
esquema XML. Afortunadamente, esta característica es ampliamente utilizada por
el generador de informes, ya que permite basar el mismo en este documento, y
posteriormente –en tiempo de ejecución- rellenar éste con las filas obtenidas del
origen de datos.
139
El mismo contendrá la estructura de las diferentes tablas en las cuales se basará
el informe pero nada sobre filas. En tiempo de ejecución, tendremos que cargar
de forma programática los diferentes registros de las tablas involucradas, y
posteriormente asociarlas al mismo.
140
Esto adicionará una nueva entrada a la lista, la cual usaremos para obtener las
estructuras necesarias para confeccionar el informe.
El próximo paso será el de expandir la misma hasta localizar las tablas de Clasif y
Producto y arrastrar las mismas sobre el módulo de DataSet.
141
A simple vista, el resultado final se parece a un informe del modelo Pull (el que
confeccionamos anteriormente), pero encierra una diferencia importante, la cual
radica en que ahora el mismo se basa en información de estructuras y tipos, pero
no almacena nada con respecto al lugar de donde las filas deberán ser obtenidas.
Esto último lo realizaremos mediante código utilizando ADO.NET. Si se intenta
asociar el mismo a un control de visor de informe y ejecutar la aplicación, el mismo
no podrá discernir de dónde obtener los datos, por lo que le solicitará al usuario
dicha información. Vamos entonces a realizar la segunda etapa, la cual radica en
obtener mediante código el conjunto de filas que empleará el mismo.
Los informes Crystal cuentan con un conjunto de clases, las cuales permiten
gestionar la totalidad de las funcionalidades de los mismos en forma programática.
El primer paso para acceder a ellas fácilmente es siempre el agregar la
importación al espacio de funcionalidades del motor de Crystal.
Imports CrystalDecisions.CrystalReports.Engine
142
Básicamente, cargaremos en esta variable la definición del informe que creamos
en tiempo de diseño, y luego le introduciremos al mismo las filas obtenidas por el
origen de datos. Todo esto lo gestionaremos mediante los métodos y propiedades
que este objeto nos provee. Primeramente debemos hacer uso del método Load
para indicar el informe a utilizar:
Sintaxis:
Load (<Ruta> As String)
Load (<Ruta> As String, <Forma de apertura> As OpenReportMethod)
Informe.Load(“C:\Ruta\Productos2.rpt”)
Esto alcanza para cargar en la variable la definición del mismo. En los próximos
pasos obtendremos el conjunto de filas mediante ADO.NET (aunque puede ser
también un Recordset de ADO), y por último asignaremos el mismo a la propiedad
SetDataSource, la cual, además de aceptar una ruta a un documento RPT, admite
un objeto de este tipo. Veamos entonces cómo se llevará a cabo este proceso:
Imports CrystalDecisions.CrystalReports.Engine
Imports System.Data.OleDb
.
.
‘Define un objeto de tipo ReportDocument
Dim Informe As New ReportDocument ( )
‘Carga la definición del Informe
Informe.Load (“C:\MiRuta\MiInforme.rpt”)
‘Aquí se debe Abrir conexión y cargar objeto DataSet
‘Asigna el contenido resultante mediante la propiedad SetDataSource
Informe.SetDataSourse (<Recordset o DataSet>)
Con esto bastaría para que el origen y contenido de las tablas puedan ser
especificados desde código. El último paso es siempre el de asignar el
documento resultante al control de visor de informe.
Me.CrystalReportViewer1.ReportSource = Informe
143
Dim adClasif As OleDbDataAdapter
Dim adProducto As OleDbDataAdapter
Dim ds As New DataSet()
' Crea un adaptador para cada tabla, los cuales podrian ser de diferentes
' Origenes de datos
adClasif = New OleDbDataAdapter("Select * From Clasif", Cn)
adProducto = New OleDbDataAdapter("Select * From Producto", Cn)
'Carga el DataSet
adClasif.Fill(ds, "Clasif")
adProducto.Fill(ds, "Producto")
'Carga el informe conteniendo la estructura del mismo
Informe.Load("D:\SistemAsist\SistemAsistencia\Productos2.rpt")
Informe.SetDataSource(ds)
CrystalReportViewer1.ReportSource = Informe
End Sub
144
Código de Barras
A + ABS(A<=49)*48 + ABS(A>=50)*142
145
El siguiente código muestra la fórmula (para implementar el interleaved 2 de 5)
que se tiene que insertar en Crystal Reports, con sintaxis de visual (en la esquina
superior derecha del Crystal Report).:
DataToPrint = ""
StartCode = Chr(40)
StopCode = Chr(41)
146
Informes en Aplicaciones para la Web
El próximo paso será el de vincular la definición del informe con el control Web. La
propiedad ReportSource no existe en la ventana de propiedades, o por lo menos
no de la misma forma que vimos en aplicaciones para Windows. Para poder
acceder a la misma, necesitamos ir a la ventana de propiedades, y posteriormente
hacer clic sobre DataBindings, la cual exhibirá una ventana similar a la de la
siguiente figura:
147
La misma ofrece las distintas propiedades factibles de ser enlazadas a datos, o lo
que nos interesa en este caso, a un documento de informe. Para realizar esta
tarea es necesario marcar la propiedad ReportSource, y luego hacer clic en
Expresión de enlace personalizado, lo que nos permitirá establecer el origen o ruta
al informe, en forma similar al de la siguiente figura:
Cuidado
148
Una vez hecho esto, bastará con escribir entre comillas la ruta física completa al
documento en la caja de texto situada en la parte inferior, y luego dar clic en
aceptar.
149
Módulo 7. Hilos Threads
Hilos
150
Para iniciar la ejecución de un nuevo subproceso, utilice el método Start, como en
el código siguiente:
MyThread.Start()
MyThread.Sleep ()
MyThread.Suspend ()
MyThread.Abort ()
Prioridad Descripción
AboveNormal Por encima del tiempo normal
BelowNormal Por debajo del tiempo normal.
Highest Valor más alto posible. Nota: Tener cuidado con este, ya que
puede bloquear la aplicación si no se utiliza correctamente.
Lowest Puede programarse después de los subprocesos que tengan
cualquier otra prioridad.
Normal Puede programarse después de los subprocesos con
prioridad AboveNormal y antes que los subprocesos con
prioridad BelowNormal. Los subprocesos tienen prioridad
Normal de forma predeterminada.
151
Subprocesos de primer plano y de fondo
La propiedad isBackGround es fundamental, ya que indica que los hilos creados
serán, de segundo plano. Esto no afecta al rendimiento de los mismos,
simplemente le indica CLR que en el caso de que la aplicación sea cerrada, los
hilos marcados como de fondo serán también destruidos. Si no se configura esta
propiedad, CLR no podrá liberar los recursos en forma adecuada al finalizar la
ejecución de la aplicación.
Imports System.Threading
152
End Try
End Sub
Hilo1.IsBackground = True
Hilo1.Priority = ThreadPriority.Lowest
Hilo2.Priority = ThreadPriority.Lowest
Hilo2.IsBackground = True
Hilo1.Start()
Hilo2.Start()
End Sub
153
Lamentablemente, el lenguaje solamente asegura en algunos pocos casos que la
tarea será realizada exitosamente. Ello es debido principalmente a que este tipo
de procesos no son realizados por el procesador ni por CLR en forma atómica, y
es allí donde debe intervenir el desarrollador para asegurar que las mismas sean
efectuadas correctamente.
Tiempo1 Tiempo2
Variable
Hilo
Por otra parte, muchas de las tareas efectuadas por CLR son también realizadas
en dos pasos. Por ejemplo, cuando se modifica el valor contenido por una
variable, el mismo formaliza dicha tarea mediante tres pasos:
154
Sincronización mediante Synclock
Esta sincronización funciona en forma similar a un semáforo de trafico, cada vez
que un objeto desea realizar un conjunto de tareas, el mismo deberá
anteriormente fijarse en si el recurso se encuentra disponible (o no bloqueado). Si
un hilo está modificando una o más variables, y otro hilo desea efectuar la misma
tarea, entonces este último será puesto automáticamente en lista de espera hasta
que el primero finalice.
Class Cache
Private Shared Sub Add(ByVal x As Object)
SyncLock GetType(Cache)
End SyncLock
End Sub
155
Ejemplo Filósofos del Comedor
Los Filósofos del comedor son generalmente utilizados para ilustrar problemas
que pueden ocurrir cuando varios hilos sincronizados compiten por recursos.
La historia transcurre así: cinco Filósofos están sentados alrededor de una mesa,
y frente a cada uno de ellos hay un plato de arroz. Entre cada filosofo hay ademas
un palillo chino. Antes de que alguno de los mismos pueda comenzar a comer, el
filosofo debe contar con dos palillo chinos, uno que haya tomado del lado
izquierdo y otro de la derecha. Los Filósofos deben encontrar entonces la manera
de compartir los palillos de forma que todos puedan comer. Este particular
algoritmo funciona de la siguiente manera: el filosofo busca primero el palillo de su
derecha. Si el mismo está allí lo toma y levanta su mano derecha.
Después intenta tomar el palillo de si izquierda y, si está disponible, el filósofo lo
toma y levanta la otra mano. Ahora éste tiene ambos palillo, por lo que puede
probar un poco de arroz.
Después de realizar dicha tarea, el filósofo deberá dejar ambos palillos sobre la
mesa, permitiendo así que algunos de sus dos vecinos los tome. Posteriormente la
historia se repetirá, ya que probará otra vez con el palito a su derecha, etc. Entre
cada intento de tomar un palito, cada filosofo deberá hacer una pausa por un
periodo al azar.
Crear un nuevo proyecto para Windows y en una forma hay que adicionar los
siguientes controles:
Objeto Propiedad Valor
ListBox ID Eventos
Button ID IniciarBanquete
Text Iniciar el Banquete
156
Una vez efectuado esto, agregaremos una clase denominada Filosofo, la cual
representará al mismo con todas sus características, a continuación se muestra el
código para esta clase:
Imports System.Runtime.Remoting
Imports System.Threading
'Propiedades
Public ReadOnly Property PalitoIzquierdo() As String
Get
Return _PalitoIzq
End Get
End Property
'Constructor
Public Sub New(ByVal Nom As String, ByRef Mesa As ListBox, ByRef
PalitoIzq As String, ByRef PalitoDer As String)
'Referencia al Palito Izquierdo que debe tomar
_PalitoIzq = PalitoIzq
157
'Método Comer
Public Sub Comer()
'Hacer
Do
'Intenta tomar el Palito Izquierdo que le corresponde
SyncLock PalitoIzquierdo
SyncLock PalitoDerecho
'Si lo consigue despliega los mensajes en el ListBox
_Mesa.Items.Add(Nombre & ": Tengo el palito derecho")
_Mesa.Items.Add(Nombre & ": Estoy comiendo!!! Mmmm")
Dim j As Integer
For j = 0 To CalcularTiempoEspera()
'Demora volver a intentar tomar un palito
Next j
Loop
End Sub
Return (TiempoMáximo)
End Function
158
End Class
Imports System.Threading
Hilo1.Priority = ThreadPriority.Lowest
Hilo2.Priority = ThreadPriority.Lowest
Hilo3.Priority = ThreadPriority.Lowest
159
Hilo4.Priority = ThreadPriority.Lowest
Hilo5.Priority = ThreadPriority.Lowest
End Class
160
Modulo 8: ASP .NET
Introducción
ASP .NET es la nueva tecnología propuesta por Microsoft para enfrentar los
desafíos de interconexión entre dispositivos y sitios Web del nuevo milenio. En
versiones anteriores de Visual Basic, las opciones brindadas para la programación
de estos últimos no contaba con las ventajas que ofrecían otras herramientas,
como visual InterDev. En esta versión, ahora se cuenta con un excelente editor de
paginas para servidor activo ASP .NET y HTML, el cual viene incluido por el
entorno de desarrollo como diseñador natural. Adicionalmente se han agregado
varias características, a los efectos de que la programación de una aplicación
para la Web cuente con todas las funcionalidades del lenguaje, y además se
efectúe en forma similar a como se hacía bajo el modelo Windows.
161
Comparación entre aplicaciones Windows y Web.
162
Eventos en Formularios Web
Una vez que el paquete llega al servidor, el mismo extrae los datos e identifica el
recurso al cual se hace referencia (pagina, archivo, etc.). Posteriormente arma
uno o varios paquetes con igual conformación (encabezado y cuerpo) y carga en
el cuerpo la información requerida, la cual posteriormente es enviada al cliente
identificándolo por los datos del remitente cargados inicialmente. El servidor
también adiciona en el encabezado varios datos más. A todo esto se le denomina
método Get, dado que es la forma que emplea el explorador para solicitar un
recurso Web.
Cuando el paquete llega al cliente, el explorador se toma el trabajo de extraer los
datos del cuerpo del mensaje y los exhibe. También pueden existir varias
peticiones para satisfacer una página, en el caso de que la misma contenga
elementos binarios, los cuales deben ser obtenidos nuevamente del servidor
mediante un proceso similar.
Adicionalmente, existe una funcionalidad ofrecida por http, la cual hace posible
enviar al servidor no solamente información de la petición de un recurso, sino
también el contenido de la página actual que tiene el explorador. Esto es muy
común cuando se desea enviar a otra pagina valores de la página activa, como
por ejemplo los datos contenidos por las cajas de texto. Para dicho fin, http provee
una alternativa diferente, la cual permite cargar en el encabezado del mensaje la
página solicitada, y en el cuerpo el contenido de los diferentes controles. A esto se
le llama método Post, dado que permite enviar información al servidor. Este tipo
de funcionalidades son gestionadas por HTML mediante la utilización de
163
elementos o marcas especificas, las cuales permiten delimitar aquellos controles a
ser enviados del explorador al servidor.
Relación del método Post con los eventos del Formulario Web
Cada vez que un evento es iniciado en un formulario Web – por ejemplo el clic- el
mismo no es ejecutado localmente dentro del explorador, sino que es enviado al
servidor que es donde reside la implementación del mismo.
Esto sucede gracias a que cada evento clic produce un método Post, el cual hace
que se lleve a cabo una ida al servidor, enviando el contenido de los controles de
la página. Por supuesto que el mismo apunta a la misma página que ya esta
viendo el usuario en el explorador, ya que de lo contrario se cambiaría de página
al iniciarse cada uno de los eventos. Una vez que la información es recibida por el
servidor, el mismo identifica al recurso que inicio el evento, y posteriormente
localiza la implementación del mismo y la ejecuta. Por último crea nuevamente la
página y la envía al explorador, incluyendo las modificaciones necesarias
realizadas por el código ejecutado.
Por ello, cada vez que un evento es iniciado por ASP .NET, la página es
completamente generada, lo que involucra una ida y vuelta al servidor. Esto da
como resultado que la interactividad de una aplicación Web sea siempre menor
que la de una aplicación para Windows. Esto es un punto importante que debe ser
considerado en conjunto con el usuario final, a los efectos de que conozca los
diferentes beneficios que obtendrá bajo esta tecnología, así como sus
restricciones.
El proceso que anterior es realizado de forma trasparente por ASP .NET, lo que
brinda al desarrollador y usuario la sensación de que el evento es producido
dentro del mismo equipo. No obstante, hay algunas tareas que realiza ASP .NET
con el fin de minimizar las idas y vueltas al servidor de Internet, y así redundar en
un mejor rendimiento. Una de las más importantes radica en que muchos de los
eventos son dejados en espera (o encolados) hasta que otro evento sea iniciado,
con el fin de que ambos sean procesados en forma conjunta.
164
Label Text Productos Pedidos
Label ID ProductosPedidos
Button ID Pedir
Text Pedir
165
AutoPostBack, la cual si se establece en verdadero, forzará a que se ejecute el
evento tan pronto como el mismo sea iniciado. Por supuesto esta propiedad debe
ser empleada únicamente en casos extremos, dado que puede reanudar en un
consumo innecesario de ancho de banda y CPU del Servidor Web.
Por otro lado, es importante destacar que hay muchos eventos que no están
disponibles en el modelo Web, como aquellos producidos por el movimiento del
ratón o la introducción de caracteres.
166
Propiedades, métodos y eventos de páginas Web.
Desde el punto de vista de ASP .NET una pagina es un objeto que gana o hereda
sus funcionalidades de una clase llamada Page, la cual sirve como contenedor
para otro controles. La idea es la de proveer mediante este objeto un modelo
similar al propuesto por Windows.
Toda página es entonces un objeto derivado de Page, el cual cuenta con varios
eventos, propiedades y métodos. Los eventos más comunes utilizados son: INIT,
PreRender, Load y Unload. Dos de ellos son familiares (Load y UnLoad) a los
desarrolladores de Visual Basic y, de hecho, tienen cierto parecido. Cuando una
pagina es requerida por un explorador, ASP .NET crea un objeto de tipo Page
conteniendo la misma, y luego ejecuta su evento INIT, el cual es el encargado de
configurar los diferentes controles contenidos por ella. Una vez que éstos han sido
establecidos (pero antes de que ésta sea enviada al cliente a través de http) el
evento load es iniciado, y es allí donde debe situarse todo el código necesario
para inicializar los diferentes valores y propiedades de controles de la misma. Una
vez que la pagina esta lista para ser enviada al explorador (pero antes que esto
suceda) el evento PreRender es iniciado. El mismo tiene como principal diferencia
con Load que en el momento en que éste es ejecutado, todos los cambios sobre la
pagina derivados de Load y la implementación de otros eventos ya han sido
efectuados. Por último, cuando todas las tareas han sido finalizadas (pero antes
de que la página sea enviada al explorador) el evento UnLoad es iniciado. La
siguiente figura muestra dicho proceso:
Load
Otros Eventos
PreRender
UnLoad
Vimos anteriormente que los formularios Web estaban constituidos por dos
archivos: aquel que contenía el código y aquel que contenía la información sobre
la presentación. Si bien dijimos que ambos eran vistos por ASP .Net como un
objeto de tipo Page, en realidad existe una separación aún más fina.
Es importante comprender dicha diferencia, ya que cuando se está en modo de
diseño en Visual Basic y se accede a la ventana de propiedades mediante la tecla
F4, la misma exhibe aquellas correspondientes al objeto Document (presentación),
más las del objeto Page, ver la siguiente figura:
167
Presentación (Document) Directivas (Objeto Page)
Ventana de Propiedades
Nombre Descripción
Background Permite configurar una imagen de fondo al formulario Web.
BgColor Color de fondo del formulario Web .
ErrorPage Permite establecer la página a emplear en caso de que
ocurra una excepción.
ShowGrid Exhibe o no la cuadrícula en tiempo de diseño.
Title Configura el título que será mostrado por el explorador en la
barra superior de la ventana.
Por supuesto que no todas las propiedades son incluidas en tiempo de diseño, ya
que muchas están disponibles solamente durante la ejecución. Este es el caso de
IsPostBack, la cual indica si la página está siendo accedida por primera vez o si la
petición corresponde a una recarga de la misma. Ella puede ser producida por
que el usuario hizo clic en la opción Actualizar del explorador, o como
consecuencia de un evento. Como vimos anteriormente los eventos producen la
reejecución de la página, y algunos valores deben ser establecidos solamente la
primera vez. Para estos casos se cuenta con IsPostBack, que generalmente es
utilizada dentro del evento Load.
168
Controles en los Formularios Web
Los controles de formularios Web son componentes que dan como resultado uno
o más controles HTML ante la petición de un explorador. Todos ellos heredan sus
características de diferentes clases, las cuales residen dentro del espacio
System.Web.UI.WebControls, el cual contiene todos aquellos elementos que
pueden componer la interfaz gráfica. Los controles pueden ir desde simples (cajas
de texto, botones, etc.) hasta algunos más complejos (calendarios, tablas
enlazadas a datos, etc.). No obstante, todos ellos comparten varias cosas en
común, como que son derivados originariamente de una clase llamada
WebControl, la cual define un elemento Web con su contraparte ejecutable del
lado del servidor.
En forma general los controles, los podríamos separar en 4 granes grupos:
• Complejos. Son aquellos controles de ASP .Net que se dibujan como un solo
control., pero que en realidad finalmente serán transformados en varios
elementos HTML en el momento de la petición de la página por parte de un
explorador. En muchas ocasiones realizan procesos realmente complejos del
lado del servidor. Como por ejemplo el calendario, el visor de informes de
Crystal Report, etc.
169
Cada una de estas comprobaciones se corresponderá con un control de
verificación, como a continuación se detalla:
RequiredFieldValidator
Estará asociado a un control de TextBox que contendrá la dirección de correo, y
verificará que tenga contenido.
RegularExpressionValidator
Corroborará que la dirección introducida tenga formato de correo electrónico.
RequiredFieldValidator
Estará asociado a un control de TextBox que almacenará la contraseña y
verificará que la misma tenga contenido.
RangeValidator
Comprobará que la clave esta en el rango 1000 y 99999999.
RequiredFieldValidator
Estará asociado a un control TextBox que contendrá la reintroducción de la clave,
a los efectos de verificar que contenga un valor.
CompareValidator
Verificará que la clave y contraseña contengan los mismos valores.
170
Debajo de cada uno de los TextBox agregaremos los diferentes controles de
validación, los cuales sólo serán visibles durante la ejecución si el contenido de la
caja no cumple con el requisito preestablecido. La vinculación entre el control a
validar se realiza mediante la propiedad ControlToValidate, mientras que el texto a
ser desplegado en el caso de que un error ocurra deberá ser establecido en
ErrorMessage. Veamos con detalle la configuración de cada uno de los controles y
sus propiedades:
171
Ahora implementaremos el código para el evento clic del botón Suscribirse. Todos
los controles de validación son agrupados en forma automática en una colección
de controles de este tipo, la cual es guardada bajo el miembro Validators del
formulario. Gracias a éste es posible recorrer la misma y conocer si alguno de sus
integrantes contiene un estado no valido. A continuación se muestra el código
para realizar esto:
172
Como se puede observar, Validators retorna la colección de controles validación,
los cuales pueden ser extraídos mediante la utilización de la estructura for each.
Dentro de la misma se evalúa la propiedad isValid para conocer el estado, y así
determinar cómo continuará la aplicación.
173
Web Form con ADO .Net
Otra situación se refiere a las relaciones entre las tablas, como sabemos en las
bases de datos relacionales existen tablas, relaciones y llaves primarias. Es
común encontrar tablas que dependan de otras, ahora es posible copiar las
relaciones de las tablas del origen de datos (todos estos conceptos ya los
tratamos en el capitulo 5 del presente manual, por lo que nos concretaremos a
ejemplificar).
174
Controles Vinculables a Datos
El siguiente ejemplo muestra como llenar un ListBox con los datos de la tabla de
clientes de la base de datos Ferretería.
Vamos a aprender a llenar un ListBox con la información de una tabla. Para ello
creamos un nuevo proyecto de aplicación Web ASP .NET llamado ListaClientes, al
cual agregaremos los controles de acuerdo con la siguiente tabla:
Imports System.Data.OleDb
175
While DataRead.Read
Lista.Items.Add(DataRead.Item(1) & "--" & DataRead.Item(2) &
"--" & DataRead.Item(3))
End While
DataRead.Close()
End Sub
176
IsClientConnected( ) As Bolean. Debido a que los procesos se realizan en el
servidor, éstos pueden tomar tiempo y es necesario saber si el usuario sigue
conectado, la función IsClienteConnected regresa un valor verdadero o falso que
indica el resultado, se utiliza en conjunción con el objeto Response.
If Response.IsClientConnected Then
'Se realiza un proceso en caso de que el usuario este conectado.
End If
Response.Redirect(“http://www.miNuevaPagina.com ”)
Request.ServerVariables(“HTTP_USER_AGENT”)
Variable=Request.ServerVariables(0)
177
Con el objetivo de ejemplificar estos dos temas crearemos un nuevo proyecto de
aplicación Web ASP .NET llamado Variables, al cual agregaremos los controles de
acuerdo con la siguiente tabla:
End Sub
178
Lock y Unlock
Los miembros Lock y Unlock se utilizan para que no existan problemas de
concurrencia, ya que se debe alterar una variable por sesión a la vez.
'Pongo un candado para que nadie más, además del que accedió primero,
'pueda alterar la variable. Además de incrementar en uno el contador
Application.Lock Application("Contador")=Application("Contador") + 1
Application.Unlock
Variables de Aplicación
Como lo explicamos antes, cada que una página es solicitada se regenera
completamente. Es por eso que no guarda valores, y se utilizan las variables de
aplicación, en las que no se permiten almacenar valores que puedan ser
compartidos por todos los usuarios que acceden a la aplicación.
El objeto Application permite que se almacene información dentro de la memoria
del servidor Web, mientras que el servicio de IIS (Internet Information Server) no
sea detenido.
Por ejemplo, podemos indicar en qué momento se inició la aplicación y
almacenarlo en una variable llamada T_DeComienzo.
179
'Now indica la fecha y hora actual del servidor.
Application("T_DeComienzo")=Now
Application.Add("Clientes",2)
Para obtener el valor de esta variable podemos utilizar el método Get del objeto
Application, cabe mencionar que no es necesario declarar previamente la variable.
Variable=Application.Get("Clientes")
Variables de Session
Cuando se necesita guardar información por usuario, entonces se utilizan las
variables de sesión. La diferencia de este tipo de variables contra las de aplicación
es que las variables de sesión tienen un conjunto de valores por usuario y las de
aplicación son globales, las comparten todos los usuarios que acceden a la
aplicación.
El valor de estas variables son mantenidas mientras la sesión no termine, ya sea
que el tiempo máximo de espera se alcance o el usuario cambie a otra página que
no pertenezca a la misma aplicación.
Es importante establecer lo que es una sesión para ASP.NET, cada ventana del
navegador de Internet abierta es interpretada como una sesión. Por ejemplo, si
tenemos tres ventanas del navegador abiertas en la misma computadora, será
interpretada por ASP.NET como tres sesiones abiertas, sin embargo generalmente
existe una sola ventana abierta del navegador de Internet por usuario.
180
El estado de una sesión se puede almacenar de las siguientes formas:
1. Como parte del proceso de la aplicación.
2. Como un servicio de Microsoft Windows, en el que se permite a la aplicación
ASP.NET compartir datos entre muchos procesadores (Web gardens).
3. Como dato en una base de datos de SQL Server, lo que permite que se pueda
compartir la información entre muchas computadoras (Web forms).
Eventos de sesión. Los eventos de sesión son aquellos que son exclusivos a un
usuario.
181
El siguiente ejemplo muestra como almacenar una variable de aplicación llamada
Contador_Aplicación, que cuente el número de sesiones activas que tiene la
aplicación actualmente. Almacenar una variable de sesión llamada Hora_Inicio,
que guarde la fecha y hora en que se inicia cada sesión. Para terminar la sesión
se contará con un botón que invocará a la función Session.Abadon()
Crearemos un nuevo proyecto de aplicación Web ASP .NET llamado Sesiones, al
cual agregaremos los controles de acuerdo con la siguiente tabla:
182
El segundo archivo es WebForm1.aspx, a continuación se muestra el código:
El resultado es el siguiente:
183
Datos Desconectados (DataSet)
Como lo vimos en el capítulo de ADO .Net un DataSet obtiene un conjunto de filas
de una o más tablas y posteriormente las aloja en memoria. Una vez realizado
esto, procede a desconectarse de la Base de Datos.
El DataSet se encargará de la gestión local de las filas obtenidas, así como
también de las posibles acciones a ser realizadas sobre las mismas
(modificaciones, eliminaciones, etc.), estas acciones serán aplicadas sobre la
copia privada de los datos, sin que ello interfiera con la base de datos.
Posteriormente, se necesitará sincronizar el DataSet con la base de datos a efecto
de que los cambios efectuados en el DataSet se hagan efectivos en la base de
batos.
El siguiente ejemplo muestra como crear altas, bajas, cambios sobre la tabla de
clientes de la base de datos Ferretería.
Vamos a aprender a llenar un Grid con la información de una tabla. Para ello
creamos un nuevo proyecto de aplicación Web ASP .NET llamado ABClientes, al
cual agregaremos los controles de acuerdo con la siguiente tabla:
184
Objeto Propiedad Valor
DataGrid ID DGClientes
RequiredFieldValidator ErrorMessage No puede estar en blanco
ControlToValidate ClientePk
RangeValidator ErrorMessage Valor fuera de rango
ControlToValidate ClientePk
MinimumValue 1
MaximumValue 99999
RequiredFieldValidator ErrorMessage No puede estar en blanco
ControlToValidate NomCliente
RequiredFieldValidator ErrorMessage No puede estar en blanco
ControlToValidate DomCliente
RequiredFieldValidator ErrorMessage No puede estar en blanco
ControlToValidate Ciudad
RequiredFieldValidator ErrorMessage No puede estar en blanco
ControlToValidate RFCliente
Después de agregar el control DataGrid haga clic derecho sobre éste y seleccione
Formato Automático y por ultimo Profesional 2.
Para seleccionar un registro completo del Grid, se necesita una columna extra que
permita realizar esta operación. En la propiedad Columnas y haga clic en
(colección) . En la ventana que aparece en seguida seleccione Columnas y abra la
opción de Columna Botón escoja Seleccionar, después establezca el Texto del
Encabezado, el Nombre de Comando es el nombre con el cual será identificado
en la programación. Una vez establecido estas propiedades oprima el botón de
Aceptar.
185
A continuación se muestra el código de la pagina:
Imports System.Data.OleDb
186
'Este procedimiento se genera cuando quiero cargar el DataGrid
Private Sub CargarDataGrid()
Ds = New DataSet
Adaptador = New OleDbDataAdapter("Select
ClientePk,NomCliente,DomCliente,Ciudad,RFCliente From Cliente", Cn)
Adaptador.Fill(Ds, "Clientes")
DGClientes.DataSource = Ds
If IsPostBack = False Then
DGClientes.DataBind()
'selecciono el primer elemento
DGClientes.SelectedIndex = 0
'Pongo todas las celdas del Item cero que es el primer
elemento del grid.
celdaGrid = DGClientes.Items(0).Cells()
Call LlenarCajas(celdaGrid)
End If
End Sub
187
Private Sub Grabar_Click(ByVal sender As System.Object,…
'Valido las cajas de texto
If RequiredFieldValidator1.IsValid And
RequiredFieldValidator2.IsValid And RequiredFieldValidator3.IsValid And
RequiredFieldValidator4.IsValid And RequiredFieldValidator5.IsValid And
RangeValidator1.IsValid Then
'Variable de tipo SqlCommandBuilder
Dim sqlCommBuilder As OleDbCommandBuilder
188
'en el DataGrid
celdaGrid =
DGClientes.Items(DGClientes.SelectedIndex).Cells()
'Procedimiento para llenar las cajas de texto
Call LlenarCajas(celdaGrid)
Catch mensaje As Exception
Label6.Text = "Error, la clave de ese libro ya
existe"
Exit Sub
End Try
'En caso de que sea edición
Else
Dim Tabla As DataTable
Dim Renglon As DataRow
Tabla = Ds.Tables("Clientes")
Renglon = Tabla.Rows(DGClientes.SelectedIndex)
Renglon("ClientePk") = ClientePk.Text
Renglon("NomCliente") = NomCliente.Text
Renglon("DomCliente") = DomCliente.Text
Renglon("Ciudad") = Ciudad.Text
Renglon("RFCliente") = RFCliente.Text
'Termino la edición
Renglon.EndEdit()
sqlCommBuilder = New OleDbCommandBuilder(Adaptador)
'sincronizar con la base de datos
Adaptador.Update(Ds, "Clientes")
'Confirmo los cambios
Ds.Tables("Clientes").AcceptChanges()
'Actualizo el control DataGrid
DGClientes.DataBind()
End If
Call HabilitarBotones()
DGClientes.Visible = True
End If
End Sub
celdaGrid = DGClientes.Items(DGClientes.SelectedIndex).Cells()
Call LlenarCajas(celdaGrid)
Call HabilitarBotones()
DGClientes.Visible = True
End Sub
189
Private Sub Borrar_Click(ByVal sender As System.Object, …
Dim Tabla As DataTable
Dim Renglon As Long
Tabla = Ds.Tables("Clientes")
'Asigno a la variable Renglon, el renglón seleccionado del
DataGrid
Renglon = DGClientes.SelectedIndex
Tabla.Rows(Renglon).Delete()
190
Es importante hacer hincapié en que cada vez que se genera un evento, como por
ejemplo un clic, la página es regenerada completamente, es por eso que se hace uso
de la instrucción IsPostBack, que checa que las instrucciones que se encuentren
dentro de ella, solamente se ejecuten la primera vez que se cargue la página. Otro
punto importante es que no es conveniente almacenar valores en las variables
locales, porque estos valores se pierden. Es por eso que en el archivo Global.asax,
que es creado automáticamente, asignamos valores que utilizaremos en el transcurso
de la aplicación.
Hay dos formas de almacenamiento, una por aplicación, que quiere decir que cada
que se inicie la aplicación se guardará o manipulará la variable sin importar cuántas
sesiones se creen. La otra es por sesión, en donde cada vez que se cree una sesión
se guardará o manipulará la variable. Dentro del código se utiliza la variable
EsAgregar, su valor depende si el usuario ha oprimido el botón de Agregar ó Editar.
Debido a que se utiliza un solo procedimiento para grabar la información, esta variable
indica si su valor es verdadero, que se debe agregar un nuevo registro, si su valor es
falso, entonces se debe modificar un registro ya existente.
191
Creación de Controles Dinámicamente
Contenedores de controles
Los objetos que tienen la capacidad de incluir varios controles dentro de si son
llamados contenedores de controles. En ASP .NET los controles que tienen esa
facultad son:
• Panel
• Placeholder
• Table con sus clases TableRow (fila) y TableCell (columna)
El siguiente ejemplo muestra como desarrollar una página en ASP .NET que
muestre un examen de opción múltiple y que presente las respuestas que
selecciono el usuario.
192
Para llevar a cabo esta actividad, crearemos un proyecto de aplicación Web ASP
.NET, al cual llamaremos CtrlDinamicos. En este adicionaremos los siguientes
controles:
Una vez creado el diseño, continuaremos con la inserción del código para darle
funcionalidad a la página. El siguiente código se incluira en el evento load de la
página:
Imports System.Data.OleDb
193
LlenarDatos(lblPreg, rblResp)
End Sub
Ahora se procederá a insertar el código del procedimiento para crear los controles
dinámicamente:
AdaptPreg.Fill(Ds, "Pregunta")
lbl.Text = "<BR>" & " " & RegPreg(0) & ". " & RegPreg(1)
Panel1.Controls.Add(lbl)
While DatRead.Read
rbl.Items.Add(New ListItem(DatRead.Item(1), DatRead.Item(0)))
End While
Panel1.Controls.Add(rbl)
DatRead.Close()
Next
End Sub
For j = 0 To RadioBoton.Items.Count - 1
If RadioBoton.Items(j).Selected = True Then
label = New Label
label.Text = RadioBoton.SelectedItem.Value & ". " &
RadioBoton.SelectedItem.Text & "<BR>"
Panel2.Controls.Add(label)
End If
Next
Next
End Sub
194
195
El contenido del presente manual esta basado en la siguiente Bibliografía
196